From 95825fa28a7e84a2f5dbdef5241078f7055c5b04 Mon Sep 17 00:00:00 2001 From: Knut Anders Hatlen Date: Thu, 7 Jan 2016 12:53:18 +0100 Subject: Bug#21682356: STOP INJECTING DATA ITEMS IN AN ERROR MESSAGE GENERATED BY THE EXP() FUNCTION When generating the error message for numeric overflow, pass a flag to Item::print() that prevents it from expanding constant expressions and parameters to the values they evaluate to. For consistency, also pass the flag to Item::print() when Item_func_spatial_collection::fix_length_and_dec() generates an error message. It doesn't make any difference at the moment, since constant expressions haven't been evaluated yet when this function is called. --- sql/item.cc | 7 ++++--- sql/item_func.h | 4 ++-- sql/item_geofunc.h | 4 ++-- sql/mysqld.h | 10 ++++++++-- sql/sql_select.cc | 40 ++++++++++++++++++++++++++++++---------- 5 files changed, 46 insertions(+), 19 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index beb68c5d321..5f02b96e59f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3456,7 +3456,7 @@ Item_param::eq(const Item *arg, bool binary_cmp) const void Item_param::print(String *str, enum_query_type query_type) { - if (state == NO_VALUE) + if (state == NO_VALUE || query_type & QT_NO_DATA_EXPANSION) { str->append('?'); } @@ -6197,7 +6197,8 @@ Item *Item_field::update_value_transformer(uchar *select_arg) void Item_field::print(String *str, enum_query_type query_type) { - if (field && field->table->const_table) + if (field && field->table->const_table && + !(query_type & QT_NO_DATA_EXPANSION)) { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),str->charset()); diff --git a/sql/item_func.h b/sql/item_func.h index fc9fa4a65fb..6c83bc179f2 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,7 +1,7 @@ #ifndef ITEM_FUNC_INCLUDED #define ITEM_FUNC_INCLUDED -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -217,7 +217,7 @@ public: char buf[256]; String str(buf, sizeof(buf), system_charset_info); str.length(0); - print(&str, QT_ORDINARY); + print(&str, QT_NO_DATA_EXPANSION); my_error(ER_DATA_OUT_OF_RANGE, MYF(0), type_name, str.c_ptr_safe()); } inline double raise_float_overflow() diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 903257525f9..fe7ccf10fcc 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,7 +1,7 @@ #ifndef ITEM_GEOFUNC_INCLUDED #define ITEM_GEOFUNC_INCLUDED -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -187,7 +187,7 @@ public: if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) { String str; - args[i]->print(&str, QT_ORDINARY); + args[i]->print(&str, QT_NO_DATA_EXPANSION); str.append('\0'); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "non geometric", str.ptr()); diff --git a/sql/mysqld.h b/sql/mysqld.h index 0253c2a0b43..ee9f8c64840 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -431,7 +431,13 @@ enum enum_query_type /// In utf8. QT_TO_SYSTEM_CHARSET= (1 << 0), /// Without character set introducers. - QT_WITHOUT_INTRODUCERS= (1 << 1) + QT_WITHOUT_INTRODUCERS= (1 << 1), + /** + If an expression is constant, print the expression, not the value + it evaluates to. Should be used for error messages, so that they + don't reveal values. + */ + QT_NO_DATA_EXPANSION= (1 << 9), }; /* query_id */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 96271f26b0f..b5ecebdadc8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17427,26 +17427,46 @@ static void print_join(THD *thd, /* List is reversed => we should reverse it before using */ List_iterator_fast ti(*tables); TABLE_LIST **table; - uint non_const_tables= 0; + + /* + If the QT_NO_DATA_EXPANSION flag is specified, we print the + original table list, including constant tables that have been + optimized away, as the constant tables may be referenced in the + expression printed by Item_field::print() when this flag is given. + Otherwise, only non-const tables are printed. + + Example: + + Original SQL: + select * from (select 1) t + + Printed without QT_NO_DATA_EXPANSION: + select '1' AS `1` from dual + + Printed with QT_NO_DATA_EXPANSION: + select `t`.`1` from (select 1 AS `1`) `t` + */ + const bool print_const_tables= (query_type & QT_NO_DATA_EXPANSION); + size_t tables_to_print= 0; for (TABLE_LIST *t= ti++; t ; t= ti++) - if (!t->optimized_away) - non_const_tables++; - if (!non_const_tables) + if (print_const_tables || !t->optimized_away) + tables_to_print++; + if (tables_to_print == 0) { str->append(STRING_WITH_LEN("dual")); return; // all tables were optimized away } ti.rewind(); - if (!(table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) * - non_const_tables))) + if (!(table= static_cast(thd->alloc(sizeof(TABLE_LIST*) * + tables_to_print)))) return; // out of memory - TABLE_LIST *tmp, **t= table + (non_const_tables - 1); + TABLE_LIST *tmp, **t= table + (tables_to_print - 1); while ((tmp= ti++)) { - if (tmp->optimized_away) + if (tmp->optimized_away && !print_const_tables) continue; *t--= tmp; } @@ -17454,7 +17474,7 @@ static void print_join(THD *thd, DBUG_ASSERT(tables->elements >= 1); (*table)->print(thd, str, query_type); - TABLE_LIST **end= table + non_const_tables; + TABLE_LIST **end= table + tables_to_print; for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++) { TABLE_LIST *curr= *tbl; -- cgit v1.2.1 From 01d41f68b7a6e6cc12565056661f1f28876beff5 Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Thu, 28 Jan 2016 17:40:17 +0530 Subject: Bug #16912362 LOAD DATA INFILE CLAIMS TO BE HOLDING 'SYSTEM LOCK' IN PROCESSLIST Analysis ========= Show processlist shows 'System Lock' in 'State' field while LOAD DATA INFILE is running. thd->proc_info update is missing in LOAD DATA INFILE path. Thus any request will get last unpdated status from lock_table() during open_table(). Fix: ======= Update state information from LOAD DATA INFILE path. --- sql/sql_load.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 5f72d3ce520..c084e5e3839 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -253,6 +253,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { DBUG_RETURN(TRUE); } + thd_proc_info(thd, "executing"); /* Let us emit an error if we are loading data to table which is used in subselect in SET clause like we do it for INSERT. -- cgit v1.2.1 From 718c787912e0d498c167e7436d840b2c837e90f9 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Fri, 29 Jan 2016 08:29:06 +0530 Subject: Bug #18823979: PS: UCS2 + CASE WHEN THEN ELSE CRASH IN ITEM_PARAM::SAFE_CHARSET_CONVERTER ISSUE: ------ Charset conversion on a null parameter is not handled correctly. SOLUTION: --------- Item_param's charset converter does not handle the case where it might have to deal with a null value. This is fine for other charset converters since the value is not supplied to them at runtime. The fix is to check if the parameter is now set to null and return an Item_null object. Also, there is no need to initialize Item_param's cnvitem in the constructor to a string. This can be done in ITEM_PARAM::SAFE_CHARSET_CONVERTER itself. Members of Item_param, cnvbuf and cnvstr, have been removed and cnvitem has been made a local variable in ITEM_PARAM::SAFE_CHARSET_CONVERTER. --- sql/item.cc | 35 +++++++++++++++++++++++++---------- sql/item.h | 6 +----- 2 files changed, 26 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 5f02b96e59f..c482f0e1a04 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -926,14 +926,31 @@ Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs) { if (const_item()) { - uint cnv_errors; - String *ostr= val_str(&cnvstr); - cnvitem->str_value.copy(ostr->ptr(), ostr->length(), - ostr->charset(), tocs, &cnv_errors); - if (cnv_errors) - return NULL; - cnvitem->str_value.mark_as_const(); - cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen; + Item *cnvitem; + String tmp, cstr, *ostr= val_str(&tmp); + + if (null_value) + { + cnvitem= new Item_null(); + if (cnvitem == NULL) + return NULL; + + cnvitem->collation.set(tocs); + } + else + { + uint conv_errors; + cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, + &conv_errors); + + if (conv_errors || !(cnvitem= new Item_string(cstr.ptr(), cstr.length(), + cstr.charset(), + collation.derivation))) + return NULL; + + cnvitem->str_value.copy(); + cnvitem->str_value.mark_as_const(); + } return cnvitem; } return Item::safe_charset_converter(tocs); @@ -2795,8 +2812,6 @@ Item_param::Item_param(uint pos_in_query_arg) : value is set. */ maybe_null= 1; - cnvitem= new Item_string("", 0, &my_charset_bin, DERIVATION_COERCIBLE); - cnvstr.set(cnvbuf, sizeof(cnvbuf), &my_charset_bin); } diff --git a/sql/item.h b/sql/item.h index 831343de7ad..8caa2bc5f9f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,7 +1,7 @@ #ifndef ITEM_INCLUDED #define ITEM_INCLUDED -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1861,10 +1861,6 @@ public: class Item_param :public Item, private Settable_routine_parameter { - char cnvbuf[MAX_FIELD_WIDTH]; - String cnvstr; - Item *cnvitem; - public: enum enum_item_param_state { -- cgit v1.2.1 From d9c541cb1be5b239787833d9d499067d44ea44d3 Mon Sep 17 00:00:00 2001 From: Nisha Gopalakrishnan Date: Wed, 10 Feb 2016 19:57:17 +0530 Subject: BUG#22037930: INSERT IGNORE FAILS TO IGNORE FOREIGN KEY CONSTRAINT. Analysis ======= INSERT and UPDATE operations using the IGNORE keyword which causes FOREIGN KEY constraint violations reports an error despite using the IGNORE keyword. Foreign key violation errors were not ignored and reported as errors instead of warnings even when IGNORE was set. Fix === Added code to ignore the foreign key violation errors and report them as warnings when the IGNORE keyword is used. --- sql/handler.cc | 27 ++++++++++++++++++++++++++- sql/handler.h | 10 ++++++++-- sql/sql_insert.cc | 12 ++++++++---- sql/sql_update.cc | 26 ++++++++++++++++++++------ 4 files changed, 62 insertions(+), 13 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 6307e95a194..9d57cba73dc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5452,3 +5452,28 @@ fl_create_iterator(enum handler_iterator_type type, } } #endif /*TRANS_LOG_MGM_EXAMPLE_CODE*/ + + +/** + Report a warning for FK constraint violation. + + @param thd Thread handle. + @param table table on which the operation is performed. + @param error handler error number. +*/ +void warn_fk_constraint_violation(THD *thd,TABLE *table, int error) +{ + String str; + switch(error) { + case HA_ERR_ROW_IS_REFERENCED: + table->file->get_error_message(error, &str); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ROW_IS_REFERENCED_2, str.c_ptr_safe()); + break; + case HA_ERR_NO_REFERENCED_ROW: + table->file->get_error_message(error, &str); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_REFERENCED_ROW_2, str.c_ptr_safe()); + break; + } +} diff --git a/sql/handler.h b/sql/handler.h index 17306fe7dd4..29b6a86c030 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2,7 +2,7 @@ #define HANDLER_INCLUDED /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -303,6 +303,7 @@ /* Flags for method is_fatal_error */ #define HA_CHECK_DUP_KEY 1 #define HA_CHECK_DUP_UNIQUE 2 +#define HA_CHECK_FK_ERROR 4 #define HA_CHECK_DUP (HA_CHECK_DUP_KEY + HA_CHECK_DUP_UNIQUE) enum legacy_db_type @@ -1485,7 +1486,10 @@ public: if (!error || ((flags & HA_CHECK_DUP_KEY) && (error == HA_ERR_FOUND_DUPP_KEY || - error == HA_ERR_FOUND_DUPP_UNIQUE))) + error == HA_ERR_FOUND_DUPP_UNIQUE)) || + ((flags & HA_CHECK_FK_ERROR) && + (error == HA_ERR_ROW_IS_REFERENCED || + error == HA_ERR_NO_REFERENCED_ROW))) return FALSE; return TRUE; } @@ -2362,4 +2366,6 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name) return ((lower_case_table_names == 2 && info->alias) ? info->alias : name); } +void warn_fk_constraint_violation(THD *thd, TABLE *table, int error); + #endif /* HANDLER_INCLUDED */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7bfc7b083ac..a267108c847 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1522,7 +1522,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) else table->file->insert_id_for_cur_row= insert_id_for_cur_row; bool is_duplicate_key_error; - if (table->file->is_fatal_error(error, HA_CHECK_DUP)) + if (table->file->is_fatal_error(error, HA_CHECK_DUP | HA_CHECK_FK_ERROR)) goto err; is_duplicate_key_error= table->file->is_fatal_error(error, 0); if (!is_duplicate_key_error) @@ -1620,7 +1620,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) error != HA_ERR_RECORD_IS_THE_SAME) { if (info->ignore && - !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) { goto ok_or_after_trg_err; } @@ -1733,7 +1734,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) { DEBUG_SYNC(thd, "write_row_noreplace"); if (!info->ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP)) + table->file->is_fatal_error(error, HA_CHECK_DUP | HA_CHECK_FK_ERROR)) goto err; table->file->restore_auto_increment(prev_insert_id); goto ok_or_after_trg_err; @@ -1751,6 +1752,9 @@ ok_or_after_trg_err: my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH); if (!table->file->has_transactions()) thd->transaction.stmt.modified_non_trans_table= TRUE; + if (info->ignore && + !table->file->is_fatal_error(error, HA_CHECK_FK_ERROR)) + warn_fk_constraint_violation(thd, table, error); DBUG_RETURN(trg_error); err: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a29d474fbfc..64d1b3e49dc 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -735,7 +735,8 @@ int mysql_update(THD *thd, error= 0; } else if (!ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) { /* If (ignore && error is ignorable) we don't have to @@ -743,7 +744,8 @@ int mysql_update(THD *thd, */ myf flags= 0; - if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); @@ -751,6 +753,9 @@ int mysql_update(THD *thd, error= 1; break; } + else if (ignore && !table->file->is_fatal_error(error, + HA_CHECK_FK_ERROR)) + warn_fk_constraint_violation(thd, table, error); } if (table->triggers && @@ -1883,7 +1888,8 @@ bool multi_update::send_data(List ¬_used_values) { updated--; if (!ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) { /* If (ignore && error == is ignorable) we don't have to @@ -1891,13 +1897,17 @@ bool multi_update::send_data(List ¬_used_values) */ myf flags= 0; - if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); table->file->print_error(error,MYF(flags)); DBUG_RETURN(1); } + else if (ignore && !table->file->is_fatal_error(error, + HA_CHECK_FK_ERROR)) + warn_fk_constraint_violation(thd, table, error); } else { @@ -2138,8 +2148,12 @@ int multi_update::do_updates() local_error != HA_ERR_RECORD_IS_THE_SAME) { if (!ignore || - table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY)) + table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY | + HA_CHECK_FK_ERROR)) goto err; + else if (ignore && !table->file->is_fatal_error(local_error, + HA_CHECK_FK_ERROR)) + warn_fk_constraint_violation(thd, table, local_error); } if (local_error != HA_ERR_RECORD_IS_THE_SAME) updated++; -- cgit v1.2.1 From 447eaa5bc04761555f066d911397e41187d43af5 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Tue, 23 Feb 2016 11:54:59 +0530 Subject: --- sql/sql_acl.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a939ae72ecb..5ff6f38d18d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -717,7 +717,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, FALSE); table->use_all_columns(); - (void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50); while (!(read_record_info.read_record(&read_record_info))) { ACL_HOST host; @@ -766,7 +765,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE); table->use_all_columns(); - (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100); password_length= table->field[2]->field_length / table->field[2]->charset()->mbmaxlen; if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) @@ -981,7 +979,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE); table->use_all_columns(); - (void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100); while (!(read_record_info.read_record(&read_record_info))) { ACL_DB db; @@ -1038,8 +1035,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_dbs); - (void) my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), - 50, 100); if (tables[3].table) { init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1, @@ -1075,6 +1070,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) return_val= FALSE; end: + end_read_record(&read_record_info); thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(return_val); } @@ -1089,12 +1085,12 @@ void acl_free(bool end) delete_dynamic(&acl_wild_hosts); delete_dynamic(&acl_proxy_users); my_hash_free(&acl_check_hosts); - plugin_unlock(0, native_password_plugin); - plugin_unlock(0, old_password_plugin); if (!end) acl_cache->clear(1); /* purecov: inspected */ else { + plugin_unlock(0, native_password_plugin); + plugin_unlock(0, old_password_plugin); delete acl_cache; acl_cache=0; } @@ -1168,6 +1164,10 @@ my_bool acl_reload(THD *thd) old_acl_users= acl_users; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; + my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50); + my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100); + my_init_dynamic_array(&acl_dbs, sizeof(ACL_DB), 50, 100); + my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100); old_mem= mem; delete_dynamic(&acl_wild_hosts); my_hash_free(&acl_check_hosts); -- cgit v1.2.1 From 29cc2c28832ae4733804ac6b29d650238ee0559c Mon Sep 17 00:00:00 2001 From: Venkatesh Duggirala Date: Fri, 26 Feb 2016 09:01:49 +0530 Subject: BUG#20574550 MAIN.MERGE TEST CASE FAILS IF BINLOG_FORMAT=ROW The main.merge test case was failing when tested using row based binlog format. While analyzing the issue it was found the following issues: a) The server is calling binlog related code even when a statement will not be binlogged; b) The child table list was not present into table structure by the time to generate the create table statement; c) The tables in the child table list will not be opened yet when generating table create info using row based replication; d) CREATE TABLE LIKE TEMP_TABLE does not preserve original table storage engine when using row based replication; This patch addressed all above issues. @ sql/sql_class.h Added a function to determine if the binary log is disabled to the current session. This is related with issue (a) above. @ sql/sql_table.cc Added code to skip binary logging related code if the statement will not be binlogged. This is related with issue (a) above. Added code to add the children to the query list of the table that will have its CREATE TABLE generated. This is related with issue (b) above. Added code to force the storage engine to be generated into the CREATE TABLE. This is related with issue (d) above. @ storage/myisammrg/ha_myisammrg.cc Added a test to skip a table getting info about a child table if the child table is not opened. This is related to issue (c) above. --- sql/sql_class.h | 14 +++++++++++++- sql/sql_table.cc | 20 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.h b/sql/sql_class.h index c9900231615..0df8c70e184 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1662,6 +1662,18 @@ public: current_stmt_binlog_format == BINLOG_FORMAT_ROW); return current_stmt_binlog_format == BINLOG_FORMAT_ROW; } + /** + Determine if binlogging is disabled for this session + @retval 0 if the current statement binlogging is disabled + (could be because of binlog closed/binlog option + is set to false). + @retval 1 if the current statement will be binlogged + */ + inline bool is_current_stmt_binlog_disabled() const + { + return (!(variables.option_bits & OPTION_BIN_LOG) || + !mysql_bin_log.is_open()); + } private: /** diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7b4d08613cf..49f05c6116e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4709,7 +4709,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, /* We have to write the query before we unlock the tables. */ - if (thd->is_current_stmt_binlog_format_row()) + if (!thd->is_current_stmt_binlog_disabled() && + thd->is_current_stmt_binlog_format_row()) { /* Since temporary tables are not replicated under row-based @@ -4751,6 +4752,21 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, if (open_table(thd, table, thd->mem_root, &ot_ctx)) goto err; + /* + After opening a MERGE table add the children to the query list of + tables, so that children tables info can be used on "CREATE TABLE" + statement generation by the binary log. + Note that placeholders don't have the handler open. + */ + if (table->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST)) + goto err; + + /* + As the reference table is temporary and may not exist on slave, we must + force the ENGINE to be present into CREATE TABLE. + */ + create_info->used_fields|= HA_CREATE_USED_ENGINE; + int result __attribute__((unused))= store_create_info(thd, table, &query, create_info, TRUE /* show_database */); -- cgit v1.2.1 From bb32ac1d9b6c1333316a8da32ea46105eceefa29 Mon Sep 17 00:00:00 2001 From: Venkatesh Duggirala Date: Tue, 1 Mar 2016 11:58:45 +0530 Subject: BUG#17018343 SLAVE CRASHES WHEN APPLYING ROW-BASED BINLOG ENTRIES IN CASCADING REPLICATION Problem: In RBR mode, merge table updates are not successfully applied on a cascading replication. Analysis & Fix: Every type of row event is preceded by one or more table_map_log_events that gives the information about all the tables that are involved in the row event. Server maintains the list in RPL_TABLE_LIST and it goes through all the tables and checks for the compatibility between master and slave. Before checking for the compatibility, it calls 'open_tables()' which takes the list of all tables that needs to be locked and opened. In RBR, because of the Table_map_log_event , we already have all the tables including base tables in the list. But the open_tables() which is generic call takes care of appending base tables if the list contains merge tables. There is an assumption in the current replication layer logic that these tables (TABLE_LIST type objects) are always added in the end of the list. Replication layer maintains the count of tables(tables_to_lock_count) that needs to be verified for compatibility check and runs through only those many tables from the list and rest of the objects in linked list can be skipped. But this assumption is wrong. open_tables()->..->add_children_to_list() adds base tables to the list immediately after seeing the merge table in the list. For eg: If the list passed to open_tables() is t1->t2->t3 where t3 is merge table (and t1 and t2 are base tables), it adds t1'->t2' to the list after t3. New table list looks like t1->t2->t3->t1'->t2'. It looks like it added at the end of the list but that is not correct. If the list passed to open_tables() is t3->t1->t2 where t3 is merge table (and t1 and t2 are base tables), the new prepared list will be t3->t1'->t2'->t1->t2. Where t1' and t2' are of TABLE_LIST objects which were added by add_children_to_list() call and replication layer should not look into them. Here tables_to_lock_count will not help as the objects are added in between the list. Fix: After investigating add_children_list() logic (which is called from open_tables()), there is no flag/logic in it to skip adding the children to the list even if the children are already included in the table list. Hence to fix the issue, a logic should be added in the replication layer to skip children in the list by checking whether 'parent_l' is non-null or not. If it is children, we will skip 'compatibility' check for that table. Also this patch is not removing 'tables_to_lock_count' logic for the performance issues if there are any children at the end of the list, those can be easily skipped directly by stopping the loop with tables_to_lock_count check. --- sql/log_event.cc | 46 +++++++++++++++++++++++++++++++++++++++------- sql/log_event_old.cc | 52 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 20 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index accb6a28dbd..702cf1d575a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -7930,9 +7930,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* When the open and locking succeeded, we check all tables to ensure that they still have the correct type. - - We can use a down cast here since we know that every table added - to the tables_to_lock is a RPL_TABLE_LIST. */ { @@ -7951,10 +7948,37 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) NOTE: The base tables are added here are removed when close_thread_tables is called. */ - RPL_TABLE_LIST *ptr= rli->tables_to_lock; - for (uint i= 0 ; ptr && (i < rli->tables_to_lock_count); - ptr= static_cast(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rli->tables_to_lock; + for (uint i=0 ; table_list_ptr && (i < rli->tables_to_lock_count); + table_list_ptr= table_list_ptr->next_global, i++) { + /* + Below if condition takes care of skipping base tables that + make up the MERGE table (which are added by open_tables() + call). They are added next to the merge table in the list. + For eg: If RPL_TABLE_LIST is t3->t1->t2 (where t1 and t2 + are base tables for merge table 't3'), open_tables will modify + the list by adding t1 and t2 again immediately after t3 in the + list (*not at the end of the list*). New table_to_lock list will + look like t3->t1'->t2'->t1->t2 (where t1' and t2' are TABLE_LIST + objects added by open_tables() call). There is no flag(or logic) in + open_tables() that can skip adding these base tables to the list. + So the logic here should take care of skipping them. + + tables_to_lock_count logic will take care of skipping base tables + that are added at the end of the list. + For eg: If RPL_TABLE_LIST is t1->t2->t3, open_tables will modify + the list into t1->t2->t3->t1'->t2'. t1' and t2' will be skipped + because tables_to_lock_count logic in this for loop. + */ + if (table_list_ptr->parent_l) + continue; + /* + We can use a down cast here since we know that every table added + to the tables_to_lock is a RPL_TABLE_LIST (or child table which is + skipped above). + */ + RPL_TABLE_LIST *ptr= static_cast(table_list_ptr); DBUG_ASSERT(ptr->m_tabledef_valid); TABLE *conv_table; if (!ptr->m_tabledef.compatible_with(thd, const_cast(rli), @@ -7995,7 +8019,15 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ TABLE_LIST *ptr= rli->tables_to_lock; for (uint i=0 ; ptr && (i < rli->tables_to_lock_count); ptr= ptr->next_global, i++) + { + /* + Please see comment in above 'for' loop to know the reason + for this if condition + */ + if (ptr->parent_l) + continue; const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); + } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index ed53aec6006..eb9678ddaa5 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -119,16 +119,25 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info /* When the open and locking succeeded, we check all tables to ensure that they still have the correct type. - - We can use a down cast here since we know that every table added - to the tables_to_lock is a RPL_TABLE_LIST. */ { - RPL_TABLE_LIST *ptr= rli->tables_to_lock; - for (uint i= 0 ; ptr&& (i< rli->tables_to_lock_count); - ptr= static_cast(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rli->tables_to_lock; + for (uint i=0 ; table_list_ptr&& (i< rli->tables_to_lock_count); + table_list_ptr= table_list_ptr->next_global, i++) { + /* + Please see comment in log_event.cc-Rows_log_event::do_apply_event() + function for the explanation of the below if condition + */ + if (table_list_ptr->parent_l) + continue; + /* + We can use a down cast here since we know that every table added + to the tables_to_lock is a RPL_TABLE_LIST(or child table which is + skipped above). + */ + RPL_TABLE_LIST *ptr=static_cast(table_list_ptr); DBUG_ASSERT(ptr->m_tabledef_valid); TABLE *conv_table; if (!ptr->m_tabledef.compatible_with(thd, const_cast(rli), @@ -162,7 +171,15 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ TABLE_LIST *ptr= rli->tables_to_lock; for (uint i=0; ptr && (i < rli->tables_to_lock_count); ptr= ptr->next_global, i++) + { + /* + Please see comment in log_event.cc-Rows_log_event::do_apply_event() + function for the explanation of the below if condition + */ + if (ptr->parent_l) + continue; const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); + } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); #endif @@ -1545,16 +1562,25 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) /* When the open and locking succeeded, we check all tables to ensure that they still have the correct type. - - We can use a down cast here since we know that every table added - to the tables_to_lock is a RPL_TABLE_LIST. */ { - RPL_TABLE_LIST *ptr= rli->tables_to_lock; - for (uint i= 0 ; ptr&& (i< rli->tables_to_lock_count); - ptr= static_cast(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rli->tables_to_lock; + for (uint i=0; table_list_ptr&& (i< rli->tables_to_lock_count); + table_list_ptr= static_cast(table_list_ptr->next_global), i++) { + /* + Please see comment in log_event.cc-Rows_log_event::do_apply_event() + function for the explanation of the below if condition + */ + if (table_list_ptr->parent_l) + continue; + /* + We can use a down cast here since we know that every table added + to the tables_to_lock is a RPL_TABLE_LIST (or child table which is + skipped above). + */ + RPL_TABLE_LIST *ptr=static_cast(table_list_ptr); TABLE *conv_table; if (ptr->m_tabledef.compatible_with(thd, const_cast(rli), ptr->table, &conv_table)) -- cgit v1.2.1 From 8361151765cc5efd72ad18c5553f80aa440a1d83 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Tue, 1 Mar 2016 12:29:51 +0530 Subject: Bug#20685029: SLAVE IO THREAD SHOULD STOP WHEN DISK IS FULL Bug#21753696: MAKE SHOW SLAVE STATUS NON BLOCKING IF IO THREAD WAITS FOR DISK SPACE Problem: ======== Currently SHOW SLAVE STATUS blocks if IO thread waits for disk space. This makes automation tools verifying server health block on taking relevant action. Finally this will create SHOW SLAVE STATUS piles. Analysis: ========= SHOW SLAVE STATUS hangs on mi->data_lock if relay log write is waiting for free disk space while holding mi->data_lock. mi->data_lock is needed to protect the format description event (mi->format_description_event) which is accessed by the clients running FLUSH LOGS and slave IO thread. Note relay log writes don't need to be protected by mi->data_lock, LOCK_log is used to protect relay log between IO and SQL thread (see MYSQL_BIN_LOG::append_event). The code takes mi->data_lock to protect mi->format_description_event during relay log rotate which might get triggered right after relay log write. Fix: ==== Release the data_lock just for the duration of writing into relay log. Made change to ensure the following lock order is maintained to avoid deadlocks. data_lock, LOCK_log data_lock is held during relay log rotations to protect the description event. --- sql/log.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++----- sql/log.h | 7 +++--- sql/slave.cc | 40 +++++++++++++++++++++----------- sql/slave.h | 4 ++-- sql/sql_reload.cc | 4 ++-- 5 files changed, 98 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 9e34532f1ac..eab9a118147 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,6 +37,7 @@ #include "log_event.h" // Query_log_event #include "rpl_filter.h" #include "rpl_rli.h" +#include "rpl_mi.h" #include "sql_audit.h" #include "sql_show.h" @@ -4377,13 +4378,22 @@ end: } -bool MYSQL_BIN_LOG::append(Log_event* ev) +#ifdef HAVE_REPLICATION +bool MYSQL_BIN_LOG::append(Log_event* ev, Master_info *mi) { bool error = 0; + mysql_mutex_assert_owner(&mi->data_lock); mysql_mutex_lock(&LOCK_log); DBUG_ENTER("MYSQL_BIN_LOG::append"); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); + /* + Release data_lock by holding LOCK_log, while writing into the relay log. + If slave IO thread waits here for free space, we don't want + SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is + sufficient to block SQL thread when IO thread is updating relay log here. + */ + mysql_mutex_unlock(&mi->data_lock); /* Log_event::write() is smart enough to use my_b_write() or my_b_append() depending on the kind of cache we have. @@ -4398,24 +4408,50 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) if (flush_and_sync(0)) goto err; if ((uint) my_b_append_tell(&log_file) > max_size) + { + /* + If rotation is required we must acquire data_lock to protect + description_event from clients executing FLUSH LOGS in parallel. + In order do that we must release the existing LOCK_log so that we + get it once again in proper locking order to avoid dead locks. + i.e data_lock , LOCK_log. + */ + mysql_mutex_unlock(&LOCK_log); + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&LOCK_log); error= new_file_without_locking(); + /* + After rotation release data_lock, we need the LOCK_log till we signal + the updation. + */ + mysql_mutex_unlock(&mi->data_lock); + } err: - mysql_mutex_unlock(&LOCK_log); signal_update(); // Safe as we don't call close + mysql_mutex_unlock(&LOCK_log); + mysql_mutex_lock(&mi->data_lock); DBUG_RETURN(error); } -bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) +bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) { bool error= 0; DBUG_ENTER("MYSQL_BIN_LOG::appendv"); va_list(args); va_start(args,len); + mysql_mutex_assert_owner(&mi->data_lock); + mysql_mutex_lock(&LOCK_log); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - mysql_mutex_assert_owner(&LOCK_log); + /* + Release data_lock by holding LOCK_log, while writing into the relay log. + If slave IO thread waits here for free space, we don't want + SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is + sufficient to block SQL thread when IO thread is updating relay log here. + */ + mysql_mutex_unlock(&mi->data_lock); do { if (my_b_append(&log_file,(uchar*) buf,len)) @@ -4428,13 +4464,34 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0)) goto err; - if ((uint) my_b_append_tell(&log_file) > max_size) + if ((uint) my_b_append_tell(&log_file) > + DBUG_EVALUATE_IF("rotate_slave_debug_group", 500, max_size)) + { + /* + If rotation is required we must acquire data_lock to protect + description_event from clients executing FLUSH LOGS in parallel. + In order do that we must release the existing LOCK_log so that we + get it once again in proper locking order to avoid dead locks. + i.e data_lock , LOCK_log. + */ + mysql_mutex_unlock(&LOCK_log); + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&LOCK_log); error= new_file_without_locking(); + /* + After rotation release data_lock, we need the LOCK_log till we signal + the updation. + */ + mysql_mutex_unlock(&mi->data_lock); + } err: if (!error) signal_update(); + mysql_mutex_unlock(&LOCK_log); + mysql_mutex_lock(&mi->data_lock); DBUG_RETURN(error); } +#endif bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) { diff --git a/sql/log.h b/sql/log.h index 1fc13afe7d1..7d1c3161ac2 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "handler.h" /* my_xid */ class Relay_log_info; +class Master_info; class Format_description_log_event; @@ -454,8 +455,8 @@ public: v stands for vector invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0) */ - bool appendv(const char* buf,uint len,...); - bool append(Log_event* ev); + bool appendv(Master_info* mi, const char* buf,uint len,...); + bool append(Log_event* ev, Master_info* mi); void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); diff --git a/sql/slave.cc b/sql/slave.cc index d97a9cdf6e9..31037c453d3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1660,7 +1660,7 @@ Waiting for the slave SQL thread to free enough relay log space"); #endif if (rli->sql_force_rotate_relay) { - rotate_relay_log(rli->mi); + rotate_relay_log(rli->mi, true/*need_data_lock=true*/); rli->sql_force_rotate_relay= false; } @@ -1705,7 +1705,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi) if (likely((bool)ev)) { ev->server_id= 0; // don't be ignored by slave SQL thread - if (unlikely(rli->relay_log.append(ev))) + if (unlikely(rli->relay_log.append(ev, mi))) mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), "failed to write a Rotate event" @@ -3605,7 +3605,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) break; Execute_load_log_event xev(thd,0,0); xev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&xev))) + if (unlikely(mi->rli.relay_log.append(&xev, mi))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3619,7 +3619,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) { cev->block = net->read_pos; cev->block_len = num_bytes; - if (unlikely(mi->rli.relay_log.append(cev))) + if (unlikely(mi->rli.relay_log.append(cev, mi))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3634,7 +3634,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) aev.block = net->read_pos; aev.block_len = num_bytes; aev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&aev))) + if (unlikely(mi->rli.relay_log.append(&aev, mi))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3713,7 +3713,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev) Rotate the relay log makes binlog format detection easier (at next slave start or mysqlbinlog) */ - DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */); + DBUG_RETURN(rotate_relay_log(mi, false/*need_data_lock=false*/)); } /* @@ -3819,7 +3819,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf, Log_event::Log_event(const char* buf...) in log_event.cc). */ ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */ - if (unlikely(rli->relay_log.append(ev))) + if (unlikely(rli->relay_log.append(ev, mi))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -3875,7 +3875,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf, inc_pos= event_len; break; } - if (unlikely(rli->relay_log.append(ev))) + if (unlikely(rli->relay_log.append(ev, mi))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -4083,7 +4083,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) direct master (an unsupported, useless setup!). */ - mysql_mutex_lock(log_lock); s_id= uint4korr(buf + SERVER_ID_OFFSET); if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) || /* @@ -4116,6 +4115,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) IGNORE_SERVER_IDS it increments mi->master_log_pos as well as rli->group_relay_log_pos. */ + mysql_mutex_lock(log_lock); if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) || (buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT && buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT && @@ -4127,13 +4127,14 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) rli->ign_master_log_pos_end= mi->master_log_pos; } rli->relay_log.signal_update(); // the slave SQL thread needs to re-check + mysql_mutex_unlock(log_lock); DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored", (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET))); } else { /* write the event to the relay log */ - if (likely(!(rli->relay_log.appendv(buf,event_len,0)))) + if (likely(!(rli->relay_log.appendv(mi, buf,event_len,0)))) { mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); @@ -4143,9 +4144,10 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) { error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; } + mysql_mutex_lock(log_lock); rli->ign_master_log_name_end[0]= 0; // last event is not ignored + mysql_mutex_unlock(log_lock); } - mysql_mutex_unlock(log_lock); skip_relay_logging: @@ -5005,11 +5007,21 @@ err: locks; here we don't, so this function is mainly taking locks). Returns nothing as we cannot catch any error (MYSQL_BIN_LOG::new_file() is void). + + @param mi Master_info for the IO thread. + @param need_data_lock If true, mi->data_lock will be acquired otherwise, + mi->data_lock must be held by the caller. */ -int rotate_relay_log(Master_info* mi) +int rotate_relay_log(Master_info* mi, bool need_data_lock) { DBUG_ENTER("rotate_relay_log"); + if (need_data_lock) + mysql_mutex_lock(&mi->data_lock); + else + { + mysql_mutex_assert_owner(&mi->data_lock); + } Relay_log_info* rli= &mi->rli; int error= 0; @@ -5044,6 +5056,8 @@ int rotate_relay_log(Master_info* mi) */ rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: + if (need_data_lock) + mysql_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); } diff --git a/sql/slave.h b/sql/slave.h index 0374a5d27ae..0cf8adb0315 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -205,7 +205,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg); void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); -int rotate_relay_log(Master_info* mi); +int rotate_relay_log(Master_info* mi, bool need_data_lock); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 40e350c4ddd..f24f31b6399 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -157,7 +157,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, { #ifdef HAVE_REPLICATION mysql_mutex_lock(&LOCK_active_mi); - if (rotate_relay_log(active_mi)) + if (rotate_relay_log(active_mi, true/*need_data_lock=true*/)) *write_to_binlog= -1; mysql_mutex_unlock(&LOCK_active_mi); #endif -- cgit v1.2.1 From 767bab4abe7666ee861984bc74ce87200ba23b5d Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Thu, 3 Mar 2016 06:42:12 +0530 Subject: Bug #18740222: CRASH IN GET_INTERVAL_INFO WITH WEIRDO INTERVALS ISSUE: ------ Some string functions return one or a combination of the parameters as their result. Here the resultant string's charset could be incorrectly set to that of the chosen parameter. This results in incorrect behavior when an ascii string is expected. SOLUTION: --------- Since an ascii string is expected, val_str_ascii should explicitly convert the string. Part of the fix is a backport of Bug#22340858 for mysql-5.5 and mysql-5.6. --- sql/item.cc | 17 +++++++++-------- sql/item_geofunc.cc | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index c482f0e1a04..f4917448dda 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -227,9 +227,6 @@ bool Item::val_bool() */ String *Item::val_str_ascii(String *str) { - if (!(collation.collation->state & MY_CS_NONASCII)) - return val_str(str); - DBUG_ASSERT(str != &str_value); uint errors; @@ -237,11 +234,15 @@ String *Item::val_str_ascii(String *str) if (!res) return 0; - if ((null_value= str->copy(res->ptr(), res->length(), - collation.collation, &my_charset_latin1, - &errors))) - return 0; - + if (!(res->charset()->state & MY_CS_NONASCII)) + str= res; + else + { + if ((null_value= str->copy(res->ptr(), res->length(), collation.collation, + &my_charset_latin1, &errors))) + return 0; + } + return str; } diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 621ddcb1a30..983491211c3 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -179,7 +179,7 @@ String *Item_func_geometry_type::val_str_ascii(String *str) /* String will not move */ str->copy(geom->get_class_info()->m_name.str, geom->get_class_info()->m_name.length, - default_charset()); + &my_charset_latin1); return str; } -- cgit v1.2.1 From 777c2131dd7aeaf25adbbbbb0c213950e852f22b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sat, 2 Apr 2016 00:04:47 +0400 Subject: MDEV-9862 Illegal mix of collation, when comparing column with CASE expression --- sql/item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index d09f6572487..41e6fe0e38e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2175,7 +2175,7 @@ public: max_length= 0; name= name_par ? name_par : (char*) "NULL"; fixed= 1; - collation.set(&my_charset_bin, DERIVATION_IGNORABLE); + collation.set(&my_charset_bin, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } enum Type type() const { return NULL_ITEM; } bool eq(const Item *item, bool binary_cmp) const; -- cgit v1.2.1 From 6fd54c01bb5bc480497b143d63181837148ff47f Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 18 Apr 2016 23:15:15 +0400 Subject: MDEV-9521 Least function returns 0000-00-00 for null date columns instead of null Item_func_ifnull::date_op() and Item_func_coalesce::date_op() could erroneously return 0000-00-00 instead of NULL when get_date() was called with the TIME_FUZZY_DATES flag, e.g. from LEAST(). --- sql/item_cmpfunc.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 81688f3321c..9287b74a867 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2558,10 +2558,7 @@ bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, uint fuzzydate) DBUG_ASSERT(fixed == 1); if (!args[0]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)) return (null_value= false); - if (!args[1]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)) - return (null_value= false); - bzero((char*) ltime,sizeof(*ltime)); - return null_value= !(fuzzydate & TIME_FUZZY_DATES); + return (null_value= args[1]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)); } @@ -3311,15 +3308,12 @@ double Item_func_coalesce::real_op() bool Item_func_coalesce::date_op(MYSQL_TIME *ltime,uint fuzzydate) { DBUG_ASSERT(fixed == 1); - null_value= 0; for (uint i= 0; i < arg_count; i++) { - bool res= args[i]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES); - if (!args[i]->null_value) - return res; + if (!args[i]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)) + return (null_value= false); } - bzero((char*) ltime,sizeof(*ltime)); - return null_value|= !(fuzzydate & TIME_FUZZY_DATES); + return (null_value= true); } -- cgit v1.2.1 From 3a8f43bec76d3d93a809b6a3c76e26e946ba0425 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Mon, 11 Apr 2016 11:41:47 +0530 Subject: Bug#22897202: RPL_IO_THD_WAIT_FOR_DISK_SPACE HAS OCCASIONAL FAILURES Analysis: ========= Test script is not ensuring that "assert_grep.inc" should be called only after 'Disk is full' error is written to the error log. Test checks for "Queueing master event to the relay log" state. But this state is set before invoking 'queue_event'. Actual 'Disk is full' error happens at a very lower level. It can happen that we might even reset the debug point before even the actual disk full simulation occurs and the "Disk is full" message will never appear in the error log. In order to guarentee that we must have some mechanism where in after we write "Disk is full" error messge into the error log we must signal the test to execute SSS and then reset the debug point. So that test is deterministic. Fix: === Added debug sync point to make script deterministic. --- sql/log.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index eab9a118147..a7f05905514 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4452,6 +4452,14 @@ bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) sufficient to block SQL thread when IO thread is updating relay log here. */ mysql_mutex_unlock(&mi->data_lock); + DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space", + { + const char act[]= "disk_full_reached SIGNAL parked"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); + do { if (my_b_append(&log_file,(uchar*) buf,len)) -- cgit v1.2.1 From fbf44eed3c69dc15047ac2d40c09dd0d16993fb0 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Tue, 19 Apr 2016 14:49:27 +0530 Subject: BUG#22286421: NULL POINTER DEREFERENCE ANALYSIS: ========= A LEX_STRING structure pointer is processed during the validation of a stored program name. During this processing, there is a possibility of null pointer dereference. FIX: ==== check_routine_name() is invoked by the parser by supplying a non-empty string as the SP name. To avoid any potential calls to check_routine_name() with NULL value, a debug assert has been added to catch such cases. --- sql/sp_head.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 13d1b310599..992e7415f45 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -490,8 +490,9 @@ sp_name::init_qname(THD *thd) bool check_routine_name(LEX_STRING *ident) { - if (!ident || !ident->str || !ident->str[0] || - ident->str[ident->length-1] == ' ') + DBUG_ASSERT(ident != NULL && ident->str != NULL); + + if (!ident->str[0] || ident->str[ident->length-1] == ' ') { my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; -- cgit v1.2.1 From edf71fd1d7b2d93c7f550d7b2cfecaf6b048fcec Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 16 Apr 2016 10:28:03 +0200 Subject: MDEV-9928 LC_TIME_NAMES=de_AT; unusual name for february s/Feber/Februar/ --- sql/sql_locale.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 13e00c99f19..3123474a59b 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -426,7 +426,7 @@ MY_LOCALE my_locale_da_DK /***** LOCALE BEGIN de_AT: German - Austria *****/ static const char *my_locale_month_names_de_AT[13] = - {"Jänner","Feber","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember", NullS }; + {"Jänner","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember", NullS }; static const char *my_locale_ab_month_names_de_AT[13] = {"Jän","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez", NullS }; static const char *my_locale_day_names_de_AT[8] = -- cgit v1.2.1 From 4f133fbf7951d0f48860cdefe79416f930615dab Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 16 Apr 2016 12:39:20 +0200 Subject: MDEV-9493 --tc-heuristic-recover option values off by one fix typelib to match defines: #define TC_HEURISTIC_RECOVER_COMMIT 1 #define TC_HEURISTIC_RECOVER_ROLLBACK 2 --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 45fb49f9cd9..fb52041fbc2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -279,7 +279,7 @@ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; static const char *tc_heuristic_recover_names[]= { - "COMMIT", "ROLLBACK", NullS + "OFF", "COMMIT", "ROLLBACK", NullS }; static TYPELIB tc_heuristic_recover_typelib= { -- cgit v1.2.1 From 3294cd11f852357b638cac74ba32578ffb456fc7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 16 Apr 2016 17:36:47 +0200 Subject: MDEV-9929 MariaDB segfaults on command "mysqld --version" with ignore-db-dir option on /etc/my.cnf don't put command-line arguments into opt_ignore_db_dirs - it is supposed to contain a malloc()'ed accumulated list of all ignored dirs --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fb52041fbc2..3450447ceb9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7800,6 +7800,7 @@ mysqld_get_one_option(int optid, case OPT_IGNORE_DB_DIRECTORY: + opt_ignore_db_dirs= NULL; // will be set in ignore_db_dirs_process_additions if (*argument == 0) ignore_db_dirs_reset(); else -- cgit v1.2.1 From 95fe71afa6f1243af63429c5295b8b4bd74d6459 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 17 Apr 2016 18:51:54 +0200 Subject: MDEV-9707 MAX(timestamp(6) column) in correlated sub-query returns non-existent row data in original table special treatment for temporal values in create_tmp_field_from_item(). old code only did it when result_type() was STRING_RESULT, but Item_cache_temporal::result_type() is INT_RESULT --- sql/sql_select.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1e22537b37..828dab7ef99 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14544,6 +14544,14 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, Field *new_field; LINT_INIT(new_field); + /* + To preserve type or DATE/TIME and GEOMETRY fields, + they need to be handled separately. + */ + if (item->cmp_type() == TIME_RESULT || + item->field_type() == MYSQL_TYPE_GEOMETRY) + new_field= item->tmp_table_field_from_field_type(table, 1); + else switch (item->result_type()) { case REAL_RESULT: new_field= new Field_double(item->max_length, maybe_null, @@ -14566,18 +14574,11 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, case STRING_RESULT: DBUG_ASSERT(item->collation.collation); - /* - DATE/TIME and GEOMETRY fields have STRING_RESULT result type. - To preserve type they needed to be handled separately. - */ - if (item->cmp_type() == TIME_RESULT || - item->field_type() == MYSQL_TYPE_GEOMETRY) - new_field= item->tmp_table_field_from_field_type(table, 1); /* Make sure that the blob fits into a Field_varstring which has 2-byte lenght. */ - else if (item->max_length/item->collation.collation->mbmaxlen > 255 && + if (item->max_length/item->collation.collation->mbmaxlen > 255 && convert_blob_length <= Field_varstring::MAX_SIZE && convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, -- cgit v1.2.1 From cc04a9fc0f60610d900f27ef60f8916a4ce1bb4c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Apr 2016 18:30:42 +0200 Subject: MDEV-9835 Valid password is not working after server restart On SET PASSWORD if the plugin is mysql_native_password or mysql_old_password, do reset plugin and auth_str fields. --- sql/sql_acl.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index da7c3f17c63..de76f27dee6 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -557,9 +557,8 @@ static void init_check_host(void); static void rebuild_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user, my_bool exact); -static bool update_user_table(THD *thd, TABLE *table, const char *host, - const char *user, const char *new_password, - uint new_password_len); +static bool update_user_table(THD *, TABLE *, const char *, const char *, const + char *, uint, bool); static my_bool acl_load(THD *thd, TABLE_LIST *tables); static my_bool grant_load(THD *thd, TABLE_LIST *tables); static inline void get_grantor(THD *thd, char* grantor); @@ -1912,6 +1911,7 @@ bool change_password(THD *thd, const char *host, const char *user, bool save_binlog_row_based; uint new_password_len= (uint) strlen(new_password); bool result= 1; + bool use_salt= 0; DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -1967,6 +1967,7 @@ bool change_password(THD *thd, const char *host, const char *user, acl_user->auth_string.length= new_password_len; set_user_salt(acl_user, new_password, new_password_len); set_user_plugin(acl_user, new_password_len); + use_salt= 1; } else push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, @@ -1975,7 +1976,7 @@ bool change_password(THD *thd, const char *host, const char *user, if (update_user_table(thd, table, acl_user->host.hostname ? acl_user->host.hostname : "", acl_user->user ? acl_user->user : "", - new_password, new_password_len)) + new_password, new_password_len, use_salt)) { mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ goto end; @@ -2223,7 +2224,8 @@ bool hostname_requires_resolving(const char *hostname) static bool update_user_table(THD *thd, TABLE *table, const char *host, const char *user, - const char *new_password, uint new_password_len) + const char *new_password, uint new_password_len, + bool reset_plugin) { char user_key[MAX_KEY_LENGTH]; int error; @@ -2246,6 +2248,11 @@ static bool update_user_table(THD *thd, TABLE *table, } store_record(table,record[1]); table->field[2]->store(new_password, new_password_len, system_charset_info); + if (reset_plugin && table->s->fields >= 41) + { + table->field[40]->reset(); + table->field[41]->reset(); + } if ((error=table->file->ha_update_row(table->record[1],table->record[0])) && error != HA_ERR_RECORD_IS_THE_SAME) { -- cgit v1.2.1 From 9a987142f93756b37b2ff02d513034cc4079c978 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 20 Apr 2016 08:53:30 +0400 Subject: MDEV-9745 Crash with CASE WHEN TRUE THEN COALESCE(CAST(NULL AS UNSIGNED)) ELSE 4 END This is a backport of the patch for MDEV-9653 (fixed earlier in 10.1.13). The code in Item_func_case::fix_length_and_dec() did not calculate max_length and decimals properly. In case of any numeric result (DECIMAL, REAL, INT) a generic method Item_func_case::agg_num_lengths() was called, which could erroneously result into a DECIMAL item with max_length==0 and decimals==0, so the constructor of Field_new_decimals tried to create a field of DECIMAL(0,0) type, which caused a crash. Unlike Item_func_case, the code responsible for merging attributes in Item_func_coalesce::fix_length_and_dec() works fine: it has specific execution branches for all distinct numeric types and correctly creates a DECIMAL(1,0) column instead of DECIMAL(0,0) for the same set of arguments. The fix does the following: - Moves the attribute merging code from Item_func_coalesce::fix_length_and_dec() to a new method Item_func_hybrid_result_type::fix_attributes() - Removes the wrong code from Item_func_case::fix_length_and_dec() and reuses fix_attributes() in both Item_func_coalesce::fix_length_and_dec() and Item_func_case::fix_length_and_dec() - Fixes count_real_length() and count_decimal_length() to get an array of Items as an argument, instead of using Item::args directly. This is needed for Item_func_case::fix_length_and_dec(). - Moves methods Item_func::count_xxx_length() from "public" to "protected". - Removes Item_func_case::agg_num_length(), as it's not used any more. - Additionally removes Item_func_case::agg_str_length(), as it also was not used (dead code). --- sql/item_cmpfunc.cc | 51 ++++++++++++++++++--------------------------------- sql/item_cmpfunc.h | 2 -- sql/item_func.cc | 22 +++++++++++----------- sql/item_func.h | 15 ++++++++------- 4 files changed, 37 insertions(+), 53 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9287b74a867..fb75c9af794 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3015,24 +3015,6 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) } -void Item_func_case::agg_str_lengths(Item* arg) -{ - fix_char_length(max(max_char_length(), arg->max_char_length())); - set_if_bigger(decimals, arg->decimals); - unsigned_flag= unsigned_flag && arg->unsigned_flag; -} - - -void Item_func_case::agg_num_lengths(Item *arg) -{ - uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals, - arg->unsigned_flag) - arg->decimals; - set_if_bigger(max_length, len); - set_if_bigger(decimals, arg->decimals); - unsigned_flag= unsigned_flag && arg->unsigned_flag; -} - - /** Check if (*place) and new_value points to different Items and call THD::change_item_tree() if needed. @@ -3098,17 +3080,7 @@ void Item_func_case::fix_length_and_dec() } else { - collation.set_numeric(); - max_length=0; - decimals=0; - unsigned_flag= TRUE; - for (uint i= 0; i < ncases; i+= 2) - agg_num_lengths(args[i + 1]); - if (else_expr_num != -1) - agg_num_lengths(args[else_expr_num]); - max_length= my_decimal_precision_to_length_no_truncation(max_length + - decimals, decimals, - unsigned_flag); + fix_attributes(agg, nagg); } /* @@ -3336,19 +3308,32 @@ void Item_func_coalesce::fix_length_and_dec() { cached_field_type= agg_field_type(args, arg_count); agg_result_type(&cached_result_type, args, arg_count); + fix_attributes(args, arg_count); +} + + +#if MYSQL_VERSION_ID > 100100 +#error Rename this to Item_hybrid_func::fix_attributes() when mering to 10.1 +#endif +void Item_func_hybrid_result_type::fix_attributes(Item **items, uint nitems) +{ switch (cached_result_type) { case STRING_RESULT: - if (count_string_result_length(cached_field_type, args, arg_count)) + if (count_string_result_length(field_type(), + items, nitems)) return; break; case DECIMAL_RESULT: - count_decimal_length(); + collation.set_numeric(); + count_decimal_length(items, nitems); break; case REAL_RESULT: - count_real_length(); + collation.set_numeric(); + count_real_length(items, nitems); break; case INT_RESULT: - count_only_length(args, arg_count); + collation.set_numeric(); + count_only_length(items, nitems); decimals= 0; break; case ROW_RESULT: diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 0faba016ba8..0194f9cd0e0 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1255,8 +1255,6 @@ public: Item *find_item(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } void cleanup(); - void agg_str_lengths(Item *arg); - void agg_num_lengths(Item *arg); }; /* diff --git a/sql/item_func.cc b/sql/item_func.cc index 252ca9e504b..bd6553d45d4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -641,16 +641,16 @@ void Item_func::count_datetime_length(Item **item, uint nitems) result length/precision depends on argument ones. */ -void Item_func::count_decimal_length() +void Item_func::count_decimal_length(Item **item, uint nitems) { int max_int_part= 0; decimals= 0; unsigned_flag= 1; - for (uint i=0 ; i < arg_count ; i++) + for (uint i=0 ; i < nitems ; i++) { - set_if_bigger(decimals, args[i]->decimals); - set_if_bigger(max_int_part, args[i]->decimal_int_part()); - set_if_smaller(unsigned_flag, args[i]->unsigned_flag); + set_if_bigger(decimals, item[i]->decimals); + set_if_bigger(max_int_part, item[i]->decimal_int_part()); + set_if_smaller(unsigned_flag, item[i]->unsigned_flag); } int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION); fix_char_length(my_decimal_precision_to_length_no_truncation(precision, @@ -681,19 +681,19 @@ void Item_func::count_only_length(Item **item, uint nitems) result length/precision depends on argument ones. */ -void Item_func::count_real_length() +void Item_func::count_real_length(Item **item, uint nitems) { uint32 length= 0; decimals= 0; max_length= 0; - for (uint i=0 ; i < arg_count ; i++) + for (uint i=0 ; i < nitems ; i++) { if (decimals != NOT_FIXED_DEC) { - set_if_bigger(decimals, args[i]->decimals); - set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); + set_if_bigger(decimals, item[i]->decimals); + set_if_bigger(length, (item[i]->max_length - item[i]->decimals)); } - set_if_bigger(max_length, args[i]->max_length); + set_if_bigger(max_length, item[i]->max_length); } if (decimals != NOT_FIXED_DEC) { @@ -811,7 +811,7 @@ void Item_num_op::fix_length_and_dec(void) if (r0 == REAL_RESULT || r1 == REAL_RESULT || r0 == STRING_RESULT || r1 ==STRING_RESULT) { - count_real_length(); + count_real_length(args, arg_count); max_length= float_length(decimals); cached_result_type= REAL_RESULT; } diff --git a/sql/item_func.h b/sql/item_func.h index 33fa49f9168..9776ec0a5b7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -39,6 +39,13 @@ protected: 0 means get this number from first argument */ uint allowed_arg_cols; + + void count_only_length(Item **item, uint nitems); + void count_real_length(Item **item, uint nitems); + void count_decimal_length(Item **item, uint nitems); + void count_datetime_length(Item **item, uint nitems); + bool count_string_result_length(enum_field_types field_type, + Item **item, uint nitems); public: uint arg_count; table_map used_tables_cache, not_null_tables_cache; @@ -146,16 +153,10 @@ public: virtual void print(String *str, enum_query_type query_type); void print_op(String *str, enum_query_type query_type); void print_args(String *str, uint from, enum_query_type query_type); - void count_only_length(Item **item, uint nitems); - void count_real_length(); - void count_decimal_length(); inline bool get_arg0_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { return (null_value=args[0]->get_date(ltime, fuzzy_date)); } - void count_datetime_length(Item **item, uint nitems); - bool count_string_result_length(enum_field_types field_type, - Item **item, uint nitems); inline bool get_arg0_time(MYSQL_TIME *ltime) { null_value= args[0]->get_time(ltime); @@ -436,7 +437,7 @@ class Item_func_hybrid_result_type: public Item_func } protected: Item_result cached_result_type; - + void fix_attributes(Item **item, uint nitems); public: Item_func_hybrid_result_type() :Item_func(), cached_result_type(REAL_RESULT) { collation.set_numeric(); } -- cgit v1.2.1 From 9e826bfa36a57f10540ca6ea649cb450add48cf4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Apr 2016 15:28:44 +0200 Subject: trivial optimization don't call write_bin_log() when binlog is known to be disable --- sql/sql_table.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9d161ebc0de..024ca9b58e1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4880,8 +4880,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, /* We have to write the query before we unlock the tables. */ - if (!thd->is_current_stmt_binlog_disabled() && - thd->is_current_stmt_binlog_format_row()) + if (thd->is_current_stmt_binlog_disabled()) + goto err; + + if (thd->is_current_stmt_binlog_format_row()) { /* Since temporary tables are not replicated under row-based -- cgit v1.2.1 From 24ac546d0f16d5f56b11c068e4f187a9c4c56bd0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Apr 2016 18:27:23 +0200 Subject: use consistent error messaging for IGNORE 1. the same message text for INSERT and INSERT IGNORE 2. no new warnings in UPDATE IGNORE yet (big change for 5.5) and replace a commonly used expression with a named constant --- sql/handler.cc | 25 ------------------------- sql/handler.h | 3 +-- sql/sql_insert.cc | 13 +++++-------- sql/sql_update.cc | 24 +++++------------------- 4 files changed, 11 insertions(+), 54 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 1a318334ef3..d528c0aea7a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5463,28 +5463,3 @@ fl_create_iterator(enum handler_iterator_type type, } } #endif /*TRANS_LOG_MGM_EXAMPLE_CODE*/ - - -/** - Report a warning for FK constraint violation. - - @param thd Thread handle. - @param table table on which the operation is performed. - @param error handler error number. -*/ -void warn_fk_constraint_violation(THD *thd,TABLE *table, int error) -{ - String str; - switch(error) { - case HA_ERR_ROW_IS_REFERENCED: - table->file->get_error_message(error, &str); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ROW_IS_REFERENCED_2, str.c_ptr_safe()); - break; - case HA_ERR_NO_REFERENCED_ROW: - table->file->get_error_message(error, &str); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_REFERENCED_ROW_2, str.c_ptr_safe()); - break; - } -} diff --git a/sql/handler.h b/sql/handler.h index 11718ba775c..3d6c8dea2bf 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -335,6 +335,7 @@ #define HA_CHECK_DUP_UNIQUE 2 #define HA_CHECK_FK_ERROR 4 #define HA_CHECK_DUP (HA_CHECK_DUP_KEY + HA_CHECK_DUP_UNIQUE) +#define HA_CHECK_ALL (~0U) enum legacy_db_type { @@ -3110,6 +3111,4 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name) return ((lower_case_table_names == 2 && info->alias) ? info->alias : name); } -void warn_fk_constraint_violation(THD *thd, TABLE *table, int error); - #endif /* HANDLER_INCLUDED */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7e3a898b3da..c60ef6fcc6e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1609,9 +1609,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) else table->file->insert_id_for_cur_row= insert_id_for_cur_row; bool is_duplicate_key_error; - if (table->file->is_fatal_error(error, HA_CHECK_DUP | HA_CHECK_FK_ERROR)) + if (table->file->is_fatal_error(error, HA_CHECK_ALL)) goto err; - is_duplicate_key_error= table->file->is_fatal_error(error, 0); + is_duplicate_key_error= + table->file->is_fatal_error(error, HA_CHECK_ALL & ~HA_CHECK_DUP); if (!is_duplicate_key_error) { /* @@ -1712,8 +1713,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) error != HA_ERR_RECORD_IS_THE_SAME) { if (info->ignore && - !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + !table->file->is_fatal_error(error, HA_CHECK_ALL)) { if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) @@ -1845,7 +1845,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) { DEBUG_SYNC(thd, "write_row_noreplace"); if (!info->ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP | HA_CHECK_FK_ERROR)) + table->file->is_fatal_error(error, HA_CHECK_ALL)) goto err; if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) @@ -1866,9 +1866,6 @@ ok_or_after_trg_err: my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH); if (!table->file->has_transactions()) thd->transaction.stmt.modified_non_trans_table= TRUE; - if (info->ignore && - !table->file->is_fatal_error(error, HA_CHECK_FK_ERROR)) - warn_fk_constraint_violation(thd, table, error); DBUG_RETURN(trg_error); err: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d1b6e945b23..f134e0ba266 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -774,8 +774,7 @@ int mysql_update(THD *thd, error= 0; } else if (!ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + table->file->is_fatal_error(error, HA_CHECK_ALL)) { /* If (ignore && error is ignorable) we don't have to @@ -783,8 +782,7 @@ int mysql_update(THD *thd, */ myf flags= 0; - if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + if (table->file->is_fatal_error(error, HA_CHECK_ALL)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); @@ -792,9 +790,6 @@ int mysql_update(THD *thd, error= 1; break; } - else if (ignore && !table->file->is_fatal_error(error, - HA_CHECK_FK_ERROR)) - warn_fk_constraint_violation(thd, table, error); } if (table->triggers && @@ -1974,8 +1969,7 @@ int multi_update::send_data(List ¬_used_values) { updated--; if (!ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + table->file->is_fatal_error(error, HA_CHECK_ALL)) { /* If (ignore && error == is ignorable) we don't have to @@ -1983,17 +1977,13 @@ int multi_update::send_data(List ¬_used_values) */ myf flags= 0; - if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + if (table->file->is_fatal_error(error, HA_CHECK_ALL)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); table->file->print_error(error,MYF(flags)); DBUG_RETURN(1); } - else if (ignore && !table->file->is_fatal_error(error, - HA_CHECK_FK_ERROR)) - warn_fk_constraint_violation(thd, table, error); } else { @@ -2266,15 +2256,11 @@ int multi_update::do_updates() local_error != HA_ERR_RECORD_IS_THE_SAME) { if (!ignore || - table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY | - HA_CHECK_FK_ERROR)) + table->file->is_fatal_error(local_error, HA_CHECK_ALL)) { err_table= table; goto err; } - else if (ignore && !table->file->is_fatal_error(local_error, - HA_CHECK_FK_ERROR)) - warn_fk_constraint_violation(thd, table, local_error); } if (local_error != HA_ERR_RECORD_IS_THE_SAME) updated++; -- cgit v1.2.1 From e5410da190d3e37af997f5b9bb1de2acb818f6f5 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Thu, 21 Apr 2016 08:18:54 -0700 Subject: SEGFAULT in get_column_grant() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to a typo, the wrong grant_table was used when fetching privileges for roles. Signed-off-by: VicenÈ›iu Ciorbaru --- sql/sql_acl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a70afe4fca9..bbd1dd86880 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7453,7 +7453,8 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, if (!grant_column) priv|= (grant->privilege | grant_table_role->privs); else - priv|= (grant->privilege | grant_table->privs | grant_column->rights); + priv|= (grant->privilege | grant_table_role->privs | + grant_column->rights); } } mysql_rwlock_unlock(&LOCK_grant); -- cgit v1.2.1 From 3b6f9aac02b126db57fa3e3f1873713438d0a950 Mon Sep 17 00:00:00 2001 From: Nisha Gopalakrishnan Date: Fri, 22 Apr 2016 10:25:16 +0530 Subject: BUG#23135731: INSERT WITH DUPLICATE KEY UPDATE REPORTS INCORRECT ERROR. Analysis ======== INSERT with DUPLICATE KEY UPDATE and REPLACE on a table where foreign key constraint is defined fails with an incorrect 'duplicate entry' error rather than foreign key constraint violation error. As part of the bug fix for BUG#22037930, a new flag 'HA_CHECK_FK_ERROR' was added while checking for non fatal errors to manage FK errors based on the 'IGNORE' flag. For INSERT with DUPLICATE KEY UPDATE and REPLACE queries, the foreign key constraint violation error was marked as non-fatal, even though IGNORE was not set. Hence it continued with the duplicate key processing resulting in an incorrect error. Fix: === Foreign key violation errors are treated as non fatal only when the IGNORE is not set in the above mentioned queries. Hence reports the appropriate foreign key violation error. --- sql/sql_insert.cc | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a267108c847..dc7cb698476 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1521,16 +1521,25 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) insert_id_for_cur_row= table->file->insert_id_for_cur_row; else table->file->insert_id_for_cur_row= insert_id_for_cur_row; - bool is_duplicate_key_error; - if (table->file->is_fatal_error(error, HA_CHECK_DUP | HA_CHECK_FK_ERROR)) + + /* + If it is a FK constraint violation and 'ignore' flag is set, + report a warning instead of error. + */ + if (info->ignore && !table->file->is_fatal_error(error, + HA_CHECK_FK_ERROR)) + goto ok_or_after_trg_err; + + if (table->file->is_fatal_error(error, HA_CHECK_DUP)) goto err; - is_duplicate_key_error= table->file->is_fatal_error(error, 0); - if (!is_duplicate_key_error) + + if (!table->file->is_fatal_error(error, 0)) { /* - We come here when we had an ignorable error which is not a duplicate - key error. In this we ignore error if ignore flag is set, otherwise - report error as usual. We will not do any duplicate key processing. + We come here when we have an ignorable error which is not a duplicate + key error or FK error(Ex: Partition related errors). In this case we + ignore the error if ignore flag is set, otherwise report error as usual. + We will not do any duplicate key processing. */ if (info->ignore) goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */ -- cgit v1.2.1 From 994030c0e25c26c51602fde14d316552edf0a922 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 21 Apr 2016 16:51:00 +0400 Subject: MDEV-8889 - Assertion `next_insert_id == 0' failed in handler::ha_external_lock There was a race condition between delayed insert thread and connection thread actually performing INSERT/REPLACE DELAYED. It was triggered by concurrent INSERT/REPLACE DELAYED and statements that flush the same table either explicitely or implicitely (like FLUSH TABLE, ALTER TABLE, ...). This race condition was caused by a gap in delayed thread shutdown logic, which allowed concurrent connection running INSERT/REPLACE DELAYED to change essential data consequently leaving table in semi-consistent state. Specifically query thread could decrease "tables_in_use" reference counter in this gap, causing delayed insert thread to shutdown without releasing auto increment and table lock. Fixed by extending condition so that delayed insert thread won't shutdown until there're locked tables. Also removed volatile qualifier from tables_in_use and stacked_inserts since they're supposed to be protected by mutexes. --- sql/sql_insert.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 42d88395060..b0151182a88 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1978,7 +1978,7 @@ public: TABLE *table; mysql_mutex_t mutex; mysql_cond_t cond, cond_client; - volatile uint tables_in_use,stacked_inserts; + uint tables_in_use, stacked_inserts; volatile bool status; /** When the handler thread starts, it clones a metadata lock ticket @@ -2863,7 +2863,8 @@ pthread_handler_t handle_delayed_insert(void *arg) lock_count=di->lock_count(); mysql_mutex_unlock(&LOCK_delayed_insert); mysql_mutex_lock(&di->mutex); - if (!lock_count && !di->tables_in_use && !di->stacked_inserts) + if (!lock_count && !di->tables_in_use && !di->stacked_inserts && + !thd->lock) break; // Time to die } -- cgit v1.2.1 From 3f0d07e55b0a2ab8c7bdc1209d55ec2f66542830 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 22 Apr 2016 16:04:20 +0400 Subject: MDEV-9372 select 100 between 1 and 9223372036854775808 returns false Integer comparison of INT expressions with different signess in BETWEEN is not safe. Switching to DECIMAL comparison in case if INT arguments have different signess. --- sql/item_cmpfunc.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fb75c9af794..3bd0b5b3fa2 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -160,10 +160,11 @@ static int cmp_row_type(Item* item1, Item* item2) static int agg_cmp_type(Item_result *type, Item **items, uint nitems) { - uint i; + uint unsigned_count= items[0]->unsigned_flag; type[0]= items[0]->cmp_type(); - for (i= 1 ; i < nitems ; i++) + for (uint i= 1 ; i < nitems ; i++) { + unsigned_count+= items[i]->unsigned_flag; type[0]= item_cmp_type(type[0], items[i]->cmp_type()); /* When aggregating types of two row expressions we have to check @@ -175,6 +176,12 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems) if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i])) return 1; // error found: invalid usage of rows } + /** + If all arguments are of INT type but have different unsigned_flag values, + switch to DECIMAL_RESULT. + */ + if (type[0] == INT_RESULT && unsigned_count != nitems && unsigned_count != 0) + type[0]= DECIMAL_RESULT; return 0; } -- cgit v1.2.1 From 19e3597e0c718a4cfdfe8789c7b4b11a4e0ba0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 7 Apr 2016 10:47:46 +0300 Subject: MDEV-9142 :Adding Constraint with no database reference results in ERROR 1046 (3D000) at line 13: No database selected. Use database from create table to foreign key database if nothing else is given. --- sql/sql_parse.cc | 30 +++++++++++++++++++++++++----- sql/sql_parse.h | 3 ++- sql/sql_table.cc | 2 +- 3 files changed, 28 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a52d55b47e9..a3114aba7d3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5395,6 +5395,7 @@ bool check_global_access(THD *thd, ulong want_access, bool no_errors) temporary table flag) @param alter_info [in] Initial list of columns and indexes for the table to be created + @param create_db [in] Database of the created table @retval false ok. @@ -5403,7 +5404,8 @@ bool check_global_access(THD *thd, ulong want_access, bool no_errors) */ bool check_fk_parent_table_access(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info) + Alter_info *alter_info, + const char* create_db) { Key *key; List_iterator key_iterator(alter_info->key_list); @@ -5443,10 +5445,28 @@ bool check_fk_parent_table_access(THD *thd, return true; } } - else if (thd->lex->copy_db_to(&db_name.str, &db_name.length)) - return true; else - is_qualified_table_name= false; + { + if (!thd->db) + { + db_name.str= (char *) thd->memdup(create_db, strlen(create_db)+1); + db_name.length= strlen(create_db); + is_qualified_table_name= true; + + if(create_db && check_db_name(&db_name)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); + return true; + } + } + else + { + if (thd->lex->copy_db_to(&db_name.str, &db_name.length)) + return true; + else + is_qualified_table_name= false; + } + } // if lower_case_table_names is set then convert tablename to lower case. if (lower_case_table_names) @@ -7462,7 +7482,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, goto err; } - if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info)) + if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, create_table->db)) goto err; error= FALSE; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 60d5925c573..4c3070d197d 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -47,7 +47,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); bool check_fk_parent_table_access(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info); + Alter_info *alter_info, + const char* create_db); bool parse_sql(THD *thd, Parser_state *parser_state, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 024ca9b58e1..2cd36ceb4de 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6305,7 +6305,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, till this point for the alter operation. */ if ((alter_info->flags & ALTER_FOREIGN_KEY) && - check_fk_parent_table_access(thd, create_info, alter_info)) + check_fk_parent_table_access(thd, create_info, alter_info, new_db)) goto err; /* -- cgit v1.2.1 From d821dd106ad5086299e3e469f02dfd32eddf04ae Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 21 Apr 2016 14:51:37 +0200 Subject: MDEV-9580 SHOW GRANTS FOR fails use get_current_user() to distinguish user name without a hostname and a role name. move privilege checks inside mysql_show_grants() to remove duplicate get_current_user() calls --- sql/sql_acl.cc | 26 +++++++++++++------------- sql/sql_parse.cc | 13 +------------ 2 files changed, 14 insertions(+), 25 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index bbd1dd86880..502e9ff83f2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7559,9 +7559,6 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) DBUG_RETURN(TRUE); } - mysql_rwlock_rdlock(&LOCK_grant); - mysql_mutex_lock(&acl_cache->lock); - if (lex_user->user.str == current_user.str) { username= thd->security_ctx->priv_user; @@ -7579,23 +7576,28 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) } else { - lex_user= get_current_user(thd, lex_user, false); + Security_context *sctx= thd->security_ctx; + bool do_check_access; + + lex_user= get_current_user(thd, lex_user); if (!lex_user) - { - mysql_mutex_unlock(&acl_cache->lock); - mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(TRUE); - } if (lex_user->is_role()) { rolename= lex_user->user.str; + do_check_access= strcmp(rolename, sctx->priv_role); } else { username= lex_user->user.str; hostname= lex_user->host.str; + do_check_access= strcmp(username, sctx->priv_user) || + strcmp(hostname, sctx->priv_host); } + + if (do_check_access && check_access(thd, SELECT_ACL, "mysql", 0, 0, 1, 0)) + DBUG_RETURN(TRUE); } DBUG_ASSERT(rolename || username); @@ -7610,12 +7612,10 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) field_list.push_back(field); if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - { - mysql_mutex_unlock(&acl_cache->lock); - mysql_rwlock_unlock(&LOCK_grant); - DBUG_RETURN(TRUE); - } + + mysql_rwlock_rdlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); if (username) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d2fed787ba9..b91455888b8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4374,21 +4374,10 @@ end_with_restore_list: case SQLCOM_SHOW_GRANTS: { LEX_USER *grant_user= lex->grant_user; - Security_context *sctx= thd->security_ctx; if (!grant_user) goto error; - if (grant_user->user.str && !strcmp(sctx->priv_user, grant_user->user.str) && - grant_user->host.str && !strcmp(sctx->priv_host, grant_user->host.str)) - grant_user->user= current_user; - - if (grant_user->user.str == current_user.str || - grant_user->user.str == current_role.str || - grant_user->user.str == current_user_and_current_role.str || - !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 0)) - { - res = mysql_show_grants(thd, grant_user); - } + res = mysql_show_grants(thd, grant_user); break; } #endif -- cgit v1.2.1 From 97728e107a5262266a2f6ed61bae9639a1717831 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 22 Apr 2016 08:16:06 +0200 Subject: comment clarify Alter_inplace_info::ALTER_PARTITIONED --- sql/handler.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 8dc05a1d9df..6ec9769036c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1822,7 +1822,10 @@ public: // Virtual columns changed static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 30; - // ALTER TABLE for a partitioned table + /** + ALTER TABLE for a partitioned table. The engine needs to commit + online alter of all partitions atomically (using group_commit_ctx) + */ static const HA_ALTER_FLAGS ALTER_PARTITIONED = 1L << 31; /** -- cgit v1.2.1 From b233b15ccda8d8a1633e82113e5731cefce5eb84 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 22 Apr 2016 08:25:36 +0200 Subject: MDEV-9868 Altering a partitioned table comment does a full copy let handler::check_if_supported_inplace_alter() (that detects frm-only changes) to work for partitioned tables too. --- sql/handler.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 9b217c60100..61d2b37c90f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4209,6 +4209,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info::ALTER_COLUMN_DEFAULT | Alter_inplace_info::ALTER_COLUMN_OPTION | Alter_inplace_info::CHANGE_CREATE_OPTION | + Alter_inplace_info::ALTER_PARTITIONED | Alter_inplace_info::ALTER_RENAME; /* Is there at least one operation that requires copy algorithm? */ -- cgit v1.2.1 From 797cadce47ecacd9dff2ee4829786e0be3009748 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 22 Apr 2016 13:13:48 +0200 Subject: MDEV-8482 mysql-test - main.func_encrypt fails if FIPS=1 * check for openssl errors in DES_ENCRYPT/DES_DECRYPT * disable the test when DES doesn't work * also disable main.func_des_encrypt --- sql/item_strfunc.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 3b8bc1580bb..4ea3075e69c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -828,9 +828,10 @@ String *Item_func_des_encrypt::val_str(String *str) /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */ bzero((char*) &ivec,sizeof(ivec)); - EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, + if (!EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, (uchar*) keystr->ptr(), (int) keystr->length(), - 1, (uchar*) &keyblock,ivec); + 1, (uchar*) &keyblock,ivec)) + goto error; DES_set_key_unchecked(&keyblock.key1,&keyschedule.ks1); DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); @@ -921,9 +922,10 @@ String *Item_func_des_decrypt::val_str(String *str) goto error; bzero((char*) &ivec,sizeof(ivec)); - EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, + if (!EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, (uchar*) keystr->ptr(),(int) keystr->length(), - 1,(uchar*) &keyblock,ivec); + 1,(uchar*) &keyblock,ivec)) + goto error; // Here we set all 64-bit keys (56 effective) one by one DES_set_key_unchecked(&keyblock.key1,&keyschedule.ks1); DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); -- cgit v1.2.1 From f6cc7f1bdc56e57cf441f99f2c88ca92aeeebc11 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 25 Apr 2016 15:37:24 +0300 Subject: Fixed failing test cases and compiler warnings - Fixed wait condition in kill_processlist-6619 - Updated Ssl_chiper for openssl tests - Added supression for valgrinds when using libcrypto - Fixed wrong argument to pthread_mutex in server_audit.c when compiling with debug - Adding missing debug_sync_update() to debug_sync.h - Added initializers to some variables and fixed error handling in jsonudf.cpp - Fixed cluster_filter_unpack_varchar which doesn't have a stable index type. - Updated compiler_warnings.supp --- sql/debug_sync.h | 1 + sql/sys_vars.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/debug_sync.h b/sql/debug_sync.h index bf1b3167dbc..25b379e5892 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -44,6 +44,7 @@ extern void debug_sync_end(void); extern void debug_sync_init_thread(THD *thd); extern void debug_sync_end_thread(THD *thd); extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len); +extern bool debug_sync_update(THD *thd, char *val_str); #endif /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 36067c50cc1..79b67d3b45c 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -30,6 +30,7 @@ #include "strfunc.h" #include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone #include "rpl_mi.h" // For Multi-Source Replication +#include "debug_sync.h" /* a set of mostly trivial (as in f(X)=X) defines below to make system variable @@ -1455,7 +1456,6 @@ public: } bool session_update(THD *thd, set_var *var) { - extern bool debug_sync_update(THD *thd, char *val_str); return debug_sync_update(thd, var->save_result.string_value.str); } bool global_update(THD *thd, set_var *var) -- cgit v1.2.1 From 22204807317c467b2f09dd0dcd13898a48501b10 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 25 Apr 2016 18:59:41 +0200 Subject: MDEV-7775 Wrong error message (Unknown error) when idle sessions are killed after wait_timeout restore the error message that was removed by mistake in ec38c1bbd709 --- sql/sql_connect.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 16b53da1ebd..61f8b4081eb 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1092,7 +1092,8 @@ void end_connection(THD *thd) } if (!thd->killed && (net->error && net->vio != 0)) - thd->print_aborted_warning(1, ER(ER_UNKNOWN_ERROR)); + thd->print_aborted_warning(1, + thd->stmt_da->is_error() ? thd->stmt_da->message() : ER(ER_UNKNOWN_ERROR)); } -- cgit v1.2.1 From 0dbc66498d9222d91b73d4c0a8a40c96bd3dc296 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 26 Apr 2016 12:22:02 +0300 Subject: Fix for MDEV-9679 main.delayed fails sporadically Problem was that notify_shared_lock() didn't abort an insert delayed thread if it was in thr_upgrade_write_delay_lock(). ALTER TABLE first takes a weak_mdl_lock, then a thr_lock and then tries to upgrade the mdl_lock. Delayed insert thread first takes a mdl lock followed by a thr_upgrade_write_delay_lock() This caused insert delay to wait for alter table in thr_lock, while alter table was waiting for the mdl lock by insert delay. Fixed by telling mdl to run thr_lock_abort() for the insert delay thread table. We also set thd->mysys_var->abort to 1 for the delay thread when it's killed by alter table to ensure it doesn't ever get locked in thr_lock. --- sql/sql_class.cc | 55 ++++++++++++++++++++++++++++++++++++------------------- sql/sql_insert.cc | 30 ++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 21 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 271c44e1948..9cd4258c0df 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1878,38 +1878,55 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, { THD *in_use= ctx_in_use->get_thd(); bool signalled= FALSE; + DBUG_ENTER("THD::notify_shared_lock"); + DBUG_PRINT("enter",("needs_thr_lock_abort: %d", needs_thr_lock_abort)); if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && !in_use->killed) { - in_use->killed= KILL_CONNECTION; - mysql_mutex_lock(&in_use->mysys_var->mutex); - if (in_use->mysys_var->current_cond) - mysql_cond_broadcast(in_use->mysys_var->current_cond); - mysql_mutex_unlock(&in_use->mysys_var->mutex); + /* This code is similar to kill_delayed_threads() */ + DBUG_PRINT("info", ("kill delayed thread")); + mysql_mutex_lock(&in_use->LOCK_thd_data); + if (in_use->killed < KILL_CONNECTION) + in_use->killed= KILL_CONNECTION; + if (in_use->mysys_var) + { + mysql_mutex_lock(&in_use->mysys_var->mutex); + if (in_use->mysys_var->current_cond) + mysql_cond_broadcast(in_use->mysys_var->current_cond); + + /* Abort if about to wait in thr_upgrade_write_delay_lock */ + in_use->mysys_var->abort= 1; + mysql_mutex_unlock(&in_use->mysys_var->mutex); + } + mysql_mutex_unlock(&in_use->LOCK_thd_data); signalled= TRUE; } if (needs_thr_lock_abort) { mysql_mutex_lock(&in_use->LOCK_thd_data); - for (TABLE *thd_table= in_use->open_tables; - thd_table ; - thd_table= thd_table->next) + /* If not already dying */ + if (in_use->killed != KILL_CONNECTION_HARD) { - /* - Check for TABLE::needs_reopen() is needed since in some places we call - handler::close() for table instance (and set TABLE::db_stat to 0) - and do not remove such instances from the THD::open_tables - for some time, during which other thread can see those instances - (e.g. see partitioning code). - */ - if (!thd_table->needs_reopen()) - signalled|= mysql_lock_abort_for_thread(this, thd_table); + for (TABLE *thd_table= in_use->open_tables; + thd_table ; + thd_table= thd_table->next) + { + /* + Check for TABLE::needs_reopen() is needed since in some + places we call handler::close() for table instance (and set + TABLE::db_stat to 0) and do not remove such instances from + the THD::open_tables for some time, during which other + thread can see those instances (e.g. see partitioning code). + */ + if (!thd_table->needs_reopen()) + signalled|= mysql_lock_abort_for_thread(this, thd_table); + } + mysql_mutex_unlock(&in_use->LOCK_thd_data); } - mysql_mutex_unlock(&in_use->LOCK_thd_data); } - return signalled; + DBUG_RETURN(signalled); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b0151182a88..def5560a011 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2620,14 +2620,16 @@ static void end_delayed_insert(THD *thd) void kill_delayed_threads(void) { + DBUG_ENTER("kill_delayed_threads"); mysql_mutex_lock(&LOCK_delayed_insert); // For unlink from list I_List_iterator it(delayed_threads); Delayed_insert *di; while ((di= it++)) { - di->thd.killed= KILL_CONNECTION; mysql_mutex_lock(&di->thd.LOCK_thd_data); + if (di->thd.killed < KILL_CONNECTION) + di->thd.killed= KILL_CONNECTION; if (di->thd.mysys_var) { mysql_mutex_lock(&di->thd.mysys_var->mutex); @@ -2648,6 +2650,7 @@ void kill_delayed_threads(void) mysql_mutex_unlock(&di->thd.LOCK_thd_data); } mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list + DBUG_VOID_RETURN; } @@ -2845,6 +2848,12 @@ pthread_handler_t handle_delayed_insert(void *arg) /* Tell client that the thread is initialized */ mysql_cond_signal(&di->cond_client); + /* + Inform mdl that it needs to call mysql_lock_abort to abort locks + for delayed insert. + */ + thd->mdl_context.set_needs_thr_lock_abort(TRUE); + /* Now wait until we get an insert or lock to handle */ /* We will not abort as long as a client thread uses this thread */ @@ -2853,6 +2862,7 @@ pthread_handler_t handle_delayed_insert(void *arg) if (thd->killed) { uint lock_count; + DBUG_PRINT("delayed", ("Insert delayed killed")); /* Remove this from delay insert list so that no one can request a table from this @@ -2869,6 +2879,9 @@ pthread_handler_t handle_delayed_insert(void *arg) } /* Shouldn't wait if killed or an insert is waiting. */ + DBUG_PRINT("delayed", + ("thd->killed: %d di->status: %d di->stacked_inserts: %d", + thd->killed, di->status, di->stacked_inserts)); if (!thd->killed && !di->status && !di->stacked_inserts) { struct timespec abstime; @@ -2908,6 +2921,9 @@ pthread_handler_t handle_delayed_insert(void *arg) mysql_mutex_unlock(&di->thd.mysys_var->mutex); mysql_mutex_lock(&di->mutex); } + DBUG_PRINT("delayed", + ("thd->killed: %d di->tables_in_use: %d thd->lock: %d", + thd->killed, di->tables_in_use, thd->lock != 0)); if (di->tables_in_use && ! thd->lock && !thd->killed) { @@ -2968,9 +2984,19 @@ pthread_handler_t handle_delayed_insert(void *arg) { DBUG_ENTER("handle_delayed_insert-cleanup"); di->table=0; - thd->killed= KILL_CONNECTION; // If error mysql_mutex_unlock(&di->mutex); + /* + Protect against mdl_locks trying to access open tables + We use KILL_CONNECTION_HARD here to ensure that + THD::notify_shared_lock() dosn't try to access open tables after + this. + */ + mysql_mutex_lock(&thd->LOCK_thd_data); + thd->killed= KILL_CONNECTION_HARD; // If error + thd->mdl_context.set_needs_thr_lock_abort(0); + mysql_mutex_unlock(&thd->LOCK_thd_data); + close_thread_tables(thd); // Free the table thd->mdl_context.release_transactional_locks(); mysql_cond_broadcast(&di->cond_client); // Safety -- cgit v1.2.1 From 29868de2fff62c3ebd8af5cf533d3d224da1b332 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 26 Apr 2016 12:58:14 +0200 Subject: MDEV-9986 Full-text search of the utf8mb4 column causes crash take into account that agg_arg_charsets_for_comparison() can replace Item_field's with Item_func_conv_charset --- sql/item_func.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index bd6553d45d4..cabba7a666c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6366,6 +6366,8 @@ bool Item_func_match::fix_index() for (i=1; i < arg_count; i++) { + if (args[i]->type() != FIELD_ITEM) + goto err; item=(Item_field*)args[i]; for (keynr=0 ; keynr < fts ; keynr++) { -- cgit v1.2.1 From 4f1ad43992d75676687f29da96dd7c4147247a8f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 26 Apr 2016 16:15:15 +0400 Subject: MDEV-9987 - gen_lex_hash leaks memory, making LeakSanitizer builds fail Fixed memory leaks in gen_lex_hash. --- sql/gen_lex_hash.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index c37f4f145cf..3a3273d279b 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -310,6 +310,7 @@ void print_find_structs() add_structs_to_map(root_by_len,max_len); set_links(root_by_len,max_len); print_hash_map("sql_functions_map"); + free(hash_map); hash_map= 0; size_hash_map= 0; @@ -319,6 +320,7 @@ void print_find_structs() add_structs_to_map(root_by_len2,max_len2); set_links(root_by_len2,max_len2); print_hash_map("symbols_map"); + free(hash_map); } -- cgit v1.2.1 From b7ad1ba5d121d4fe4b0655e46076b6e50754b4e9 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 26 Apr 2016 20:11:40 +0300 Subject: Fixed mutex that wasn't properly unlocked (typo in last patch) --- sql/sql_class.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9cd4258c0df..1ee5e4b4113 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1923,8 +1923,8 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (!thd_table->needs_reopen()) signalled|= mysql_lock_abort_for_thread(this, thd_table); } - mysql_mutex_unlock(&in_use->LOCK_thd_data); } + mysql_mutex_unlock(&in_use->LOCK_thd_data); } DBUG_RETURN(signalled); } -- cgit v1.2.1 From 94bad73dd1dd563a3a324dcd519975f6d995dc88 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 28 Apr 2016 21:59:23 +0400 Subject: MDEV-9988 - Insert cast to suppress -Wdynamic-class-memaccess Clang warns on this code because it is memsetting over a vtable contained in a struct in the best_positions array. The diagnostic text is: mariadb/sql/sql_select.cc:24462:10: error: destination for this 'memset' call is a pointer to class containing a dynamic class 'Duplicate_weedout_picker'; vtable pointer will be overwritten [-Werror,-Wdynamic-class-memaccess] memset(best_positions, 0, sizeof(POSITION) * (table_count + 1)); ~~~~~~ ^ Patch contributed by David Gow. --- sql/opt_subselect.cc | 9 +++++---- sql/sql_select.cc | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index de57143e61d..a81b091461f 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2243,7 +2243,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) rows *= join->map2table[tableno]->table->quick_condition_rows; sjm->rows= MY_MIN(sjm->rows, rows); } - memcpy(sjm->positions, join->best_positions + join->const_tables, + memcpy((uchar*) sjm->positions, + (uchar*) (join->best_positions + join->const_tables), sizeof(POSITION) * n_tables); /* @@ -3347,7 +3348,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) SJ_MATERIALIZATION_INFO *sjm= s->emb_sj_nest->sj_mat_info; sjm->is_used= TRUE; sjm->is_sj_scan= FALSE; - memcpy(pos - sjm->tables + 1, sjm->positions, + memcpy((uchar*) (pos - sjm->tables + 1), (uchar*) sjm->positions, sizeof(POSITION) * sjm->tables); recalculate_prefix_record_count(join, tablenr - sjm->tables + 1, tablenr); @@ -3363,8 +3364,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) sjm->is_used= TRUE; sjm->is_sj_scan= TRUE; first= pos->sjmat_picker.sjm_scan_last_inner - sjm->tables + 1; - memcpy(join->best_positions + first, - sjm->positions, sizeof(POSITION) * sjm->tables); + memcpy((uchar*) (join->best_positions + first), + (uchar*) sjm->positions, sizeof(POSITION) * sjm->tables); recalculate_prefix_record_count(join, first, first + sjm->tables); join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN; join->best_positions[first].n_sj_tables= sjm->tables; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f58738a4539..c2b25d812fb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -24672,7 +24672,7 @@ void JOIN::save_query_plan(Join_plan_state *save_to) } memcpy((uchar*) save_to->best_positions, (uchar*) best_positions, sizeof(POSITION) * (table_count + 1)); - memset(best_positions, 0, sizeof(POSITION) * (table_count + 1)); + memset((uchar*) best_positions, 0, sizeof(POSITION) * (table_count + 1)); /* Save SJM nests */ List_iterator it(select_lex->sj_nests); -- cgit v1.2.1 From 9eba34f08675c31b0796eeb127582be827773070 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 28 Apr 2016 22:18:15 +0200 Subject: Fix crash due to heap corruption in main.shm --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 177018dd171..4dfe45683d6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6642,7 +6642,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg) thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */ create_new_thread(thd); connect_number++; - set_current_thd(thd); + set_current_thd(0); continue; errorconn: -- cgit v1.2.1 From ad4239cc3dc7ad5f6f264e1fb3cf6d24084bda90 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 1 May 2016 18:52:13 +0300 Subject: Fixed assert if user table was mailformed. Added mysql_to_mariadb.sql script, to change mysql.user tables from MySQL 5.7 to MariaDB. After this script is run, one can get the other tables fixed by running mysql_upgrade --- sql/sql_acl.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d34f04ceb6f..3b6f8bc9f16 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1263,15 +1263,12 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) } freeze_size(&acl_hosts); - if (init_read_record(&read_record_info, thd, table=tables[USER_TABLE].table, - NULL, 1, 1, FALSE)) - goto end; - table->use_all_columns(); (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0)); (void) my_hash_init2(&acl_roles,50, &my_charset_utf8_bin, 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0, (void (*)(void *))free_acl_role, 0); + table= tables[USER_TABLE].table, username_char_length= MY_MIN(table->field[1]->char_length(), USERNAME_CHAR_LENGTH); password_length= table->field[2]->field_length / @@ -1283,6 +1280,10 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) goto end; } + if (init_read_record(&read_record_info, thd, table, NULL, 1, 1, FALSE)) + goto end; + table->use_all_columns(); + DBUG_PRINT("info",("user table fields: %d, password length: %d", table->s->fields, password_length)); @@ -1294,6 +1295,7 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) mysql_mutex_unlock(&LOCK_global_system_variables); sql_print_error("Fatal error: mysql.user table is in old format, " "but server started with --secure-auth option."); + end_read_record(&read_record_info); goto end; } mysql_user_table_is_in_short_password_format= true; -- cgit v1.2.1 From 94cd0f6c9b3b04db67501ef29d470f32527ceda2 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 2 May 2016 12:58:57 +0400 Subject: MDEV-9898 SET ROLE NONE can crash mysqld. The check_user_can_set_role() used find_user_exact() to get the permissions for the SET ROLE NONE command. Which returned NULL too often, for instance when user authenticated as 'user'@'%'. Now we use find_user_wild() instead. --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3b6f8bc9f16..f323c7871c9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2037,7 +2037,7 @@ static int check_user_can_set_role(const char *user, const char *host, { /* have to clear the privileges */ /* get the current user */ - acl_user= find_user_exact(host, user); + acl_user= find_user_wild(host, user, ip); if (acl_user == NULL) { my_error(ER_INVALID_CURRENT_USER, MYF(0), rolename); -- cgit v1.2.1 From a02d4023db42755b5cb7d0ccb0543fbe94d1b628 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 4 May 2016 11:42:39 +0400 Subject: MDEV-9618 solaris sparc build fails on 10.1. Compiler there is strict about the C/C++ call model mixing in function variable assumptions. Fixed by adding some 'extern "C"' and changing '?' operator with 'if'. --- sql/encryption.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/encryption.cc b/sql/encryption.cc index 209b092b0a4..52aaef896dd 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -23,6 +23,8 @@ static plugin_ref encryption_manager= 0; struct encryption_service_st encryption_handler; +extern "C" { + uint no_key(uint) { return ENCRYPTION_KEY_VERSION_INVALID; @@ -41,6 +43,8 @@ static unsigned int get_length(unsigned int slen, unsigned int key_id, return my_aes_get_size(MY_AES_CBC, slen); } +} /* extern "C" */ + int initialize_encryption_plugin(st_plugin_int *plugin) { if (encryption_manager) @@ -57,9 +61,15 @@ int initialize_encryption_plugin(st_plugin_int *plugin) st_mariadb_encryption *handle= (struct st_mariadb_encryption*) plugin->plugin->info; - encryption_handler.encryption_ctx_size_func= - handle->crypt_ctx_size ? handle->crypt_ctx_size : - (uint (*)(unsigned int, unsigned int))my_aes_ctx_size; + /* + Copmiler on Spark doesn't like the '?' operator here as it + belives the (uint (*)...) implies the C++ call model. + */ + if (handle->crypt_ctx_size) + encryption_handler.encryption_ctx_size_func= handle->crypt_ctx_size; + else + encryption_handler.encryption_ctx_size_func= + (uint (*)(unsigned int, unsigned int))my_aes_ctx_size; encryption_handler.encryption_ctx_init_func= handle->crypt_ctx_init ? handle->crypt_ctx_init : ctx_init; -- cgit v1.2.1 From fba385e3b19149a4ec521d85b9db7717d22e3952 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sun, 21 Feb 2016 22:00:58 +0100 Subject: MDEV-9487: Server crashes in Time_and_counter_tracker::incr_loops with UNION in ALL subquery Do not mark subquery as inexpensive when it is not optimized. --- sql/item_subselect.cc | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index dea58bf8e0c..1812110b1e6 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -561,22 +561,34 @@ bool Item_subselect::is_expensive() for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) { JOIN *cur_join= sl->join; + + /* not optimized subquery */ if (!cur_join) - continue; + return true; + + /* very simple subquery */ + if (!cur_join->tables_list && !sl->first_inner_unit()) + return false; + + /* + If the subquery is not optimised or in the process of optimization + it supposed to be expensive + */ + if (!cur_join->optimized) + return true; /* Subqueries whose result is known after optimization are not expensive. Such subqueries have all tables optimized away, thus have no join plan. */ - if (cur_join->optimized && - (cur_join->zero_result_cause || !cur_join->tables_list)) + if ((cur_join->zero_result_cause || !cur_join->tables_list)) return false; /* If a subquery is not optimized we cannot estimate its cost. A subquery is considered optimized if it has a join plan. */ - if (!(cur_join->optimized && cur_join->join_tab)) + if (!cur_join->join_tab) return true; if (sl->first_inner_unit()) -- cgit v1.2.1 From 4db2ebb1fe8454ea0f2a70d740fc2d9d9b408f0d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 30 Apr 2016 09:09:10 +0200 Subject: MDEV-9940 CREATE ROLE blocked by password validation plugin --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d168529df37..95b90c263ee 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3458,7 +3458,7 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo, } if (!old_row_exists || combo.pwtext.length || combo.pwhash.length) - if (validate_password(&combo)) + if (!handle_as_role && validate_password(&combo)) goto end; /* Update table columns with new privileges */ -- cgit v1.2.1 From bf9404d3a493ba122bc46c0fadf33d8cda9d0d3f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 4 May 2016 16:05:30 +0200 Subject: protect against corrupted frms when reading table options --- sql/create_options.cc | 15 ++++++++++----- sql/create_options.h | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/create_options.cc b/sql/create_options.cc index 66515be05b8..40e4e8b321c 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -685,20 +685,25 @@ uchar *engine_table_options_frm_image(uchar *buff, @returns pointer to byte after last recorded in the buffer */ -uchar *engine_option_value::frm_read(const uchar *buff, engine_option_value **start, +uchar *engine_option_value::frm_read(const uchar *buff, const uchar *buff_end, + engine_option_value **start, engine_option_value **end, MEM_ROOT *root) { LEX_STRING name, value; uint len; +#define need_buff(N) if (buff + (N) >= buff_end) return NULL + need_buff(3); name.length= buff[0]; buff++; + need_buff(name.length + 2); if (!(name.str= strmake_root(root, (const char*)buff, name.length))) return NULL; buff+= name.length; len= uint2korr(buff); value.length= len & ~FRM_QUOTED_VALUE; buff+= 2; + need_buff(value.length); if (!(value.str= strmake_root(root, (const char*)buff, value.length))) return NULL; buff+= value.length; @@ -735,8 +740,8 @@ bool engine_table_options_frm_read(const uchar *buff, uint length, while (buff < buff_end && *buff) { - if (!(buff= engine_option_value::frm_read(buff, &share->option_list, &end, - root))) + if (!(buff= engine_option_value::frm_read(buff, buff_end, + &share->option_list, &end, root))) DBUG_RETURN(TRUE); } buff++; @@ -745,7 +750,7 @@ bool engine_table_options_frm_read(const uchar *buff, uint length, { while (buff < buff_end && *buff) { - if (!(buff= engine_option_value::frm_read(buff, + if (!(buff= engine_option_value::frm_read(buff, buff_end, &share->field[count]->option_list, &end, root))) DBUG_RETURN(TRUE); @@ -757,7 +762,7 @@ bool engine_table_options_frm_read(const uchar *buff, uint length, { while (buff < buff_end && *buff) { - if (!(buff= engine_option_value::frm_read(buff, + if (!(buff= engine_option_value::frm_read(buff, buff_end, &share->key_info[count].option_list, &end, root))) DBUG_RETURN(TRUE); diff --git a/sql/create_options.h b/sql/create_options.h index eb21f291ff4..f7b04f0484f 100644 --- a/sql/create_options.h +++ b/sql/create_options.h @@ -66,7 +66,8 @@ class engine_option_value: public Sql_alloc link(start, end); } } - static uchar *frm_read(const uchar *buff, engine_option_value **start, + static uchar *frm_read(const uchar *buff, const uchar *buff_end, + engine_option_value **start, engine_option_value **end, MEM_ROOT *root); void link(engine_option_value **start, engine_option_value **end); uint frm_length(); -- cgit v1.2.1 From 09464ddec49355a90fdd32abe2daaa1dff8e1106 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 30 Apr 2016 22:50:06 +0200 Subject: small parser cleanup * my_yyabort_error() helper * s/lex->thd/thd/ * remove 'else' after MYSQL_YYABORT (for consistency, 95% of the parser did not use 'else' in this case) * simplify ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE --- sql/share/errmsg-utf8.txt | 2 +- sql/sql_yacc.yy | 1056 +++++++++++++-------------------------------- 2 files changed, 304 insertions(+), 754 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 1bd87e0b393..c05ffb4866a 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6136,7 +6136,7 @@ ER_SLAVE_HEARTBEAT_FAILURE eng "Unexpected master's heartbeat data: %s" ger "Unerwartete Daten vom Heartbeat des Masters: %s" ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE - eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)." + eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%u seconds)." ER_UNUSED_14 eng "You should never see it" ER_CONFLICT_FN_PARSE_ERROR diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 24dc3c44b0f..cc5846b06c9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -99,6 +99,9 @@ int yylex(void *yylval, void *yythd); MYSQL_YYABORT; \ } +#define my_yyabort_error(A) \ + do { my_error A; MYSQL_YYABORT; } while(0) + #ifndef DBUG_OFF #define YYDEBUG 1 #else @@ -2024,10 +2027,8 @@ query: { if (!thd->bootstrap && (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) - { - my_message(ER_EMPTY_QUERY, ER_THD(thd, ER_EMPTY_QUERY), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); + thd->lex->sql_command= SQLCOM_EMPTY_QUERY; YYLIP->found_semicolon= NULL; } @@ -2210,10 +2211,7 @@ help: HELP_SYM { if (Lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HELP"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HELP")); } ident_or_text { @@ -2304,13 +2302,9 @@ master_def: Lex->mi.heartbeat_period= (float) $3->val_real(); if (Lex->mi.heartbeat_period > SLAVE_MAX_HEARTBEAT_PERIOD || Lex->mi.heartbeat_period < 0.0) - { - const char format[]= "%d"; - char buf[4*sizeof(SLAVE_MAX_HEARTBEAT_PERIOD) + sizeof(format)]; - sprintf(buf, format, SLAVE_MAX_HEARTBEAT_PERIOD); - my_error(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), buf); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), + SLAVE_MAX_HEARTBEAT_PERIOD)); + if (Lex->mi.heartbeat_period > slave_net_timeout) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -2418,28 +2412,19 @@ master_file_def: | MASTER_USE_GTID_SYM EQ CURRENT_POS_SYM { if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS; } | MASTER_USE_GTID_SYM EQ SLAVE_POS_SYM { if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS; } | MASTER_USE_GTID_SYM EQ NO_SYM { if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO; } ; @@ -2459,10 +2444,7 @@ connection_name: Lex->mi.connection_name= $1; #ifdef HAVE_REPLICATION if (check_master_connection_name(&$1)) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME")); #endif } ; @@ -2772,10 +2754,7 @@ ev_sql_stmt: - CREATE PROCEDURE ... BEGIN DROP EVENT ... END| */ if (lex->sphead) - { - my_error(ER_EVENT_RECURSION_FORBIDDEN, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0))); if (!make_sp_head(thd, lex->event_parse_data->identifier, TYPE_ENUM_PROCEDURE)) MYSQL_YYABORT; @@ -2814,14 +2793,9 @@ sp_name: ident '.' ident { if (!$1.str || check_db_name(&$1)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (check_routine_name(&$3)) - { MYSQL_YYABORT; - } $$= new (thd->mem_root) sp_name($1, $3, true); if ($$ == NULL) MYSQL_YYABORT; @@ -2837,7 +2811,7 @@ sp_name: } if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; - $$= new (lex->thd->mem_root) sp_name(db, $1, false); + $$= new (thd->mem_root) sp_name(db, $1, false); if ($$ == NULL) MYSQL_YYABORT; $$->init_qname(thd); @@ -2942,10 +2916,7 @@ sp_param_name_and_type: sp_pcontext *spc= lex->spcont; if (spc->find_variable($1, TRUE)) - { - my_error(ER_SP_DUP_PARAM, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_DUP_PARAM, MYF(0), $1.str)); sp_variable *spvar= spc->add_variable(thd, $1); @@ -3015,17 +2986,9 @@ sp_decls: shift/reduce conflicts with the wrong result. (And we get better error handling this way.) */ if (($2.vars || $2.conds) && ($1.curs || $1.hndlrs)) - { /* Variable or condition following cursor or handler */ - my_message(ER_SP_VARCOND_AFTER_CURSHNDLR, - ER_THD(thd, ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_VARCOND_AFTER_CURSHNDLR, MYF(0))); if ($2.curs && $1.hndlrs) - { /* Cursor following handler */ - my_message(ER_SP_CURSOR_AFTER_HANDLER, - ER_THD(thd, ER_SP_CURSOR_AFTER_HANDLER), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_CURSOR_AFTER_HANDLER, MYF(0))); $$.vars= $1.vars + $2.vars; $$.conds= $1.conds + $2.conds; $$.hndlrs= $1.hndlrs + $2.hndlrs; @@ -3092,16 +3055,11 @@ sp_decl: /* The last instruction is responsible for freeing LEX. */ - sp_instr_set *is= (new (lex->thd->mem_root) - sp_instr_set(lex->sphead->instructions(), - pctx, - var_idx, - dflt_value_item, - var_type, - lex, - last)); - if (is == NULL || - lex->sphead->add_instr(is)) + sp_instr_set *is= new (thd->mem_root) + sp_instr_set(lex->sphead->instructions(), + pctx, var_idx, dflt_value_item, + var_type, lex, last); + if (is == NULL || lex->sphead->add_instr(is)) MYSQL_YYABORT; } @@ -3117,10 +3075,7 @@ sp_decl: sp_pcontext *spc= lex->spcont; if (spc->find_condition($2, TRUE)) - { - my_error(ER_SP_DUP_COND, MYF(0), $2.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_DUP_COND, MYF(0), $2.str)); if(spc->add_condition(thd, $2, $5)) MYSQL_YYABORT; $$.vars= $$.hndlrs= $$.curs= 0; @@ -3139,7 +3094,7 @@ sp_decl: sp_pcontext *ctx= lex->spcont; sp_instr_hpush_jump *i= - new (lex->thd->mem_root) sp_instr_hpush_jump(sp->instructions(), + new (thd->mem_root) sp_instr_hpush_jump(sp->instructions(), ctx, h); if (i == NULL || sp->add_instr(i)) @@ -3163,7 +3118,7 @@ sp_decl: if ($2 == sp_handler::CONTINUE) { - i= new (lex->thd->mem_root) + i= new (thd->mem_root) sp_instr_hreturn(sp->instructions(), ctx); if (i == NULL || sp->add_instr(i)) @@ -3171,7 +3126,7 @@ sp_decl: } else { /* EXIT or UNDO handler, just jump to the end of the block */ - i= new (lex->thd->mem_root) + i= new (thd->mem_root) sp_instr_hreturn(sp->instructions(), ctx); if (i == NULL || sp->add_instr(i) || @@ -3194,17 +3149,12 @@ sp_decl: sp_instr_cpush *i; if (ctx->find_cursor($2, &offp, TRUE)) - { - my_error(ER_SP_DUP_CURS, MYF(0), $2.str); - delete $5; - MYSQL_YYABORT; - } - i= new (lex->thd->mem_root) - sp_instr_cpush(sp->instructions(), ctx, $5, - ctx->current_cursor_count()); - if (i == NULL || - sp->add_instr(i) || - ctx->add_cursor($2)) + my_yyabort_error((ER_SP_DUP_CURS, MYF(0), $2.str)); + + i= new (thd->mem_root) + sp_instr_cpush(sp->instructions(), ctx, $5, + ctx->current_cursor_count()); + if (i == NULL || sp->add_instr(i) || ctx->add_cursor($2)) MYSQL_YYABORT; $$.vars= $$.conds= $$.hndlrs= 0; $$.curs= 1; @@ -3222,11 +3172,7 @@ sp_cursor_stmt: DBUG_ASSERT(lex->sql_command == SQLCOM_SELECT); if (lex->result) - { - my_message(ER_SP_BAD_CURSOR_SELECT, ER_THD(thd, ER_SP_BAD_CURSOR_SELECT), - MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BAD_CURSOR_SELECT, MYF(0))); lex->sp_lex_in_use= TRUE; $$= lex; if (lex->sphead->restore_lex(thd)) @@ -3255,17 +3201,10 @@ sp_hcond_element: sp_pcontext *ctx= lex->spcont->parent_context(); if (ctx->check_duplicate_handler($1)) - { - my_message(ER_SP_DUP_HANDLER, ER_THD(thd, ER_SP_DUP_HANDLER), MYF(0)); - MYSQL_YYABORT; - } - else - { - sp_instr_hpush_jump *i= - (sp_instr_hpush_jump *)sp->last_instruction(); + my_yyabort_error((ER_SP_DUP_HANDLER, MYF(0))); - i->add_condition($1); - } + sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction(); + i->add_condition($1); } ; @@ -3273,10 +3212,7 @@ sp_cond: ulong_num { /* mysql errno */ if ($1 == 0) - { - my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_VALUE, MYF(0), "CONDITION", "0")); $$= new (thd->mem_root) sp_condition_value($1); if ($$ == NULL) MYSQL_YYABORT; @@ -3296,10 +3232,7 @@ sqlstate: condition. */ if (!is_sqlstate_valid(&$3) || is_sqlstate_completion($3.str)) - { - my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BAD_SQLSTATE, MYF(0), $3.str)); $$= new (thd->mem_root) sp_condition_value($3.str); if ($$ == NULL) MYSQL_YYABORT; @@ -3320,10 +3253,7 @@ sp_hcond: { $$= Lex->spcont->find_condition($1, false); if ($$ == NULL) - { - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); } | SQLWARNING_SYM /* SQLSTATEs 01??? */ { @@ -3364,23 +3294,15 @@ signal_value: { LEX *lex= Lex; sp_condition_value *cond; + + /* SIGNAL foo cannot be used outside of stored programs */ if (lex->spcont == NULL) - { - /* SIGNAL foo cannot be used outside of stored programs */ - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); cond= lex->spcont->find_condition($1, false); if (cond == NULL) - { - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); if (cond->type != sp_condition_value::SQLSTATE) - { - my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0))); $$= cond; } | sqlstate @@ -3418,11 +3340,8 @@ signal_information_item_list: info= &thd->m_parser_state->m_yacc.m_set_signal_info; int index= (int) $3; if (info->m_item[index] != NULL) - { - my_error(ER_DUP_SIGNAL_SET, MYF(0), - Diag_condition_item_names[index].str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_SIGNAL_SET, MYF(0), + Diag_condition_item_names[index].str)); info->m_item[index]= $5; } ; @@ -3653,10 +3572,7 @@ sp_decl_idents: sp_pcontext *spc= lex->spcont; if (spc->find_variable($1, TRUE)) - { - my_error(ER_SP_DUP_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $1.str)); spc->add_variable(thd, $1); $$= 1; } @@ -3668,10 +3584,7 @@ sp_decl_idents: sp_pcontext *spc= lex->spcont; if (spc->find_variable($3, TRUE)) - { - my_error(ER_SP_DUP_VAR, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $3.str)); spc->add_variable(thd, $3); $$= $1 + 1; } @@ -3729,11 +3642,9 @@ sp_proc_stmt_statement: sp_head *sp= lex->sphead; sp->m_flags|= sp_get_flags_for_command(lex); + /* "USE db" doesn't work in a procedure */ if (lex->sql_command == SQLCOM_CHANGE_DB) - { /* "USE db" doesn't work in a procedure */ - my_error(ER_SP_BADSTATEMENT, MYF(0), "USE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "USE")); /* Don't add an instruction for SET statements, since all instructions for them were already added during processing @@ -3743,7 +3654,7 @@ sp_proc_stmt_statement: lex->var_list.is_empty()); if (lex->sql_command != SQLCOM_SET_OPTION) { - sp_instr_stmt *i=new (lex->thd->mem_root) + sp_instr_stmt *i=new (thd->mem_root) sp_instr_stmt(sp->instructions(), lex->spcont, lex); if (i == NULL) MYSQL_YYABORT; @@ -3777,22 +3688,17 @@ sp_proc_stmt_return: sp_head *sp= lex->sphead; if (sp->m_type != TYPE_ENUM_FUNCTION) - { - my_message(ER_SP_BADRETURN, ER_THD(thd, ER_SP_BADRETURN), MYF(0)); - MYSQL_YYABORT; - } - else - { - sp_instr_freturn *i; + my_yyabort_error((ER_SP_BADRETURN, MYF(0))); + + sp_instr_freturn *i; - i= new (lex->thd->mem_root) + i= new (thd->mem_root) sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_return_field_def.sql_type, lex); - if (i == NULL || - sp->add_instr(i)) - MYSQL_YYABORT; - sp->m_flags|= sp_head::HAS_RETURN; - } + if (i == NULL || sp->add_instr(i)) + MYSQL_YYABORT; + sp->m_flags|= sp_head::HAS_RETURN; + if (sp->restore_lex(thd)) MYSQL_YYABORT; } @@ -3807,49 +3713,44 @@ sp_proc_stmt_leave: sp_label *lab= ctx->find_label($2); if (! lab) + my_yyabort_error((ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str)); + + sp_instr_jump *i; + uint ip= sp->instructions(); + uint n; + /* + When jumping to a BEGIN-END block end, the target jump + points to the block hpop/cpop cleanup instructions, + so we should exclude the block context here. + When jumping to something else (i.e., SP_LAB_ITER), + there are no hpop/cpop at the jump destination, + so we should include the block context here for cleanup. + */ + bool exclusive= (lab->type == sp_label::BEGIN); + + n= ctx->diff_handlers(lab->ctx, exclusive); + if (n) { - my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str); - MYSQL_YYABORT; + sp_instr_hpop *hpop= new (thd->mem_root) + sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); } - else + n= ctx->diff_cursors(lab->ctx, exclusive); + if (n) { - sp_instr_jump *i; - uint ip= sp->instructions(); - uint n; - /* - When jumping to a BEGIN-END block end, the target jump - points to the block hpop/cpop cleanup instructions, - so we should exclude the block context here. - When jumping to something else (i.e., SP_LAB_ITER), - there are no hpop/cpop at the jump destination, - so we should include the block context here for cleanup. - */ - bool exclusive= (lab->type == sp_label::BEGIN); - - n= ctx->diff_handlers(lab->ctx, exclusive); - if (n) - { - sp_instr_hpop *hpop= new (lex->thd->mem_root) - sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL) - MYSQL_YYABORT; - sp->add_instr(hpop); - } - n= ctx->diff_cursors(lab->ctx, exclusive); - if (n) - { - sp_instr_cpop *cpop= new (lex->thd->mem_root) - sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL) - MYSQL_YYABORT; - sp->add_instr(cpop); - } - i= new (lex->thd->mem_root) sp_instr_jump(ip, ctx); - if (i == NULL) + sp_instr_cpop *cpop= new (thd->mem_root) + sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL) MYSQL_YYABORT; - sp->push_backpatch(i, lab); /* Jumping forward */ - sp->add_instr(i); + sp->add_instr(cpop); } + i= new (thd->mem_root) sp_instr_jump(ip, ctx); + if (i == NULL) + MYSQL_YYABORT; + sp->push_backpatch(i, lab); /* Jumping forward */ + sp->add_instr(i); } ; @@ -3862,40 +3763,35 @@ sp_proc_stmt_iterate: sp_label *lab= ctx->find_label($2); if (! lab || lab->type != sp_label::ITERATION) + my_yyabort_error((ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str)); + + sp_instr_jump *i; + uint ip= sp->instructions(); + uint n; + + n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ + if (n) { - my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str); - MYSQL_YYABORT; + sp_instr_hpop *hpop= new (thd->mem_root) + sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL || + sp->add_instr(hpop)) + MYSQL_YYABORT; } - else + n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ + if (n) { - sp_instr_jump *i; - uint ip= sp->instructions(); - uint n; - - n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ - if (n) - { - sp_instr_hpop *hpop= new (lex->thd->mem_root) - sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL || - sp->add_instr(hpop)) - MYSQL_YYABORT; - } - n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ - if (n) - { - sp_instr_cpop *cpop= new (lex->thd->mem_root) - sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL || - sp->add_instr(cpop)) - MYSQL_YYABORT; - } - i= new (lex->thd->mem_root) - sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ - if (i == NULL || - sp->add_instr(i)) + sp_instr_cpop *cpop= new (thd->mem_root) + sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL || + sp->add_instr(cpop)) MYSQL_YYABORT; } + i= new (thd->mem_root) + sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ + if (i == NULL || + sp->add_instr(i)) + MYSQL_YYABORT; } ; @@ -3908,11 +3804,8 @@ sp_proc_stmt_open: sp_instr_copen *i; if (! lex->spcont->find_cursor($2, &offset, false)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str); - MYSQL_YYABORT; - } - i= new (lex->thd->mem_root) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str)); + i= new (thd->mem_root) sp_instr_copen(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) @@ -3929,11 +3822,8 @@ sp_proc_stmt_fetch: sp_instr_cfetch *i; if (! lex->spcont->find_cursor($3, &offset, false)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str); - MYSQL_YYABORT; - } - i= new (lex->thd->mem_root) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $3.str)); + i= new (thd->mem_root) sp_instr_cfetch(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) @@ -3952,11 +3842,8 @@ sp_proc_stmt_close: sp_instr_cclose *i; if (! lex->spcont->find_cursor($2, &offset, false)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str); - MYSQL_YYABORT; - } - i= new (lex->thd->mem_root) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str)); + i= new (thd->mem_root) sp_instr_cclose(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) @@ -3979,17 +3866,11 @@ sp_fetch_list: sp_variable *spv; if (!spc || !(spv = spc->find_variable($1, false))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } - else - { - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); - i->add_to_varlist(spv); - } + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); } | sp_fetch_list ',' ident { @@ -3999,17 +3880,11 @@ sp_fetch_list: sp_variable *spv; if (!spc || !(spv = spc->find_variable($3, false))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str); - MYSQL_YYABORT; - } - else - { - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); - i->add_to_varlist(spv); - } + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); } ; @@ -4021,7 +3896,7 @@ sp_if: sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; uint ip= sp->instructions(); - sp_instr_jump_if_not *i= new (lex->thd->mem_root) + sp_instr_jump_if_not *i= new (thd->mem_root) sp_instr_jump_if_not(ip, ctx, $2, lex); if (i == NULL || sp->push_backpatch(i, ctx->push_label(thd, empty_lex_str, 0)) || @@ -4229,10 +4104,7 @@ sp_labeled_block: sp_label *lab= ctx->find_label($1); if (lab) - { - my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_LABEL_REDEFINE, MYF(0), $1.str)); lex->name= $1; } sp_block_content sp_opt_label @@ -4240,10 +4112,7 @@ sp_labeled_block: if ($6.str) { if (my_strcasecmp(system_charset_info, $6.str, $5->name.str) != 0) - { - my_error(ER_SP_LABEL_MISMATCH, MYF(0), $6.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_LABEL_MISMATCH, MYF(0), $6.str)); } } ; @@ -4297,7 +4166,7 @@ sp_block_content: } if ($2.curs) { - i= new (lex->thd->mem_root) + i= new (thd->mem_root) sp_instr_cpop(sp->instructions(), ctx, $2.curs); if (i == NULL || sp->add_instr(i)) @@ -4314,7 +4183,7 @@ loop_body: LEX *lex= Lex; uint ip= lex->sphead->instructions(); sp_label *lab= lex->spcont->last_label(); /* Jumping back */ - sp_instr_jump *i= new (lex->thd->mem_root) + sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, lex->spcont, lab->ip); if (i == NULL || lex->sphead->add_instr(i)) @@ -4328,7 +4197,7 @@ while_body: LEX *lex= Lex; sp_head *sp= lex->sphead; uint ip= sp->instructions(); - sp_instr_jump_if_not *i= new (lex->thd->mem_root) + sp_instr_jump_if_not *i= new (thd->mem_root) sp_instr_jump_if_not(ip, lex->spcont, $1, lex); if (i == NULL || /* Jumping forward */ @@ -4344,7 +4213,7 @@ while_body: LEX *lex= Lex; uint ip= lex->sphead->instructions(); sp_label *lab= lex->spcont->last_label(); /* Jumping back */ - sp_instr_jump *i= new (lex->thd->mem_root) + sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, lex->spcont, lab->ip); if (i == NULL || lex->sphead->add_instr(i)) @@ -4361,7 +4230,7 @@ repeat_body: LEX *lex= Lex; uint ip= lex->sphead->instructions(); sp_label *lab= lex->spcont->last_label(); /* Jumping back */ - sp_instr_jump_if_not *i= new (lex->thd->mem_root) + sp_instr_jump_if_not *i= new (thd->mem_root) sp_instr_jump_if_not(ip, lex->spcont, $4, lab->ip, lex); if (i == NULL || lex->sphead->add_instr(i)) @@ -4382,10 +4251,7 @@ pop_sp_label: { if (my_strcasecmp(system_charset_info, $1.str, lab->name.str) != 0) - { - my_error(ER_SP_LABEL_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_LABEL_MISMATCH, MYF(0), $1.str)); } } ; @@ -4752,10 +4618,7 @@ opt_ts_nodegroup: { LEX *lex= Lex; if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP")); lex->alter_tablespace_info->nodegroup_id= $3; } ; @@ -4765,10 +4628,7 @@ opt_ts_comment: { LEX *lex= Lex; if (lex->alter_tablespace_info->ts_comment != NULL) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT")); lex->alter_tablespace_info->ts_comment= $3.str; } ; @@ -4778,11 +4638,8 @@ opt_ts_engine: { LEX *lex= Lex; if (lex->alter_tablespace_info->storage_engine != NULL) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0), - "STORAGE ENGINE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE, MYF(0), + "STORAGE ENGINE")); lex->alter_tablespace_info->storage_engine= $4; } ; @@ -4802,10 +4659,7 @@ ts_wait: { LEX *lex= Lex; if (!(lex->alter_tablespace_info->wait_until_completed)) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT")); lex->alter_tablespace_info->wait_until_completed= FALSE; } ; @@ -4837,23 +4691,14 @@ size_number: text_shift_number+=10; break; default: - { - my_error(ER_WRONG_SIZE_NUMBER, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SIZE_NUMBER, MYF(0))); } if (prefix_number >> 31) - { - my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SIZE_OVERFLOW_ERROR, MYF(0))); number= prefix_number << text_shift_number; } else - { - my_error(ER_WRONG_SIZE_NUMBER, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SIZE_NUMBER, MYF(0))); $$= number; } ; @@ -4967,15 +4812,11 @@ have_partitioning: #ifdef WITH_PARTITION_STORAGE_ENGINE LEX_STRING partition_name={C_STRING_WITH_LEN("partition")}; if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), - "--skip-partition"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition")); #else - my_error(ER_FEATURE_DISABLED, MYF(0), "partitioning", - "--with-plugin-partition"); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), "partitioning", + "--with-plugin-partition")); #endif } ; @@ -5068,11 +4909,8 @@ part_field_item: MYSQL_YYABORT; } if (part_info->num_columns > MAX_REF_PARTS) - { - my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), - "list of partition fields"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of partition fields")); } ; @@ -5113,10 +4951,7 @@ opt_num_parts: uint num_parts= $2; partition_info *part_info= Lex->part_info; if (num_parts == 0) - { - my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "partitions")); part_info->num_parts= num_parts; part_info->use_default_num_partitions= FALSE; @@ -5153,11 +4988,8 @@ sub_part_field_item: MYSQL_YYABORT; } if (part_info->subpart_field_list.elements > MAX_REF_PARTS) - { - my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), - "list of subpartition fields"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of subpartition fields")); } ; @@ -5184,10 +5016,7 @@ opt_num_subparts: uint num_parts= $2; LEX *lex= Lex; if (num_parts == 0) - { - my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "subpartitions")); lex->part_info->num_subparts= num_parts; lex->part_info->use_default_num_subpartitions= FALSE; } @@ -5198,17 +5027,11 @@ part_defs: { partition_info *part_info= Lex->part_info; if (part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), - "RANGE"); - MYSQL_YYABORT; - } - else if (part_info->part_type == LIST_PARTITION) - { - my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), - "LIST"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "RANGE")); + if (part_info->part_type == LIST_PARTITION) + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "LIST")); } | '(' part_def_list ')' { @@ -5278,17 +5101,11 @@ opt_part_values: if (! lex->is_partition_management()) { if (part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN")); if (part_info->part_type == LIST_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "LIST", "IN")); } else part_info->part_type= HASH_PARTITION; @@ -5300,11 +5117,8 @@ opt_part_values: if (! lex->is_partition_management()) { if (part_info->part_type != RANGE_PARTITION) - { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN")); } else part_info->part_type= RANGE_PARTITION; @@ -5317,11 +5131,8 @@ opt_part_values: if (! lex->is_partition_management()) { if (part_info->part_type != LIST_PARTITION) - { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN")); } else part_info->part_type= LIST_PARTITION; @@ -5979,10 +5790,7 @@ storage_engines: else { if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION) - { - my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); $$= 0; push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_STORAGE_ENGINE, @@ -5999,10 +5807,7 @@ known_storage_engines: if ((plugin= ha_resolve_by_name(thd, &$1, false))) $$= plugin_hton(plugin); else - { - my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); } ; @@ -6162,10 +5967,7 @@ field_spec: if (check_string_char_length(&$1, 0, NAME_CHAR_LEN, system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TOO_LONG_IDENT, MYF(0), $1.str)); if (!f) MYSQL_YYABORT; @@ -6252,10 +6054,7 @@ parse_vcol_expr: Prevent the end user from invoking this command. */ if (!Lex->parse_vcol_expr) - { - my_message(ER_SYNTAX_ERROR, ER_THD(thd, ER_SYNTAX_ERROR), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SYNTAX_ERROR, MYF(0))); } ; @@ -6287,12 +6086,9 @@ field_type: int err; ulonglong tmp_length= my_strtoll10(Lex->length, NULL, &err); if (err || tmp_length > PRECISION_FOR_DOUBLE) - { - my_error(ER_WRONG_FIELD_SPEC, MYF(0), - Lex->last_field->field_name); - MYSQL_YYABORT; - } - else if (tmp_length > PRECISION_FOR_FLOAT) + my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0), + Lex->last_field->field_name)); + if (tmp_length > PRECISION_FOR_FLOAT) $$= MYSQL_TYPE_DOUBLE; Lex->length= 0; } @@ -6421,9 +6217,8 @@ field_type: Lex->last_field->geom_type= $1; $$=MYSQL_TYPE_GEOMETRY; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } | MEDIUMBLOB @@ -6639,15 +6434,9 @@ attribute: | COLLATE_SYM collation_name { if (Lex->charset && !my_charset_same(Lex->charset,$2)) - { - my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - $2->name,Lex->charset->csname); - MYSQL_YYABORT; - } - else - { - Lex->last_field->charset= $2; - } + my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0), + $2->name,Lex->charset->csname)); + Lex->last_field->charset= $2; } | IDENT_sys equal TEXT_STRING_sys { @@ -6710,10 +6499,7 @@ charset_name: ident_or_text { if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0)))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); } | BINARY { $$= &my_charset_bin; } ; @@ -6733,10 +6519,7 @@ old_or_new_charset_name: { if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))) && !($$=get_old_charset_by_name($1.str))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); } | BINARY { $$= &my_charset_bin; } ; @@ -6775,10 +6558,7 @@ charset_or_alias: | UNICODE_SYM { if (!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0)))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2")); } ; @@ -6994,9 +6774,8 @@ spatial: #ifdef HAVE_SPATIAL $$= Key::SPATIAL; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } ; @@ -7094,10 +6873,7 @@ fulltext_key_opt: if (plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN)) Lex->last_key->key_create_info.parser_name= $3; else - { - my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str)); } ; @@ -7129,9 +6905,7 @@ key_part: { int key_part_len= atoi($3.str); if (!key_part_len) - { - my_error(ER_KEY_PART_0, MYF(0), $1.str); - } + my_yyabort_error((ER_KEY_PART_0, MYF(0), $1.str)); $$= new (thd->mem_root) Key_part_spec($1, (uint) key_part_len); if ($$ == NULL) MYSQL_YYABORT; @@ -7211,10 +6985,7 @@ alter: { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "DATABASE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "DATABASE")); lex->sql_command= SQLCOM_ALTER_DB_UPGRADE; lex->name= $3; } @@ -7223,10 +6994,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_a_chistics @@ -7241,10 +7009,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_a_chistics @@ -7259,10 +7024,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW")); lex->create_view_mode= VIEW_ALTER; } view_tail @@ -7277,10 +7039,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW")); lex->create_view_algorithm= VIEW_ALGORITHM_INHERIT; lex->create_view_mode= VIEW_ALTER; } @@ -7743,10 +7502,7 @@ alter_list_item: } if (check_table_name($3->table.str,$3->table.length, FALSE) || ($3->db.str && check_db_name(&$3->db))) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3->table.str)); lex->name= $3->table; lex->alter_info.flags|= Alter_info::ALTER_RENAME; } @@ -7758,15 +7514,11 @@ alter_list_item: } $5= $5 ? $5 : $4; if (!my_charset_same($4,$5)) - { - my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - $5->name, $4->csname); + my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0), + $5->name, $4->csname)); + if (Lex->create_info.add_alter_list_item_convert_to_charset($5)) MYSQL_YYABORT; - } - LEX *lex= Lex; - if (lex->create_info.add_alter_list_item_convert_to_charset($5)) - MYSQL_YYABORT; - lex->alter_info.flags|= Alter_info::ALTER_CONVERT; + Lex->alter_info.flags|= Alter_info::ALTER_CONVERT; } | create_table_options_space_separated { @@ -7807,10 +7559,7 @@ alter_algorithm_option: | ALGORITHM_SYM opt_equal ident { if (Lex->alter_info.set_requested_algorithm(&$3)) - { - my_error(ER_UNKNOWN_ALTER_ALGORITHM, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_ALTER_ALGORITHM, MYF(0), $3.str)); } ; @@ -7823,10 +7572,7 @@ alter_lock_option: | LOCK_SYM opt_equal ident { if (Lex->alter_info.set_requested_lock(&$3)) - { - my_error(ER_UNKNOWN_ALTER_LOCK, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_ALTER_LOCK, MYF(0), $3.str)); } ; @@ -8002,11 +7748,7 @@ slave_until: (lex->mi.relay_log_name || lex->mi.relay_log_pos)) || !((lex->mi.log_file_name && lex->mi.pos) || (lex->mi.relay_log_name && lex->mi.relay_log_pos))) - { - my_message(ER_BAD_SLAVE_UNTIL_COND, - ER_THD(thd, ER_BAD_SLAVE_UNTIL_COND), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_BAD_SLAVE_UNTIL_COND, MYF(0))); } | UNTIL_SYM MASTER_GTID_POS_SYM EQ TEXT_STRING_sys { @@ -8221,10 +7963,7 @@ check: CHECK_SYM { LEX* lex= thd->lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "CHECK")); DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table(); if (lex->m_sql_cmd == NULL) @@ -8321,9 +8060,9 @@ table_to_table: { LEX *lex=Lex; SELECT_LEX *sl= lex->current_select; - if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING, + if (!sl->add_table_to_list(thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE) || - !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING, + !sl->add_table_to_list(thd, $3,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } @@ -8528,18 +8267,11 @@ select_part2: opt_into opt_select_lock_type { - if ($2 && $10) - { - /* double "INTO" clause */ - my_error(ER_WRONG_USAGE, MYF(0), "INTO", "INTO"); - MYSQL_YYABORT; - } - if ($9 && ($2 || $10)) - { - /* "INTO" with "PROCEDURE ANALYSE" */ - my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "INTO"); - MYSQL_YYABORT; - } + if ($2 && $10) /* double "INTO" clause */ + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "INTO", "INTO")); + + if ($9 && ($2 || $10)) /* "INTO" with "PROCEDURE ANALYSE" */ + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "PROCEDURE", "INTO")); } ; @@ -8596,10 +8328,7 @@ select_options: | select_option_list { if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL) - { - my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT")); } ; @@ -8617,26 +8346,15 @@ select_option: SQL_CACHE wasn't specified, and only once per query. */ if (Lex->current_select != &Lex->select_lex) - { - my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - { - my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else - { - Lex->safe_to_cache_query=0; - Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; - } + my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE")); + + Lex->safe_to_cache_query=0; + Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; + Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; } | SQL_CACHE_SYM { @@ -8645,26 +8363,15 @@ select_option: SQL_NO_CACHE wasn't specified, and only once per query. */ if (Lex->current_select != &Lex->select_lex) - { - my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - { - my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"); - MYSQL_YYABORT; - } - else - { - Lex->safe_to_cache_query=1; - Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; - } + my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE")); + + Lex->safe_to_cache_query=1; + Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; } ; @@ -8717,10 +8424,7 @@ select_item: { if (Lex->sql_command == SQLCOM_CREATE_VIEW && check_column_name($4.str)) - { - my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str)); $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } @@ -9462,11 +9166,7 @@ simple_expr: { Item_splocal *il= $3->get_item_splocal(); if (il) - { - - my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str)); $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(), $3); if ($$ == NULL) @@ -10082,9 +9782,8 @@ function_call_conflict: if ($$ == NULL) MYSQL_YYABORT; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } ; @@ -10246,10 +9945,7 @@ function_call_generic: */ if (!$1.str || check_db_name(&$1)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (check_routine_name(&$3)) { MYSQL_YYABORT; @@ -10473,10 +10169,7 @@ variable: '@' { if (! Lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); } variable_aux { @@ -10543,9 +10236,8 @@ opt_gorder_clause: sel->olap != UNSPECIFIED_OLAP_TYPE && (sel->linkage != UNION_TYPE || sel->braces)) { - my_error(ER_WRONG_USAGE, MYF(0), - "CUBE/ROLLUP", "ORDER BY"); - MYSQL_YYABORT; + my_yyabort_error((ER_WRONG_USAGE, MYF(0), + "CUBE/ROLLUP", "ORDER BY")); } } gorder_list; @@ -10689,7 +10381,7 @@ table_ref: | join_table { LEX *lex= Lex; - if (!($$= lex->current_select->nest_last_join(lex->thd))) + if (!($$= lex->current_select->nest_last_join(thd))) { my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; @@ -10913,7 +10605,7 @@ table_factor: MYSQL_YYABORT; } } - if ($2->init_nested_join(lex->thd)) + if ($2->init_nested_join(thd)) MYSQL_YYABORT; $$= 0; /* incomplete derived tables return NULL, we must be @@ -10962,7 +10654,7 @@ table_factor: Table_ident *ti= new (thd->mem_root) Table_ident(unit); if (ti == NULL) MYSQL_YYABORT; - if (!($$= sel->add_table_to_list(lex->thd, + if (!($$= sel->add_table_to_list(thd, ti, $5, 0, TL_READ, MDL_SHARED_READ))) @@ -11085,17 +10777,15 @@ select_part2_derived: select_derived: get_select_lex { - LEX *lex= Lex; - if ($1->init_nested_join(lex->thd)) + if ($1->init_nested_join(thd)) MYSQL_YYABORT; } derived_table_list { - LEX *lex= Lex; /* for normal joins, $3 != NULL and end_nested_join() != NULL, for derived tables, both must equal NULL */ - if (!($$= $1->end_nested_join(lex->thd)) && $3) + if (!($$= $1->end_nested_join(thd)) && $3) MYSQL_YYABORT; if (!$3 && $$) { @@ -11139,14 +10829,11 @@ select_derived_init: LEX *lex= Lex; if (! lex->parsing_options.allows_derived) - { - my_error(ER_VIEW_SELECT_DERIVED, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_DERIVED, MYF(0))); SELECT_LEX *sel= lex->current_select; TABLE_LIST *embedding; - if (!sel->embedding || sel->end_nested_join(lex->thd)) + if (!sel->embedding || sel->end_nested_join(thd)) { /* we are not in parentheses */ my_parse_error(thd, ER_SYNTAX_ERROR); @@ -11381,14 +11068,11 @@ olap_opt: */ LEX *lex=Lex; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE", - "global union parameters"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE", + "global union parameters")); lex->current_select->olap= CUBE_TYPE; - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE"); - MYSQL_YYABORT; + + my_yyabort_error((ER_NOT_SUPPORTED_YET, MYF(0), "CUBE")); } | WITH_ROLLUP_SYM { @@ -11401,11 +11085,8 @@ olap_opt: */ LEX *lex= Lex; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", - "global union parameters"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", + "global union parameters")); lex->current_select->olap= ROLLUP_TYPE; } ; @@ -11470,7 +11151,7 @@ order_clause: if (!unit->is_union() && (first_sl->order_list.elements || first_sl->select_limit) && - unit->add_fake_select_lex(lex->thd)) + unit->add_fake_select_lex(thd)) MYSQL_YYABORT; } if (sel->master_unit()->is_union() && !sel->braces) @@ -11587,15 +11268,9 @@ limit_option: lex->safe_to_cache_query=0; } else - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); if (splocal->type() != Item::INT_ITEM) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0))); splocal->limit_clause_param= TRUE; $$= splocal; } @@ -11708,16 +11383,10 @@ opt_procedure_clause: LEX *lex=Lex; if (! lex->parsing_options.allows_select_procedure) - { - my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE")); if (&lex->select_lex != lex->current_select) - { - my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery")); lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; @@ -11726,7 +11395,7 @@ opt_procedure_clause: NULL, NULL, $2.str); if (item == NULL) MYSQL_YYABORT; - if (add_proc_to_list(lex->thd, item)) + if (add_proc_to_list(thd, item)) MYSQL_YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); @@ -11811,10 +11480,7 @@ select_outvar: sp_variable *t; if (!Lex->spcont || !(t= Lex->spcont->find_variable($1, false))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); $$ = Lex->result ? (new (thd->mem_root) my_var_sp($1, t->offset, t->type, Lex->sphead)) : @@ -11831,10 +11497,7 @@ into: INTO { if (! Lex->parsing_options.allows_select_into) - { - my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO")); } into_destination ; @@ -11914,7 +11577,7 @@ drop: lex->alter_info.reset(); lex->alter_info.flags= Alter_info::ALTER_DROP_INDEX; lex->alter_info.drop_list.push_back(ad, thd->mem_root); - if (!lex->current_select->add_table_to_list(lex->thd, $6, NULL, + if (!lex->current_select->add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) @@ -11931,17 +11594,11 @@ drop: LEX *lex= thd->lex; sp_name *spname; if ($4.str && check_db_name(&$4)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $4.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $4.str)); if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); lex->set_command(SQLCOM_DROP_FUNCTION, $3); - spname= new (lex->thd->mem_root) sp_name($4, $6, true); + spname= new (thd->mem_root) sp_name($4, $6, true); if (spname == NULL) MYSQL_YYABORT; spname->init_qname(thd); @@ -11953,14 +11610,11 @@ drop: LEX_STRING db= {0, 0}; sp_name *spname; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); if (thd->db && lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; lex->set_command(SQLCOM_DROP_FUNCTION, $3); - spname= new (lex->thd->mem_root) sp_name(db, $4, false); + spname= new (thd->mem_root) sp_name(db, $4, false); if (spname == NULL) MYSQL_YYABORT; spname->init_qname(thd); @@ -11970,10 +11624,7 @@ drop: { LEX *lex=Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); lex->set_command(SQLCOM_DROP_PROCEDURE, $3); lex->spname= $4; } @@ -13005,14 +12656,9 @@ opt_format_json: if (!my_strcasecmp(system_charset_info, $3.str, "JSON")) Lex->explain_json= true; else if (!my_strcasecmp(system_charset_info, $3.str, "TRADITIONAL")) - { DBUG_ASSERT(Lex->explain_json==false); - } else - { - my_error(ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), $3.str)); } ; @@ -13109,10 +12755,7 @@ flush_option: { LEX *lex= Lex; if (lex->type & REFRESH_RELAY_LOG) - { - my_error(ER_WRONG_USAGE, MYF(0), "FLUSH", "RELAY LOGS"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH", "RELAY LOGS")); lex->type|= REFRESH_RELAY_LOG; lex->relay_log_connection_name= lex->mi.connection_name; } @@ -13133,10 +12776,7 @@ flush_option: { LEX *lex= Lex; if (lex->type & REFRESH_SLAVE) - { - my_error(ER_WRONG_USAGE, MYF(0), "FLUSH","SLAVE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH","SLAVE")); lex->type|= REFRESH_SLAVE; lex->reset_slave_info.all= false; } @@ -13615,19 +13255,13 @@ param_marker: Lex_input_stream *lip= YYLIP; Item_param *item; if (! lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); const char *query_start= lex->sphead ? lex->sphead->m_tmp_query : thd->query(); item= new (thd->mem_root) Item_param(thd, lip->get_tok_start() - query_start); if (!($$= item) || lex->param_list.push_back(item, thd->mem_root)) - { - my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_OUT_OF_RESOURCES, MYF(0))); } ; @@ -13825,10 +13459,7 @@ simple_ident: { /* We're compiling a stored procedure and found a variable */ if (! lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); Item_splocal *splocal; splocal= new (thd->mem_root) @@ -13904,17 +13535,11 @@ simple_ident_q: if (lex->trg_chistics.event == TRG_EVENT_INSERT && !new_row) - { - my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT")); if (lex->trg_chistics.event == TRG_EVENT_DELETE && new_row) - { - my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE")); DBUG_ASSERT(!new_row || (lex->trg_chistics.event == TRG_EVENT_INSERT || @@ -14023,26 +13648,17 @@ field_ident: { TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (my_strcasecmp(table_alias_charset, $3.str, table->table_name)) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3.str)); $$=$5; } | ident '.' ident { TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->alias)) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $1.str)); $$=$3; } | '.' ident { $$=$2;} /* For Delphi */ @@ -14678,10 +14294,7 @@ set: { LEX *lex= Lex; if (lex->table_or_sp_used()) - { - my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT")); lex->stmt_var_list= lex->var_list; lex->var_list.empty(); } @@ -15010,10 +14623,7 @@ internal_variable_name: !my_strcasecmp(system_charset_info, $1.str, "OLD"))) { if ($1.str[0]=='O' || $1.str[0]=='o') - { - my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", ""); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "")); if (lex->trg_chistics.event == TRG_EVENT_DELETE) { my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), @@ -15021,10 +14631,7 @@ internal_variable_name: MYSQL_YYABORT; } if (lex->trg_chistics.action_time == TRG_ACTION_AFTER) - { - my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after "); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ")); /* This special combination will denote field of NEW row */ $$.var= trg_new_row_fake_var; $$.base_name= $3; @@ -15116,10 +14723,7 @@ opt_for_user: LEX_STRING pw= { C_STRING_WITH_LEN("password") }; if (spc && spc->find_variable(pw, false)) - { - my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str)); if (!(lex->definer= (LEX_USER*) thd->calloc(sizeof(LEX_USER)))) MYSQL_YYABORT; lex->definer->user= current_user; @@ -15172,10 +14776,7 @@ lock: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK")); lex->sql_command= SQLCOM_LOCK_TABLES; } table_lock_list @@ -15225,10 +14826,7 @@ unlock: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK")); lex->sql_command= SQLCOM_UNLOCK_TABLES; } table_or_tables @@ -15244,34 +14842,25 @@ handler: { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_OPEN; - if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, $4, 0)) MYSQL_YYABORT; } | HANDLER_SYM table_ident_nodb CLOSE_SYM { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_CLOSE; - if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, 0, 0)) MYSQL_YYABORT; } | HANDLER_SYM table_ident_nodb READ_SYM { LEX *lex=Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->expr_allows_subselect= FALSE; lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ @@ -15281,7 +14870,7 @@ handler: lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; lex->limit_rows_examined= 0; - if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, 0, 0)) MYSQL_YYABORT; } handler_read_or_scan opt_where_clause opt_limit_clause @@ -15487,10 +15076,7 @@ grant_role: /* trim end spaces (as they'll be lost in mysql.user anyway) */ $1.length= cs->cset->lengthsp(cs, $1.str, $1.length); if ($1.length == 0) - { - my_error(ER_INVALID_ROLE, MYF(0), ""); - MYSQL_YYABORT; - } + my_yyabort_error((ER_INVALID_ROLE, MYF(0), "")); if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; $$->user = $1; @@ -15585,30 +15171,21 @@ require_list_element: { LEX *lex=Lex; if (lex->x509_subject) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SUBJECT")); lex->x509_subject=$2.str; } | ISSUER_SYM TEXT_STRING { LEX *lex=Lex; if (lex->x509_issuer) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "ISSUER")); lex->x509_issuer=$2.str; } | CIPHER_SYM TEXT_STRING { LEX *lex=Lex; if (lex->ssl_cipher) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CIPHER")); lex->ssl_cipher=$2.str; } ; @@ -15623,11 +15200,7 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | ident '.' '*' { @@ -15636,11 +15209,7 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | '*' '.' '*' { @@ -15649,16 +15218,12 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant= GLOBAL_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | table_ident { LEX *lex=Lex; - if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL, + if (!lex->current_select->add_table_to_list(thd, $1,NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; if (lex->grant == GLOBAL_ACLS) @@ -16339,10 +15904,7 @@ trigger_tail: Lex_input_stream *lip= YYLIP; if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER")); lex->stmt_definition_begin= $2; lex->ident.str= $9; @@ -16399,10 +15961,7 @@ udf_tail2: if (lex->add_create_options_with_check($2)) MYSQL_YYABORT; if (is_native_function(thd, & $3)) - { - my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $3.str)); lex->sql_command= SQLCOM_CREATE_FUNCTION; lex->udf.name= $3; lex->udf.returns= (Item_result) $5; @@ -16425,10 +15984,7 @@ sf_tail: lex->spname= $3; if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION")); if (!make_sp_head(thd, $3, TYPE_ENUM_FUNCTION)) MYSQL_YYABORT; @@ -16472,10 +16028,7 @@ sf_tail: lex->sql_command= SQLCOM_CREATE_SPFUNCTION; sp->set_stmt_end(thd); if (!(sp->m_flags & sp_head::HAS_RETURN)) - { - my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NORETURN, MYF(0), sp->m_qname.str)); if (is_native_function(thd, & sp->m_name)) { /* @@ -16522,10 +16075,7 @@ sp_tail: MYSQL_YYABORT; if (Lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE")); if (!make_sp_head(thd, $3, TYPE_ENUM_PROCEDURE)) MYSQL_YYABORT; -- cgit v1.2.1 From ea195d372bfa8f695ee2189f909c9c22b39df0c4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 1 May 2016 19:33:25 +0200 Subject: MDEV-9949 Connect Engine: long SRCDEF leads to broken table Two bugs here: * the server could create an frm (with a long attribute value) that it could not read back * Connect engine opened files from inside DROP TABLE and was ignoring the error (correctly) but was not hiding it from the server (incorrectly). This caused a crash later when DROP TABLE was finishing successfully while stmt_da already have seen an error. Also added a text case for MDEV-7935 CREATE TABLE ... AS SELECT ... can cause a Server crash (Assertion `0' in Protocol::end_statement) because Connect stopped clearing the error status in stmt_da as a fix for MDEV-7935 --- sql/create_options.h | 3 ++- sql/share/errmsg-utf8.txt | 4 ++-- sql/sql_yacc.yy | 12 ++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/create_options.h b/sql/create_options.h index f7b04f0484f..3e7f9ecfabf 100644 --- a/sql/create_options.h +++ b/sql/create_options.h @@ -23,7 +23,8 @@ #define SQL_CREATE_OPTIONS_INCLUDED #include "sql_class.h" -//#include "handler.h" + +enum { ENGINE_OPTION_MAX_LENGTH=32767 }; class engine_option_value: public Sql_alloc { diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c05ffb4866a..709ac55b28c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6506,8 +6506,8 @@ ER_PARTITION_EXCHANGE_FOREIGN_KEY swe "Tabellen att byta ut mot partition har foreign key referenser: '%-.64s'" ER_NO_SUCH_KEY_VALUE eng "Key value '%-.192s' was not found in table '%-.192s.%-.192s'" -ER_RPL_INFO_DATA_TOO_LONG - eng "Data for column '%s' too long" +ER_VALUE_TOO_LONG + eng "Too long value for '%s'" ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE eng "Replication event checksum verification failed while reading from network." ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cc5846b06c9..e614692bd70 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5730,12 +5730,16 @@ create_table_option: } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, true, &Lex->create_info.option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, false, &Lex->create_info.option_list, &Lex->option_list_last); @@ -6440,12 +6444,16 @@ attribute: } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, true, &Lex->last_field->option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, false, &Lex->last_field->option_list, &Lex->option_list_last); @@ -6834,12 +6842,16 @@ all_key_opt: { Lex->last_key->key_create_info.comment= $2; } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, true, &Lex->option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, false, &Lex->option_list, &Lex->option_list_last); -- cgit v1.2.1 From 5ef0ce4131c9e5ebd2e09907a6a89b6c9d6c5afe Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 3 May 2016 13:07:05 +0200 Subject: comments --- sql/handler.h | 4 ++-- sql/sql_admin.cc | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 4f30ec6d7ec..92a4e81ddcc 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -129,7 +129,7 @@ enum enum_alter_inplace_result { */ #define HA_PRIMARY_KEY_REQUIRED_FOR_POSITION (1ULL << 16) #define HA_CAN_RTREEKEYS (1ULL << 17) -#define HA_NOT_DELETE_WITH_CACHE (1ULL << 18) +#define HA_NOT_DELETE_WITH_CACHE (1ULL << 18) /* unused */ /* The following is we need to a primary key to delete (and update) a row. If there is no primary key, all columns needs to be read on update and delete @@ -143,7 +143,7 @@ enum enum_alter_inplace_result { #define HA_HAS_OLD_CHECKSUM (1ULL << 24) /* Table data are stored in separate files (for lower_case_table_names) */ #define HA_FILE_BASED (1ULL << 26) -#define HA_NO_VARCHAR (1ULL << 27) +#define HA_NO_VARCHAR (1ULL << 27) /* unused */ #define HA_CAN_BIT_FIELD (1ULL << 28) /* supports bit fields */ #define HA_NEED_READ_RANGE_BUFFER (1ULL << 29) /* for read_multi_range */ #define HA_ANY_INDEX_MAY_BE_UNIQUE (1ULL << 30) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index f27cdcc41f2..73f483bbe90 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -622,16 +622,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* Close all instances of the table to allow MyISAM "repair" - to rename files. + (which is internally also used from "optimize") to rename files. @todo: This code does not close all instances of the table. It only closes instances in other connections, but if this connection has LOCK TABLE t1 a READ, t1 b WRITE, both t1 instances will be kept open. There is no need to execute this branch for InnoDB, which does - repair by recreate. There is no need to do it for OPTIMIZE, - which doesn't move files around. - Hence, this code should be moved to prepare_for_repair(), - and executed only for MyISAM engine. + repair by recreate. + Hence, this code should be executed only for MyISAM engine. */ if (lock_type == TL_WRITE && !table->table->s->tmp_table) { -- cgit v1.2.1 From 153259874bfb32c9d1f89a682b96897e32a61986 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 3 May 2016 20:31:02 +0200 Subject: MDEV-9155 Enabling Defragmenting in 10.1.8 still causes OPTIMIZE TABLE to take metadatalocks take MDL_SHARED_WRITE instead of MDL_SHARED_NO_READ_WRITE for OPTIMIZE TABLE. For engines that need a stronger lock (like MyISAM), reopen the table with MDL_SHARED_NO_READ_WRITE. --- sql/handler.h | 9 +++++++++ sql/sql_admin.cc | 33 ++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 92a4e81ddcc..3ffe4d03596 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -248,6 +248,15 @@ enum enum_alter_inplace_result { */ #define HA_CAN_EXPORT (1LL << 45) +/* + Storage engine does not require an exclusive metadata lock + on the table during optimize. (TODO and repair?). + It can allow other connections to open the table. + (it does not necessarily mean that other connections can + read or modify the table - this is defined by THR locks and the + ::store_lock() method). +*/ +#define HA_CONCURRENT_OPTIMIZE (1LL << 46) /* Set of all binlog flags. Currently only contain the capabilities diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 73f483bbe90..b974075b442 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -381,9 +381,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, To allow concurrent execution of read-only operations we acquire weak metadata lock for them. */ - table->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ? - MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ); + table->mdl_request.set_type(lex->sql_command == SQLCOM_REPAIR + ? MDL_SHARED_NO_READ_WRITE + : lock_type >= TL_WRITE_ALLOW_WRITE + ? MDL_SHARED_WRITE : MDL_SHARED_READ); + /* open only one table from local list of command */ + while (1) { TABLE_LIST *save_next_global, *save_next_local; save_next_global= table->next_global; @@ -483,6 +487,20 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, result_code= HA_ADMIN_FAILED; goto send_result; } + + if (!table->table || table->mdl_request.type != MDL_SHARED_WRITE || + table->table->file->ha_table_flags() & HA_CONCURRENT_OPTIMIZE) + break; + + trans_rollback_stmt(thd); + trans_rollback(thd); + close_thread_tables(thd); + table->table= NULL; + thd->mdl_context.release_transactional_locks(); + table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name, + MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION); + } + #ifdef WITH_PARTITION_STORAGE_ENGINE if (table->table) { @@ -521,7 +539,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } } #endif - } DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table)); if (prepare_func) @@ -627,11 +644,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, It only closes instances in other connections, but if this connection has LOCK TABLE t1 a READ, t1 b WRITE, both t1 instances will be kept open. - There is no need to execute this branch for InnoDB, which does - repair by recreate. - Hence, this code should be executed only for MyISAM engine. + + Note that this code is only executed for engines that request + MDL_SHARED_NO_READ_WRITE lock (MDL_SHARED_WRITE cannot be upgraded) + by *not* having HA_CONCURRENT_OPTIMIZE table_flag. */ - if (lock_type == TL_WRITE && !table->table->s->tmp_table) + if (lock_type == TL_WRITE && !table->table->s->tmp_table && + table->mdl_request.type > MDL_SHARED_WRITE) { if (wait_while_table_is_used(thd, table->table, HA_EXTRA_PREPARE_FOR_RENAME)) -- cgit v1.2.1 From a87507eec3081f3a63e527786b1d31e46d79be1c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 5 May 2016 15:39:04 +0400 Subject: MDEV-9712 Performance degradation of nested NULLIF 10.1 introduced a problem: Execution time for various recursive stages (walk, update_used_table, and propagate_equal_fields) in NULLIF is O(recursion_level^2), because complexity is doubled on every recursion level when we copy args[0] to args[2]. This change fixes to avoid unnecessary recursion in: - Item_func_nullif::walk - Item_func_nullif::update_used_tables - Item_func_nullif::propagate_equal_fields when possible. --- sql/item_cmpfunc.cc | 26 +++++++++++++++++++++++++- sql/item_cmpfunc.h | 15 ++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d745dd8ff73..f3196c55873 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2507,6 +2507,23 @@ void Item_func_nullif::split_sum_func(THD *thd, Item **ref_pointer_array, } +bool Item_func_nullif::walk(Item_processor processor, + bool walk_subquery, uchar *arg) +{ + /* + No needs to iterate through args[2] when it's just a copy of args[0]. + See MDEV-9712 Performance degradation of nested NULLIF + */ + uint tmp_count= arg_count == 2 || args[0] == args[2] ? 2 : 3; + for (uint i= 0; i < tmp_count; i++) + { + if (args[i]->walk(processor, walk_subquery, arg)) + return true; + } + return (this->*processor)(arg); +} + + void Item_func_nullif::update_used_tables() { if (m_cache) @@ -2517,7 +2534,14 @@ void Item_func_nullif::update_used_tables() } else { - Item_func::update_used_tables(); + /* + MDEV-9712 Performance degradation of nested NULLIF + No needs to iterate through args[2] when it's just a copy of args[0]. + */ + DBUG_ASSERT(arg_count == 3); + used_tables_and_const_cache_init(); + used_tables_and_const_cache_update_and_join(args[0] == args[2] ? 2 : 3, + args); } } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 39f2cf5590d..2f66382941d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1026,6 +1026,7 @@ public: String *str_op(String *str); my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); + bool walk(Item_processor processor, bool walk_subquery, uchar *arg); uint decimal_precision() const { return args[2]->decimal_precision(); } const char *func_name() const { return "nullif"; } void print(String *str, enum_query_type query_type); @@ -1037,13 +1038,21 @@ public: Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) { Context cmpctx(ANY_SUBST, cmp.compare_type(), cmp.compare_collation()); + const Item *old0= args[0]; args[0]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[0]); args[1]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[1]); - args[2]->propagate_equal_fields_and_change_item_tree(thd, - Context_identity(), - cond, &args[2]); + /* + MDEV-9712 Performance degradation of nested NULLIF + ANY_SUBST is more relaxed than IDENTITY_SUBST. + If ANY_SUBST did not change args[0], + then we can skip propagation for args[2]. + */ + if (old0 != args[0]) + args[2]->propagate_equal_fields_and_change_item_tree(thd, + Context_identity(), + cond, &args[2]); return this; } }; -- cgit v1.2.1 From 9a5c75a07340d6883adeac699ad1a29775698d8f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 29 Apr 2016 09:34:44 -0400 Subject: MDEV-9853: WSREP says it cannot get fake InnoDB transaction ID followed by segmentation fault Ha_trx_info should not be reset in ha_fake_trx_id() as it is later used during commit. --- sql/handler.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 1e6e16171e3..49e451e3836 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6122,7 +6122,6 @@ void ha_fake_trx_id(THD *thd) else hton->fake_trx_id(hton, thd); ha_info_next= ha_info->next(); - ha_info->reset(); /* keep it conveniently zero-filled */ } DBUG_VOID_RETURN; } -- cgit v1.2.1 From 1512078a7a56779d6fdd307a93187b61494de897 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 29 Apr 2016 10:50:39 -0400 Subject: MDEV-9851: CREATE USER w/o IDENTIFIED BY clause causes crash when using cracklib plugin Do not allow NULL password to pass directly to password validation plugin. --- sql/sql_acl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 95b90c263ee..7db7d2cf3fb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -899,7 +899,9 @@ static bool validate_password(LEX_USER *user) { if (user->pwtext.length || !user->pwhash.length) { - struct validation_data data= { &user->user, &user->pwtext }; + struct validation_data data= { &user->user, + user->pwtext.str ? &user->pwtext : + const_cast(&empty_lex_str) }; if (plugin_foreach(NULL, do_validate, MariaDB_PASSWORD_VALIDATION_PLUGIN, &data)) { -- cgit v1.2.1 From 964c4f070a7e96bf45979d8755beb10aa6e6617b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 10 May 2016 19:13:06 +0400 Subject: MDEV-10052 Illegal mix of collations with DAYNAME(date_field)<>varchar_field --- sql/item_timefunc.cc | 6 ++---- sql/sql_locale.h | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 873dcdac4b9..28e93683422 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -935,9 +935,8 @@ void Item_func_monthname::fix_length_and_dec() { THD* thd= current_thd; CHARSET_INFO *cs= thd->variables.collation_connection; - uint32 repertoire= my_charset_repertoire(cs); locale= thd->variables.lc_time_names; - collation.set(cs, DERIVATION_COERCIBLE, repertoire); + collation.set(cs, DERIVATION_COERCIBLE, locale->repertoire()); decimals=0; max_length= locale->max_month_name_length * collation.collation->mbmaxlen; maybe_null=1; @@ -1082,9 +1081,8 @@ void Item_func_dayname::fix_length_and_dec() { THD* thd= current_thd; CHARSET_INFO *cs= thd->variables.collation_connection; - uint32 repertoire= my_charset_repertoire(cs); locale= thd->variables.lc_time_names; - collation.set(cs, DERIVATION_COERCIBLE, repertoire); + collation.set(cs, DERIVATION_COERCIBLE, locale->repertoire()); decimals=0; max_length= locale->max_day_name_length * collation.collation->mbmaxlen; maybe_null=1; diff --git a/sql/sql_locale.h b/sql/sql_locale.h index 8357a9ecba4..8559bb55cd9 100644 --- a/sql/sql_locale.h +++ b/sql/sql_locale.h @@ -61,6 +61,8 @@ public: grouping(grouping_par), errmsgs(errmsgs_par) {} + uint repertoire() const + { return is_ascii ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_EXTENDED; } }; /* Exported variables */ -- cgit v1.2.1 From 5c68bc2c3264fa2c4832c468bad32701dd3d4ed0 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 6 May 2016 12:30:01 +0300 Subject: MDEV-10006: optimizer doesn't convert outer join to inner on views with WHERE clause When simplify_joins() converts an outer join to an inner, it should reset the value of TABLE::dep_tables. This is needed, because the function may have already set TABLE::dep_tables according to the outer join dependency. --- sql/sql_select.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9de597eb0e3..f59a1591296 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14418,6 +14418,8 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top, if (table->outer_join && !table->embedding && table->table) table->table->maybe_null= FALSE; table->outer_join= 0; + if (!(straight_join || table->straight)) + table->dep_tables= table->embedding? table->embedding->dep_tables: 0; if (table->on_expr) { /* Add ON expression to the WHERE or upper-level ON condition. */ -- cgit v1.2.1 From ef3f09f0c9e62ea1bf86b33b5d97e954b3ae34fe Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Fri, 13 May 2016 16:42:45 +0530 Subject: Bug#23251517: SEMISYNC REPLICATION HANGING Revert following bug fix: Bug#20685029: SLAVE IO THREAD SHOULD STOP WHEN DISK IS FULL Bug#21753696: MAKE SHOW SLAVE STATUS NON BLOCKING IF IO THREAD WAITS FOR DISK SPACE This fix results in a deadlock between slave IO thread and SQL thread. (cherry picked from commit e3fea6c6dbb36c6ab21c4ab777224560e9608b53) --- sql/log.cc | 75 ++++--------------------------------------------------- sql/log.h | 5 ++-- sql/slave.cc | 38 +++++++++------------------- sql/slave.h | 2 +- sql/sql_reload.cc | 2 +- 5 files changed, 21 insertions(+), 101 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index a7f05905514..42937ec1682 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -37,7 +37,6 @@ #include "log_event.h" // Query_log_event #include "rpl_filter.h" #include "rpl_rli.h" -#include "rpl_mi.h" #include "sql_audit.h" #include "sql_show.h" @@ -4378,22 +4377,13 @@ end: } -#ifdef HAVE_REPLICATION -bool MYSQL_BIN_LOG::append(Log_event* ev, Master_info *mi) +bool MYSQL_BIN_LOG::append(Log_event* ev) { bool error = 0; - mysql_mutex_assert_owner(&mi->data_lock); mysql_mutex_lock(&LOCK_log); DBUG_ENTER("MYSQL_BIN_LOG::append"); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - /* - Release data_lock by holding LOCK_log, while writing into the relay log. - If slave IO thread waits here for free space, we don't want - SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is - sufficient to block SQL thread when IO thread is updating relay log here. - */ - mysql_mutex_unlock(&mi->data_lock); /* Log_event::write() is smart enough to use my_b_write() or my_b_append() depending on the kind of cache we have. @@ -4408,58 +4398,24 @@ bool MYSQL_BIN_LOG::append(Log_event* ev, Master_info *mi) if (flush_and_sync(0)) goto err; if ((uint) my_b_append_tell(&log_file) > max_size) - { - /* - If rotation is required we must acquire data_lock to protect - description_event from clients executing FLUSH LOGS in parallel. - In order do that we must release the existing LOCK_log so that we - get it once again in proper locking order to avoid dead locks. - i.e data_lock , LOCK_log. - */ - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); error= new_file_without_locking(); - /* - After rotation release data_lock, we need the LOCK_log till we signal - the updation. - */ - mysql_mutex_unlock(&mi->data_lock); - } err: - signal_update(); // Safe as we don't call close mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); + signal_update(); // Safe as we don't call close DBUG_RETURN(error); } -bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) +bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) { bool error= 0; DBUG_ENTER("MYSQL_BIN_LOG::appendv"); va_list(args); va_start(args,len); - mysql_mutex_assert_owner(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - /* - Release data_lock by holding LOCK_log, while writing into the relay log. - If slave IO thread waits here for free space, we don't want - SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is - sufficient to block SQL thread when IO thread is updating relay log here. - */ - mysql_mutex_unlock(&mi->data_lock); - DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space", - { - const char act[]= "disk_full_reached SIGNAL parked"; - DBUG_ASSERT(opt_debug_sync_timeout > 0); - DBUG_ASSERT(!debug_sync_set_action(current_thd, - STRING_WITH_LEN(act))); - };); - + mysql_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(uchar*) buf,len)) @@ -4472,34 +4428,13 @@ bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0)) goto err; - if ((uint) my_b_append_tell(&log_file) > - DBUG_EVALUATE_IF("rotate_slave_debug_group", 500, max_size)) - { - /* - If rotation is required we must acquire data_lock to protect - description_event from clients executing FLUSH LOGS in parallel. - In order do that we must release the existing LOCK_log so that we - get it once again in proper locking order to avoid dead locks. - i.e data_lock , LOCK_log. - */ - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); + if ((uint) my_b_append_tell(&log_file) > max_size) error= new_file_without_locking(); - /* - After rotation release data_lock, we need the LOCK_log till we signal - the updation. - */ - mysql_mutex_unlock(&mi->data_lock); - } err: if (!error) signal_update(); - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); DBUG_RETURN(error); } -#endif bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) { diff --git a/sql/log.h b/sql/log.h index 7d1c3161ac2..4d13e4d0720 100644 --- a/sql/log.h +++ b/sql/log.h @@ -20,7 +20,6 @@ #include "handler.h" /* my_xid */ class Relay_log_info; -class Master_info; class Format_description_log_event; @@ -455,8 +454,8 @@ public: v stands for vector invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0) */ - bool appendv(Master_info* mi, const char* buf,uint len,...); - bool append(Log_event* ev, Master_info* mi); + bool appendv(const char* buf,uint len,...); + bool append(Log_event* ev); void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); diff --git a/sql/slave.cc b/sql/slave.cc index 31037c453d3..acf68e231f3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1660,7 +1660,7 @@ Waiting for the slave SQL thread to free enough relay log space"); #endif if (rli->sql_force_rotate_relay) { - rotate_relay_log(rli->mi, true/*need_data_lock=true*/); + rotate_relay_log(rli->mi); rli->sql_force_rotate_relay= false; } @@ -1705,7 +1705,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi) if (likely((bool)ev)) { ev->server_id= 0; // don't be ignored by slave SQL thread - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), "failed to write a Rotate event" @@ -3605,7 +3605,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) break; Execute_load_log_event xev(thd,0,0); xev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&xev, mi))) + if (unlikely(mi->rli.relay_log.append(&xev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3619,7 +3619,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) { cev->block = net->read_pos; cev->block_len = num_bytes; - if (unlikely(mi->rli.relay_log.append(cev, mi))) + if (unlikely(mi->rli.relay_log.append(cev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3634,7 +3634,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) aev.block = net->read_pos; aev.block_len = num_bytes; aev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&aev, mi))) + if (unlikely(mi->rli.relay_log.append(&aev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3713,7 +3713,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev) Rotate the relay log makes binlog format detection easier (at next slave start or mysqlbinlog) */ - DBUG_RETURN(rotate_relay_log(mi, false/*need_data_lock=false*/)); + DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */); } /* @@ -3819,7 +3819,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf, Log_event::Log_event(const char* buf...) in log_event.cc). */ ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */ - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -3875,7 +3875,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf, inc_pos= event_len; break; } - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -4083,6 +4083,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) direct master (an unsupported, useless setup!). */ + mysql_mutex_lock(log_lock); s_id= uint4korr(buf + SERVER_ID_OFFSET); if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) || /* @@ -4115,7 +4116,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) IGNORE_SERVER_IDS it increments mi->master_log_pos as well as rli->group_relay_log_pos. */ - mysql_mutex_lock(log_lock); if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) || (buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT && buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT && @@ -4127,14 +4127,13 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) rli->ign_master_log_pos_end= mi->master_log_pos; } rli->relay_log.signal_update(); // the slave SQL thread needs to re-check - mysql_mutex_unlock(log_lock); DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored", (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET))); } else { /* write the event to the relay log */ - if (likely(!(rli->relay_log.appendv(mi, buf,event_len,0)))) + if (likely(!(rli->relay_log.appendv(buf,event_len,0)))) { mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); @@ -4144,10 +4143,9 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) { error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; } - mysql_mutex_lock(log_lock); rli->ign_master_log_name_end[0]= 0; // last event is not ignored - mysql_mutex_unlock(log_lock); } + mysql_mutex_unlock(log_lock); skip_relay_logging: @@ -5007,21 +5005,11 @@ err: locks; here we don't, so this function is mainly taking locks). Returns nothing as we cannot catch any error (MYSQL_BIN_LOG::new_file() is void). - - @param mi Master_info for the IO thread. - @param need_data_lock If true, mi->data_lock will be acquired otherwise, - mi->data_lock must be held by the caller. */ -int rotate_relay_log(Master_info* mi, bool need_data_lock) +int rotate_relay_log(Master_info* mi) { DBUG_ENTER("rotate_relay_log"); - if (need_data_lock) - mysql_mutex_lock(&mi->data_lock); - else - { - mysql_mutex_assert_owner(&mi->data_lock); - } Relay_log_info* rli= &mi->rli; int error= 0; @@ -5056,8 +5044,6 @@ int rotate_relay_log(Master_info* mi, bool need_data_lock) */ rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: - if (need_data_lock) - mysql_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); } diff --git a/sql/slave.h b/sql/slave.h index 0cf8adb0315..7bf136694cc 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -205,7 +205,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg); void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); -int rotate_relay_log(Master_info* mi, bool need_data_lock); +int rotate_relay_log(Master_info* mi); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index f24f31b6399..b29cc9a9433 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -157,7 +157,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, { #ifdef HAVE_REPLICATION mysql_mutex_lock(&LOCK_active_mi); - if (rotate_relay_log(active_mi, true/*need_data_lock=true*/)) + if (rotate_relay_log(active_mi)) *write_to_binlog= -1; mysql_mutex_unlock(&LOCK_active_mi); #endif -- cgit v1.2.1 From 99cd5a962c53e35620cdeeca35dfab4ab4b3bb4c Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 23 May 2016 21:15:01 +0300 Subject: MDEV-8989: ORDER BY optimizer ignores equality propagation Variant #4 of the fix. Make ORDER BY optimization functions take into account multiple equalities. This is done in several places: - remove_const() checks whether we can sort the first table in the join, or we need to put rows into temp.table and then sort. - test_if_order_by_key() checks whether there are indexes that can be used to produce the required ordering - make_unireg_sortorder() constructs sort criteria for filesort. --- sql/sql_delete.cc | 2 +- sql/sql_select.cc | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++---- sql/sql_select.h | 4 +- sql/sql_table.cc | 2 +- sql/sql_update.cc | 2 +- 5 files changed, 189 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index f49a053918b..e077073c2df 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -499,7 +499,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, Filesort_tracker *fs_tracker= thd->lex->explain->get_upd_del_plan()->filesort_tracker; - if (!(sortorder= make_unireg_sortorder(thd, order, &length, NULL)) || + if (!(sortorder= make_unireg_sortorder(thd, NULL, 0, order, &length, NULL)) || (table->sort.found_records= filesort(thd, table, sortorder, length, select, HA_POS_ERROR, true, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f59a1591296..a278183d5fd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12327,7 +12327,53 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; } - *simple_order=0; // Must do a temp table to sort + /* + UseMultipleEqualitiesToRemoveTempTable: + Can use multiple-equalities here to check that ORDER BY columns + can be used without tmp. table. + */ + bool can_subst_to_first_table= false; + if (first_is_base_table && + order->item[0]->real_item()->type() == Item::FIELD_ITEM && + join->cond_equal) + { + table_map first_table_bit= + join->join_tab[join->const_tables].table->map; + + Item *item= order->item[0]; + + /* + We are using Context_identity below. This means only do + substitution when equality means + */ + Item *res= item->propagate_equal_fields(join->thd, + Value_source:: + Context_identity(), + join->cond_equal); + if (res != item) + { + /* Substituted to a constant */ + can_subst_to_first_table= true; + } + else + { + Item_equal *item_eq= item->get_item_equal(); + if (item_eq) + { + Item *first= item_eq->get_first(NO_PARTICULAR_TAB, NULL); + if (first->const_item() || first->used_tables() == + first_table_bit) + { + can_subst_to_first_table= true; + } + } + } + } + + if (!can_subst_to_first_table) + { + *simple_order=0; // Must do a temp table to sort + } } } } @@ -20327,6 +20373,8 @@ part_of_refkey(TABLE *table,Field *field) /** Test if one can use the key to resolve ORDER BY. + @param join if not NULL, can use the join's top-level + multiple-equalities. @param order Sort order @param table Table to sort @param idx Index to check @@ -20349,7 +20397,8 @@ part_of_refkey(TABLE *table,Field *field) -1 Reverse key can be used */ -static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, +static int test_if_order_by_key(JOIN *join, + ORDER *order, TABLE *table, uint idx, uint *used_key_parts= NULL) { KEY_PART_INFO *key_part,*key_part_end; @@ -20372,7 +20421,8 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, for (; order ; order=order->next, const_key_parts>>=1) { - Field *field=((Item_field*) (*order->item)->real_item())->field; + Item_field *item_field= ((Item_field*) (*order->item)->real_item()); + Field *field= item_field->field; int flag; /* @@ -20414,6 +20464,17 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, DBUG_RETURN(0); } + if (key_part->field != field) + { + /* + Check if there is a multiple equality that allows to infer that field + and key_part->field are equal + (see also: compute_part_of_sort_key_for_equals) + */ + if (item_field->item_equal && + item_field->item_equal->contains(key_part->field)) + field= key_part->field; + } if (key_part->field != field || !field->part_of_sortkey.is_set(idx)) DBUG_RETURN(0); @@ -20541,7 +20602,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, table->key_info[nr].user_defined_key_parts >= ref_key_parts && is_subkey(table->key_info[nr].key_part, ref_key_part, ref_key_part_end) && - test_if_order_by_key(order, table, nr)) + test_if_order_by_key(NULL, order, table, nr)) { min_length= table->key_info[nr].key_length; best= nr; @@ -20680,6 +20741,68 @@ find_field_in_item_list (Field *field, void *data) } +/* + Fill *col_keys with a union of Field::part_of_sortkey of all fields + that belong to 'table' and are equal to 'item_field'. +*/ + +void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table, + Item_field *item_field, + key_map *col_keys) +{ + col_keys->clear_all(); + col_keys->merge(item_field->field->part_of_sortkey); + + Item_equal *item_eq= NULL; + + if (item_field->item_equal) + { + /* + The item_field is from ORDER structure, but it already has an item_equal + pointer set (UseMultipleEqualitiesToRemoveTempTable code have set it) + */ + item_eq= item_field->item_equal; + } + else + { + /* + Walk through join's muliple equalities and find the one that contains + item_field. + */ + if (!join->cond_equal) + return; + table_map needed_tbl_map= item_field->used_tables() | table->map; + List_iterator li(join->cond_equal->current_level); + Item_equal *cur_item_eq; + while ((cur_item_eq= li++)) + { + if ((cur_item_eq->used_tables() & needed_tbl_map) && + cur_item_eq->contains(item_field->field)) + { + item_eq= cur_item_eq; + item_field->item_equal= item_eq; // Save the pointer to our Item_equal. + break; + } + } + } + + if (item_eq) + { + Item_equal_fields_iterator it(*item_eq); + Item *item; + /* Loop through other members that belong to table table */ + while ((item= it++)) + { + if (item->type() == Item::FIELD_ITEM && + ((Item_field*)item)->field->table == table) + { + col_keys->merge(((Item_field*)item)->field->part_of_sortkey); + } + } + } +} + + /** Test if we can skip the ORDER BY by using an index. @@ -20736,7 +20859,27 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, usable_keys.clear_all(); DBUG_RETURN(0); } - usable_keys.intersect(((Item_field*) item)->field->part_of_sortkey); + + /* + Take multiple-equalities into account. Suppose we have + ORDER BY col1, col10 + and there are + multiple-equal(col1, col2, col3), + multiple-equal(col10, col11). + + Then, + - when item=col1, we find the set of indexes that cover one of {col1, + col2, col3} + - when item=col10, we find the set of indexes that cover one of {col10, + col11} + + And we compute an intersection of these sets to find set of indexes that + cover all ORDER BY components. + */ + key_map col_keys; + compute_part_of_sort_key_for_equals(tab->join, table, (Item_field*)item, + &col_keys); + usable_keys.intersect(col_keys); if (usable_keys.is_clear_all()) goto use_filesort; // No usable keys } @@ -20894,7 +21037,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } /* Check if we get the rows in requested sorted order by using the key */ if (usable_keys.is_set(ref_key) && - (order_direction= test_if_order_by_key(order,table,ref_key, + (order_direction= test_if_order_by_key(tab->join, order,table,ref_key, &used_key_parts))) goto check_reverse_order; } @@ -21274,8 +21417,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, for (ORDER *ord= join->order; ord; ord= ord->next) length++; if (!(join->sortorder= - make_unireg_sortorder(thd, order, &length, join->sortorder))) + make_unireg_sortorder(thd, join, tab->table->map, order, &length, + join->sortorder))) + { goto err; /* purecov: inspected */ + } table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), MYF(MY_WME | MY_ZEROFILL| @@ -21693,7 +21839,9 @@ err: } -SORT_FIELD *make_unireg_sortorder(THD *thd, ORDER *order, uint *length, +SORT_FIELD *make_unireg_sortorder(THD *thd, JOIN *join, + table_map first_table_bit, + ORDER *order, uint *length, SORT_FIELD *sortorder) { uint count; @@ -21713,7 +21861,30 @@ SORT_FIELD *make_unireg_sortorder(THD *thd, ORDER *order, uint *length, for (;order;order=order->next,pos++) { - Item *const item= order->item[0], *const real_item= item->real_item(); + Item *first= order->item[0]; + /* + It is possible that the query plan is to read table t1, while the + sort criteria actually has "ORDER BY t2.col" and the WHERE clause has + a multi-equality(t1.col, t2.col, ...). + The optimizer detects such cases (grep for + UseMultipleEqualitiesToRemoveTempTable to see where), but doesn't + perform equality substitution in the order->item. We need to do the + substitution here ourselves. + */ + table_map item_map= first->used_tables(); + if (join && (item_map & ~join->const_table_map) && + !(item_map & first_table_bit) && join->cond_equal && + first->get_item_equal()) + { + /* + Ok, this is the case descibed just above. Get the first element of the + multi-equality. + */ + Item_equal *item_eq= first->get_item_equal(); + first= item_eq->get_first(NO_PARTICULAR_TAB, NULL); + } + + Item *const item= first, *const real_item= item->real_item(); pos->field= 0; pos->item= 0; if (real_item->type() == Item::FIELD_ITEM) { @@ -25581,7 +25752,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, uint used_key_parts= 0; if (keys.is_set(nr) && - (direction= test_if_order_by_key(order, table, nr, &used_key_parts))) + (direction= test_if_order_by_key(join, order, table, nr, + &used_key_parts))) { /* At this point we are sure that ref_key is a non-ordering @@ -25824,7 +25996,7 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select, } uint used_key_parts; - switch (test_if_order_by_key(order, table, select->quick->index, + switch (test_if_order_by_key(NULL, order, table, select->quick->index, &used_key_parts)) { case 1: // desired order *need_sort= FALSE; diff --git a/sql/sql_select.h b/sql/sql_select.h index 3a0baf03c26..89ee63e87b0 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1821,7 +1821,9 @@ bool error_if_full_join(JOIN *join); int report_error(TABLE *table, int error); int safe_index_read(JOIN_TAB *tab); int get_quick_record(SQL_SELECT *select); -SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length, +SORT_FIELD *make_unireg_sortorder(THD *thd, JOIN *join, + table_map first_table_map, + ORDER *order, uint *length, SORT_FIELD *sortorder); int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 337fb06d4e4..dae3b7ad827 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9472,7 +9472,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (thd->lex->select_lex.setup_ref_array(thd, order_num) || setup_order(thd, thd->lex->select_lex.ref_pointer_array, &tables, fields, all_fields, order) || - !(sortorder= make_unireg_sortorder(thd, order, &length, NULL)) || + !(sortorder= make_unireg_sortorder(thd, NULL, 0, order, &length, NULL)) || (from->sort.found_records= filesort(thd, from, sortorder, length, NULL, HA_POS_ERROR, true, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3c0827bb164..4221025da28 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -567,7 +567,7 @@ int mysql_update(THD *thd, Filesort_tracker *fs_tracker= thd->lex->explain->get_upd_del_plan()->filesort_tracker; - if (!(sortorder=make_unireg_sortorder(thd, order, &length, NULL)) || + if (!(sortorder=make_unireg_sortorder(thd, NULL, 0, order, &length, NULL)) || (table->sort.found_records= filesort(thd, table, sortorder, length, select, limit, true, -- cgit v1.2.1 From b6e826bac2e4d32985e4b90d782dd52d504f0f5b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 24 May 2016 23:15:00 +0200 Subject: MDEV-10118 : do not suggest upgrade from MySQL 5.7 to MariaDB 10.x in the installer. Do not lauch upgrade wizard after installation --- sql/winservice.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/winservice.c b/sql/winservice.c index 1cf9f8d7823..74e9e56acc6 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -81,8 +81,10 @@ void normalize_path(char *path, size_t size) and services. We do not want to mess up with these installations. We will just ignore such services, pretending it is not MySQL. - ´@return - TRUE, if this service should be excluded from UI lists etc (OEM install) + We also exclude MySQL5.7+ since we cannot upgrade it (and it is not an upgrade anyway) + + @return + TRUE, if this service should be excluded from UI lists etc FALSE otherwise. */ BOOL exclude_service(mysqld_service_properties *props) @@ -104,7 +106,12 @@ BOOL exclude_service(mysqld_service_properties *props) if (strstr(buf, exclude_patterns[i])) return TRUE; } - + if ((props->version_major == 0) || + (props->version_major > 5 && props->version_major < 10) || + (props->version_major == 5 && props->version_minor > 6)) + { + return TRUE; + } return FALSE; } -- cgit v1.2.1 From fb35b9ad07f11c8beb24e579f365eca57bbda28a Mon Sep 17 00:00:00 2001 From: pruet Date: Thu, 26 May 2016 16:45:50 +0700 Subject: Multi-level collation in UCA, Thai sorting with contraction for UTF8. --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 38fc58d00d5..75b034cbd4f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3536,7 +3536,7 @@ void Item_func_weight_string::fix_length_and_dec() { uint char_length; char_length= ((cs->state & MY_CS_STRNXFRM_BAD_NWEIGHTS) || !nweights) ? - args[0]->max_char_length() : nweights; + args[0]->max_char_length() : nweights * cs->levels_for_order; max_length= cs->coll->strnxfrmlen(cs, char_length * cs->mbmaxlen); } maybe_null= 1; -- cgit v1.2.1 From a85f6533f13a02a0b0547656a5ff918a1d91d887 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 27 May 2016 15:16:08 +0300 Subject: MDEV-8989: ORDER BY optimizer ignores equality propagation Post-fix: add comments, remove dead-code. --- sql/sql_select.cc | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a278183d5fd..4b535b16d6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12342,30 +12342,26 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, Item *item= order->item[0]; - /* - We are using Context_identity below. This means only do - substitution when equality means + /* + TODO: equality substitution in the context of ORDER BY is + sometimes allowed when it is not allowed in the general case. + + We make the below call for its side effect: it will locate the + multiple equality the item belongs to and set item->item_equal + accordingly. */ Item *res= item->propagate_equal_fields(join->thd, Value_source:: Context_identity(), join->cond_equal); - if (res != item) - { - /* Substituted to a constant */ - can_subst_to_first_table= true; - } - else + Item_equal *item_eq; + if ((item_eq= res->get_item_equal())) { - Item_equal *item_eq= item->get_item_equal(); - if (item_eq) + Item *first= item_eq->get_first(NO_PARTICULAR_TAB, NULL); + if (first->const_item() || first->used_tables() == + first_table_bit) { - Item *first= item_eq->get_first(NO_PARTICULAR_TAB, NULL); - if (first->const_item() || first->used_tables() == - first_table_bit) - { - can_subst_to_first_table= true; - } + can_subst_to_first_table= true; } } } -- cgit v1.2.1 From a8422fa241db4779c68df219e48130b11ececc99 Mon Sep 17 00:00:00 2001 From: iangilfillan Date: Fri, 27 May 2016 18:25:14 +0200 Subject: Update sponsors --- sql/contributors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/contributors.h b/sql/contributors.h index 04f8b74aa65..76674d654e5 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -46,7 +46,7 @@ struct show_table_contributors_st show_table_contributors[]= { /* Smaller sponsors, newer per year */ {"Verkkokauppa.com", "Finland", "Sponsor of the MariaDB Foundation"}, - {"Webyog", "Bangalore", "Sponsor of the MariaDB Foundation"}, + {"Virtuozzo", "https://virtuozzo.com/", "Sponsor of the MariaDB Foundation"}, /* Sponsors of important features */ {"Google", "USA", "Sponsoring encryption, parallel replication and GTID"}, -- cgit v1.2.1 From 016790403a4bb6182094870870ce1a1c3e2756dc Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 31 May 2016 17:59:04 +0300 Subject: MDEV-9764: MariaDB does not limit memory used for range optimization A partial backport of 67f21fb3a077dedfd14b9ca720e926c55e682f93, Bug#22283790: RANGE OPTIMIZER UTILIZES TOO MUCH MEMORY WITH MANY OR CONDITIONS The backported part changes SEL_TREE::keys from being an array of MAX_KEY elements (64*8=512 bytes) to a Mem_root_array (32 bytes + alloc'ed array of as many elements as we need). The patch doesn't fix the "not limiting memory" part, but the memory usage is much lower with it. --- sql/mem_root_array.h | 67 ++++++++++++++++++++++++++++++++++++++++ sql/opt_range.cc | 87 +++++++++++++++++++++++++++++----------------------- 2 files changed, 116 insertions(+), 38 deletions(-) (limited to 'sql') diff --git a/sql/mem_root_array.h b/sql/mem_root_array.h index 2dcc475cd7b..5daeedadcba 100644 --- a/sql/mem_root_array.h +++ b/sql/mem_root_array.h @@ -47,12 +47,21 @@ template class Mem_root_array { public: + /// Convenience typedef, same typedef name as std::vector + typedef Element_type value_type; + Mem_root_array(MEM_ROOT *root) : m_root(root), m_array(NULL), m_size(0), m_capacity(0) { DBUG_ASSERT(m_root != NULL); } + Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val= value_type()) + : m_root(root), m_array(NULL), m_size(0), m_capacity(0) + { + resize(n, val); + } + ~Mem_root_array() { clear(); @@ -70,6 +79,12 @@ public: return m_array[n]; } + Element_type &operator[](size_t n) { return at(n); } + const Element_type &operator[](size_t n) const { return at(n); } + + Element_type &back() { return at(size() - 1); } + const Element_type &back() const { return at(size() - 1); } + // Returns a pointer to the first element in the array. Element_type *begin() { return &m_array[0]; } @@ -155,6 +170,58 @@ public: return false; } + /** + Removes the last element in the array, effectively reducing the + container size by one. This destroys the removed element. + */ + void pop_back() + { + DBUG_ASSERT(!empty()); + if (!has_trivial_destructor) + back().~Element_type(); + m_size-= 1; + } + + /** + Resizes the container so that it contains n elements. + + If n is smaller than the current container size, the content is + reduced to its first n elements, removing those beyond (and + destroying them). + + If n is greater than the current container size, the content is + expanded by inserting at the end as many elements as needed to + reach a size of n. If val is specified, the new elements are + initialized as copies of val, otherwise, they are + value-initialized. + + If n is also greater than the current container capacity, an automatic + reallocation of the allocated storage space takes place. + + Notice that this function changes the actual content of the + container by inserting or erasing elements from it. + */ + void resize(size_t n, const value_type &val= value_type()) + { + if (n == m_size) + return; + if (n > m_size) + { + if (!reserve(n)) + { + while (n != m_size) + push_back(val); + } + return; + } + if (!has_trivial_destructor) + { + while (n != m_size) + pop_back(); + } + m_size= n; + } + size_t capacity() const { return m_capacity; } size_t element_size() const { return sizeof(Element_type); } bool empty() const { return size() == 0; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ea5f77eed1d..0c8166c13f8 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -256,12 +256,19 @@ public: (type == SEL_TREE::IMPOSSIBLE) */ enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type; - SEL_TREE(enum Type type_arg) :type(type_arg) {} - SEL_TREE() :type(KEY) + + SEL_TREE(enum Type type_arg, MEM_ROOT *root, size_t num_keys) + : type(type_arg), keys(root, num_keys), n_ror_scans(0) { keys_map.clear_all(); - bzero((char*) keys,sizeof(keys)); } + + SEL_TREE(MEM_ROOT *root, size_t num_keys) : + type(KEY), keys(root, num_keys), n_ror_scans(0) + { + keys_map.clear_all(); + } + SEL_TREE(SEL_TREE *arg, bool without_merges, RANGE_OPT_PARAM *param); /* Note: there may exist SEL_TREE objects with sel_tree->type=KEY and @@ -269,7 +276,8 @@ public: merit in range analyzer functions (e.g. get_mm_parts) returning a pointer to such SEL_TREE instead of NULL) */ - SEL_ARG *keys[MAX_KEY]; + Mem_root_array keys; + key_map keys_map; /* bitmask of non-NULL elements in keys */ /* @@ -579,7 +587,7 @@ int SEL_IMERGE::and_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree, { SEL_TREE *res_or_tree= 0; SEL_TREE *and_tree= 0; - if (!(res_or_tree= new SEL_TREE()) || + if (!(res_or_tree= new SEL_TREE(param->mem_root, param->keys)) || !(and_tree= new SEL_TREE(tree, TRUE, param))) return (-1); if (!and_range_trees(param, *or_tree, and_tree, res_or_tree)) @@ -788,7 +796,10 @@ int SEL_IMERGE::or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, */ SEL_TREE::SEL_TREE(SEL_TREE *arg, bool without_merges, - RANGE_OPT_PARAM *param): Sql_alloc() + RANGE_OPT_PARAM *param) + : Sql_alloc(), + keys(param->mem_root, param->keys), + n_ror_scans(0) { keys_map= arg->keys_map; type= arg->type; @@ -3020,9 +3031,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) PARAM param; MEM_ROOT alloc; SEL_TREE *tree; - SEL_ARG **key, **end; double rows; - uint idx= 0; init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); @@ -3067,11 +3076,12 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) goto free_alloc; } - for (key= tree->keys, end= key + param.keys; key != end; key++, idx++) + for (uint idx= 0; idx < param.keys; idx++) { - if (*key) + SEL_ARG *key= tree->keys[idx]; + if (key) { - if ((*key)->type == SEL_ARG::IMPOSSIBLE) + if (key->type == SEL_ARG::IMPOSSIBLE) { rows= 0; table->reginfo.impossible_range= 1; @@ -3079,10 +3089,10 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) } else { - rows= records_in_column_ranges(¶m, idx, *key); + rows= records_in_column_ranges(¶m, idx, key); if (rows != HA_POS_ERROR) - (*key)->field->cond_selectivity= rows/table_records; - } + key->field->cond_selectivity= rows/table_records; + } } } @@ -4947,8 +4957,8 @@ TABLE_READ_PLAN *merge_same_index_scans(PARAM *param, SEL_IMERGE *imerge, { SEL_TREE **changed_tree= imerge->trees+(*tree_idx_ptr-1); SEL_ARG *key= (*changed_tree)->keys[key_idx]; - bzero((*changed_tree)->keys, - sizeof((*changed_tree)->keys[0])*param->keys); + for (uint i= 0; i < param->keys; i++) + (*changed_tree)->keys[i]= NULL; (*changed_tree)->keys_map.clear_all(); if (key) key->incr_refs(); @@ -6725,8 +6735,8 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, bool update_tbl_stats, double read_time) { - uint idx; - SEL_ARG **key,**end, **key_to_read= NULL; + uint idx, best_idx; + SEL_ARG *key_to_read= NULL; ha_rows UNINIT_VAR(best_records); /* protected by key_to_read */ uint UNINIT_VAR(best_mrr_flags), /* protected by key_to_read */ UNINIT_VAR(best_buf_size); /* protected by key_to_read */ @@ -6749,9 +6759,10 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, sizeof(INDEX_SCAN_INFO *) * param->keys); } tree->index_scans_end= tree->index_scans; - for (idx= 0,key=tree->keys, end=key+param->keys; key != end; key++,idx++) + for (idx= 0; idx < param->keys; idx++) { - if (*key) + SEL_ARG *key= tree->keys[idx]; + if (key) { ha_rows found_records; Cost_estimate cost; @@ -6759,14 +6770,14 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, uint mrr_flags, buf_size; INDEX_SCAN_INFO *index_scan; uint keynr= param->real_keynr[idx]; - if ((*key)->type == SEL_ARG::MAYBE_KEY || - (*key)->maybe_flag) + if (key->type == SEL_ARG::MAYBE_KEY || + key->maybe_flag) param->needed_reg->set_bit(keynr); bool read_index_only= index_read_must_be_used ? TRUE : (bool) param->table->covering_keys.is_set(keynr); - found_records= check_quick_select(param, idx, read_index_only, *key, + found_records= check_quick_select(param, idx, read_index_only, key, update_tbl_stats, &mrr_flags, &buf_size, &cost); @@ -6780,7 +6791,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, index_scan->used_key_parts= param->max_key_part+1; index_scan->range_count= param->range_count; index_scan->records= found_records; - index_scan->sel_arg= *key; + index_scan->sel_arg= key; *tree->index_scans_end++= index_scan; } if ((found_records != HA_POS_ERROR) && param->is_ror_scan) @@ -6794,6 +6805,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, read_time= found_read_time; best_records= found_records; key_to_read= key; + best_idx= idx; best_mrr_flags= mrr_flags; best_buf_size= buf_size; } @@ -6804,17 +6816,16 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, "ROR scans");); if (key_to_read) { - idx= key_to_read - tree->keys; - if ((read_plan= new (param->mem_root) TRP_RANGE(*key_to_read, idx, + if ((read_plan= new (param->mem_root) TRP_RANGE(key_to_read, best_idx, best_mrr_flags))) { read_plan->records= best_records; - read_plan->is_ror= tree->ror_scans_map.is_set(idx); + read_plan->is_ror= tree->ror_scans_map.is_set(best_idx); read_plan->read_cost= read_time; read_plan->mrr_buf_size= best_buf_size; DBUG_PRINT("info", ("Returning range plan for key %s, cost %g, records %lu", - param->table->key_info[param->real_keynr[idx]].name, + param->table->key_info[param->real_keynr[best_idx]].name, read_plan->read_cost, (ulong) read_plan->records)); } } @@ -7442,9 +7453,11 @@ SEL_TREE *Item::get_mm_tree_for_const(RANGE_OPT_PARAM *param) MEM_ROOT *tmp_root= param->mem_root; param->thd->mem_root= param->old_root; SEL_TREE *tree; - tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) : - new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE); + + const SEL_TREE::Type type= val_int()? SEL_TREE::ALWAYS: SEL_TREE::IMPOSSIBLE; param->thd->mem_root= tmp_root; + + tree= new (tmp_root) SEL_TREE(type, tmp_root, param->keys); DBUG_RETURN(tree); } @@ -7470,7 +7483,8 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) if ((ref_tables & param->current_table) || (ref_tables & ~(param->prev_tables | param->read_tables))) DBUG_RETURN(0); - DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); + DBUG_RETURN(new (param->mem_root) SEL_TREE(SEL_TREE::MAYBE, param->mem_root, + param->keys)); } @@ -7588,7 +7602,8 @@ Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field, if (field->eq(key_part->field)) { SEL_ARG *sel_arg=0; - if (!tree && !(tree=new (param->thd->mem_root) SEL_TREE())) + if (!tree && !(tree=new (param->thd->mem_root) SEL_TREE(param->mem_root, + param->keys))) DBUG_RETURN(0); // OOM if (!value || !(value_used_tables & ~param->read_tables)) { @@ -8551,7 +8566,7 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) imerge[0]= new SEL_IMERGE(tree1->merges.head(), 0, param); } bool no_imerge_from_ranges= FALSE; - if (!(result= new SEL_TREE())) + if (!(result= new (param->mem_root) SEL_TREE(param->mem_root, param->keys))) DBUG_RETURN(result); /* Build the range part of the tree for the formula (1) */ @@ -14382,16 +14397,12 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, const char *msg) { - SEL_ARG **key,**end; - int idx; char buff[1024]; DBUG_ENTER("print_sel_tree"); String tmp(buff,sizeof(buff),&my_charset_bin); tmp.length(0); - for (idx= 0,key=tree->keys, end=key+param->keys ; - key != end ; - key++,idx++) + for (uint idx= 0; idx < param->keys; idx++) { if (tree_map->is_set(idx)) { -- cgit v1.2.1 From 5a5a54f7b4cb03d8d8bf6199baa52bdc2b5350b7 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 1 Jun 2016 23:43:11 +0300 Subject: MDEV-8989: ORDER BY optimizer ignores equality propagation Post-fix #2: - Update test results - Make the optimization conditional under @@optimizer_switch flag. - The optimization is now disabled by default, so .result files are changed back to be what they were before the MDEV-8989 patch. --- sql/sql_priv.h | 2 +- sql/sql_select.cc | 6 +++++- sql/sys_vars.cc | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_priv.h b/sql/sql_priv.h index db7149953f3..def15060978 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -224,7 +224,7 @@ #define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 26) #define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 27) #define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28) -#define OPTIMIZER_SWITCH_USE_CONDITION_SELECTIVITY (1ULL << 29) +#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29) #define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4b535b16d6f..48257265a6a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12333,7 +12333,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, can be used without tmp. table. */ bool can_subst_to_first_table= false; - if (first_is_base_table && + if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_ORDERBY_EQ_PROP) && + first_is_base_table && order->item[0]->real_item()->type() == Item::FIELD_ITEM && join->cond_equal) { @@ -20748,6 +20749,9 @@ void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table, { col_keys->clear_all(); col_keys->merge(item_field->field->part_of_sortkey); + + if (!optimizer_flag(join->thd, OPTIMIZER_SWITCH_ORDERBY_EQ_PROP)) + return; Item_equal *item_eq= NULL; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index e3ff327404f..3b043d92d75 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2391,7 +2391,9 @@ export const char *optimizer_switch_names[]= "table_elimination", "extended_keys", "exists_to_in", - "default", NullS + "orderby_uses_equalities", + "default", + NullS }; static bool fix_optimizer_switch(sys_var *self, THD *thd, enum_var_type type) -- cgit v1.2.1 From 7d3d75895d9d29d52c34dd3559cec59731d8d267 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 2 Jun 2016 19:00:26 +0300 Subject: MDEV-9764: MariaDB does not limit memory used for range optimization Part #2: make tree_or(tree1, tree2) to reuse tree1 for the result object for simple cases. These include key IN (c1, ... cN). The reuse was happening in old MySQL versions, but we stopped doing it in the "fair choice between range and index_merge" patch. --- sql/opt_range.cc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0c8166c13f8..3d059abd666 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8566,14 +8566,30 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) imerge[0]= new SEL_IMERGE(tree1->merges.head(), 0, param); } bool no_imerge_from_ranges= FALSE; - if (!(result= new (param->mem_root) SEL_TREE(param->mem_root, param->keys))) - DBUG_RETURN(result); /* Build the range part of the tree for the formula (1) */ if (sel_trees_can_be_ored(param, tree1, tree2, &ored_keys)) { bool must_be_ored= sel_trees_must_be_ored(param, tree1, tree2, ored_keys); no_imerge_from_ranges= must_be_ored; + + if (no_imerge_from_ranges && no_merges1 && no_merges2) + { + /* + Reuse tree1 as the result in simple cases. This reduces memory usage + for e.g. "key IN (c1, ..., cN)" which produces a lot of ranges. + */ + result= tree1; + } + else + { + if (!(result= new (param->mem_root) SEL_TREE(param->mem_root, + param->keys))) + { + DBUG_RETURN(result); + } + } + key_map::Iterator it(ored_keys); int key_no; while ((key_no= it++) != key_map::Iterator::BITMAP_END) @@ -8590,7 +8606,13 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) } result->type= tree1->type; } - + else + { + if (!result && !(result= new (param->mem_root) SEL_TREE(param->mem_root, + param->keys))) + DBUG_RETURN(result); + } + if (no_imerge_from_ranges && no_merges1 && no_merges2) { if (result->keys_map.is_clear_all()) -- cgit v1.2.1 From 1859caf60b725f81f2ac6091eb44cb848a4a439a Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 3 Jun 2016 14:43:08 +0300 Subject: MDEV-10175: range optimizer calls records_in_range() for full extended keys Make the range optimizer not call records_in_range() when it would not give any benefit. --- sql/opt_range_mrr.cc | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index bff96c7d4cb..729c491a6f1 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -266,12 +266,28 @@ walk_up_n_right: range->end_key.flag= (cur->max_key_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts); - + + KEY *key_info; + if (seq->real_keyno== MAX_KEY) + key_info= NULL; + else + key_info= &seq->param->table->key_info[seq->real_keyno]; + + /* + Conditions below: + (1) - range analysis is used for estimating condition selectivity + (2) - This is a unique key, and we have conditions for all its + user-defined key parts. + (3) - The table uses extended keys, and we have conditions for + all key parts. + */ if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && - (seq->real_keyno == MAX_KEY || - ((uint)key_tree->part+1 == - seq->param->table->key_info[seq->real_keyno].user_defined_key_parts && - (seq->param->table->key_info[seq->real_keyno].flags & HA_NOSAME))) && + (!key_info || // (1) + ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2) + key_info->flags & HA_NOSAME) || // (2) + (seq->param->table->s->use_ext_keys && // (3) + (uint)key_tree->part+1 == key_info->ext_key_parts) // (3) + ) && range->start_key.length == range->end_key.length && !memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length)) range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); -- cgit v1.2.1 From a4848e975d2fe359ff354e767427c01dbe908037 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 8 Jun 2016 19:04:12 +0400 Subject: MDEV-9972 Least function retuns date in date time format --- sql/item_func.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index cabba7a666c..4b5f96cd3e7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2939,12 +2939,13 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) } unpack_time(min_max, ltime); - if (compare_as_dates->field_type() == MYSQL_TYPE_DATE) + enum_field_types ftype= compare_as_dates->field_type(); + if (ftype == MYSQL_TYPE_DATE || ftype == MYSQL_TYPE_NEWDATE) { ltime->time_type= MYSQL_TIMESTAMP_DATE; ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; } - else if (compare_as_dates->field_type() == MYSQL_TYPE_TIME) + else if (ftype == MYSQL_TYPE_TIME) { ltime->time_type= MYSQL_TIMESTAMP_TIME; ltime->hour+= (ltime->month * 32 + ltime->day) * 24; -- cgit v1.2.1 From df1448801ceba4d8d8a02db83ba022fea9e6755d Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 10 Jun 2016 15:50:19 +0400 Subject: MDEV-10181 Illegal mix of collation for a field and an ASCII string as a view field --- sql/field.cc | 1 + sql/field.h | 21 ++++++++++++--------- sql/sql_select.cc | 6 ++++-- 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index ceea0893a3f..a0686fb2f19 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1701,6 +1701,7 @@ Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, if (charset_arg->state & MY_CS_BINSORT) flags|=BINARY_FLAG; field_derivation= DERIVATION_IMPLICIT; + field_repertoire= my_charset_repertoire(charset_arg); } diff --git a/sql/field.h b/sql/field.h index f761aa8d3ea..fdf229edfbb 100644 --- a/sql/field.h +++ b/sql/field.h @@ -580,11 +580,12 @@ public: { return binary() ? &my_charset_bin : charset(); } virtual CHARSET_INFO *sort_charset(void) const { return charset(); } virtual bool has_charset(void) const { return FALSE; } - virtual void set_charset(CHARSET_INFO *charset_arg) { } virtual enum Derivation derivation(void) const { return DERIVATION_IMPLICIT; } virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } - virtual void set_derivation(enum Derivation derivation_arg) { } + virtual void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { } virtual int set_time() { return 1; } void set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code, int cuted_increment); @@ -775,8 +776,10 @@ public: class Field_str :public Field { protected: + // TODO-10.2: Reuse DTCollation instead of these three members CHARSET_INFO *field_charset; enum Derivation field_derivation; + uint field_repertoire; public: Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -799,15 +802,15 @@ public: int store_decimal(const my_decimal *); int store(const char *to,uint length,CHARSET_INFO *cs)=0; uint size_of() const { return sizeof(*this); } - uint repertoire(void) const - { - return my_charset_repertoire(field_charset); - } + uint repertoire(void) const { return field_repertoire; } CHARSET_INFO *charset(void) const { return field_charset; } - void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; } enum Derivation derivation(void) const { return field_derivation; } - virtual void set_derivation(enum Derivation derivation_arg) - { field_derivation= derivation_arg; } + void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { + field_derivation= derivation_arg; + field_repertoire= repertoire_arg; + } bool binary() const { return field_charset == &my_charset_bin; } uint32 max_display_length() { return field_length; } friend class Create_field; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 91aecadfd0a..613cbb2e086 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14586,7 +14586,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, item->collation.collation); else new_field= item->make_string_field(table); - new_field->set_derivation(item->collation.derivation); + new_field->set_derivation(item->collation.derivation, + item->collation.repertoire); break; case DECIMAL_RESULT: new_field= Field_new_decimal::create_from_item(item); @@ -14825,7 +14826,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, modify_item, convert_blob_length); case Item::TYPE_HOLDER: result= ((Item_type_holder *)item)->make_field_by_type(table); - result->set_derivation(item->collation.derivation); + result->set_derivation(item->collation.derivation, + item->collation.repertoire); return result; default: // Dosen't have to be stored return 0; -- cgit v1.2.1 From 4155d0937b98e57a93adbe5b5dc20d06ceda59e7 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 10 Jun 2016 17:06:38 +0400 Subject: MDEV-8402 Bug #77473 Truncated data with subquery & UTF8 --- sql/field.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index fdf229edfbb..f8fc7427618 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1854,10 +1854,9 @@ public: packlength= 4; if (set_packlength) { - uint32 l_char_length= len_arg/cs->mbmaxlen; - packlength= l_char_length <= 255 ? 1 : - l_char_length <= 65535 ? 2 : - l_char_length <= 16777215 ? 3 : 4; + packlength= len_arg <= 255 ? 1 : + len_arg <= 65535 ? 2 : + len_arg <= 16777215 ? 3 : 4; } } Field_blob(uint32 packlength_arg) -- cgit v1.2.1 From 868c2ceb013e06c29ba37d4634f2d543b96539aa Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sun, 12 Jun 2016 19:28:56 -0400 Subject: MDEV-9083: Slave IO thread does not handle autoreconnect to restarting Galera Cluster node Chery-picked commits from codership/mysql-wsrep. MW-284: Slave I/O retry on ER_COM_UNKNOWN_ERROR Slave would treat ER_COM_UNKNOWN_ERROR as fatal error and stop. The fix here is to treat it as a network error and rely on the built-in mechanism to retry. MW-284: Add an MTR test --- sql/slave.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index 4bc4cd4ab83..e9db77a0924 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1361,6 +1361,10 @@ bool is_network_error(uint errorno) errorno == ER_NET_READ_INTERRUPTED || errorno == ER_SERVER_SHUTDOWN) return TRUE; +#ifdef WITH_WSREP + if (errorno == ER_UNKNOWN_COM_ERROR) + return TRUE; +#endif return FALSE; } -- cgit v1.2.1 From 2db724c8d2f3771c1a20b8cf9aaaf913b94aee68 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Mon, 13 Jun 2016 15:54:12 +0400 Subject: MDEV-10218 - rpl.rpl_binlog_errors fails in buildbot with valgrind warnings - bytes are possibly lost Timer thread of threadpool is created "joinable", but they're not "joined" on completion. This causes memory leaks around thread local storage. Fixed by joining timer thread. --- sql/threadpool_unix.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc index df1a05b3ebf..6075c758e40 100644 --- a/sql/threadpool_unix.cc +++ b/sql/threadpool_unix.cc @@ -166,6 +166,7 @@ struct pool_timer_t volatile uint64 next_timeout_check; int tick_interval; bool shutdown; + pthread_t timer_thread_id; }; static pool_timer_t pool_timer; @@ -603,12 +604,12 @@ void check_stall(thread_group_t *thread_group) static void start_timer(pool_timer_t* timer) { - pthread_t thread_id; DBUG_ENTER("start_timer"); mysql_mutex_init(key_timer_mutex,&timer->mutex, NULL); mysql_cond_init(key_timer_cond, &timer->cond, NULL); timer->shutdown = false; - mysql_thread_create(key_timer_thread,&thread_id, NULL, timer_thread, timer); + mysql_thread_create(key_timer_thread, &timer->timer_thread_id, NULL, + timer_thread, timer); DBUG_VOID_RETURN; } @@ -620,6 +621,7 @@ static void stop_timer(pool_timer_t *timer) timer->shutdown = true; mysql_cond_signal(&timer->cond); mysql_mutex_unlock(&timer->mutex); + pthread_join(timer->timer_thread_id, NULL); DBUG_VOID_RETURN; } -- cgit v1.2.1 From c73b987e73343d49c0b98666552d7aeb1a9799da Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 14 Jun 2016 13:18:05 +0200 Subject: MDEV-8328 Evaluation of two "!" operators depends on space in beetween fix the lexer to backtrack when parsing "<=", "<>", "!=", ">=", "<<", ">>", "<=>". --- sql/lex.h | 3 --- sql/sql_lex.cc | 29 ++++++++++++---------- sql/sql_yacc.yy | 77 +++++++++++++++++++++++++++------------------------------ 3 files changed, 53 insertions(+), 56 deletions(-) (limited to 'sql') diff --git a/sql/lex.h b/sql/lex.h index 65411402f6a..aec2ec29dca 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -46,12 +46,9 @@ SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"}; static SYMBOL symbols[] = { { "&&", SYM(AND_AND_SYM)}, - { "<", SYM(LT)}, { "<=", SYM(LE)}, { "<>", SYM(NE)}, { "!=", SYM(NE)}, - { "=", SYM(EQ)}, - { ">", SYM(GT_SYM)}, { ">=", SYM(GE)}, { "<<", SYM(SHIFT_LEFT)}, { ">>", SYM(SHIFT_RIGHT)}, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7b8b37f61fd..ee0e09acbf9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1452,32 +1452,35 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd) return (BIN_NUM); case MY_LEX_CMP_OP: // Incomplete comparison operator + lip->next_state= MY_LEX_START; // Allow signed numbers if (state_map[(uchar) lip->yyPeek()] == MY_LEX_CMP_OP || state_map[(uchar) lip->yyPeek()] == MY_LEX_LONG_CMP_OP) - lip->yySkip(); - if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0))) { - lip->next_state= MY_LEX_START; // Allow signed numbers - return(tokval); + lip->yySkip(); + if ((tokval= find_keyword(lip, 2, 0))) + return(tokval); + lip->yyUnget(); } - state = MY_LEX_CHAR; // Something fishy found - break; + return(c); case MY_LEX_LONG_CMP_OP: // Incomplete comparison operator + lip->next_state= MY_LEX_START; if (state_map[(uchar) lip->yyPeek()] == MY_LEX_CMP_OP || state_map[(uchar) lip->yyPeek()] == MY_LEX_LONG_CMP_OP) { lip->yySkip(); if (state_map[(uchar) lip->yyPeek()] == MY_LEX_CMP_OP) + { lip->yySkip(); + if ((tokval= find_keyword(lip, 3, 0))) + return(tokval); + lip->yyUnget(); + } + if ((tokval= find_keyword(lip, 2, 0))) + return(tokval); + lip->yyUnget(); } - if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0))) - { - lip->next_state= MY_LEX_START; // Found long op - return(tokval); - } - state = MY_LEX_CHAR; // Something fishy found - break; + return(c); case MY_LEX_BOOL: if (c != lip->yyPeek()) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2cb02059ba4..50484e08b3f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -970,7 +970,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ENGINES_SYM %token ENGINE_SYM %token ENUM -%token EQ /* OPERATOR */ %token EQUAL_SYM /* OPERATOR */ %token ERROR_SYM %token ERRORS @@ -1016,7 +1015,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token GRANTS %token GROUP_SYM /* SQL-2003-R */ %token GROUP_CONCAT_SYM -%token GT_SYM /* OPERATOR */ %token HANDLER_SYM %token HARD_SYM %token HASH_SYM @@ -1095,7 +1093,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token LONG_SYM %token LOOP_SYM %token LOW_PRIORITY -%token LT /* OPERATOR */ %token MASTER_CONNECT_RETRY_SYM %token MASTER_HOST_SYM %token MASTER_LOG_FILE_SYM @@ -1439,7 +1436,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %left XOR %left AND_SYM AND_AND_SYM %left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE -%left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM +%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE REGEXP IN_SYM %left '|' %left '&' %left SHIFT_LEFT SHIFT_RIGHT @@ -1922,58 +1919,58 @@ master_defs: ; master_def: - MASTER_HOST_SYM EQ TEXT_STRING_sys + MASTER_HOST_SYM '=' TEXT_STRING_sys { Lex->mi.host = $3.str; } - | MASTER_USER_SYM EQ TEXT_STRING_sys + | MASTER_USER_SYM '=' TEXT_STRING_sys { Lex->mi.user = $3.str; } - | MASTER_PASSWORD_SYM EQ TEXT_STRING_sys + | MASTER_PASSWORD_SYM '=' TEXT_STRING_sys { Lex->mi.password = $3.str; } - | MASTER_PORT_SYM EQ ulong_num + | MASTER_PORT_SYM '=' ulong_num { Lex->mi.port = $3; } - | MASTER_CONNECT_RETRY_SYM EQ ulong_num + | MASTER_CONNECT_RETRY_SYM '=' ulong_num { Lex->mi.connect_retry = $3; } - | MASTER_SSL_SYM EQ ulong_num + | MASTER_SSL_SYM '=' ulong_num { Lex->mi.ssl= $3 ? LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } - | MASTER_SSL_CA_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CA_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_ca= $3.str; } - | MASTER_SSL_CAPATH_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CAPATH_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_capath= $3.str; } - | MASTER_SSL_CERT_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CERT_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_cert= $3.str; } - | MASTER_SSL_CIPHER_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CIPHER_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_cipher= $3.str; } - | MASTER_SSL_KEY_SYM EQ TEXT_STRING_sys + | MASTER_SSL_KEY_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_key= $3.str; } - | MASTER_SSL_VERIFY_SERVER_CERT_SYM EQ ulong_num + | MASTER_SSL_VERIFY_SERVER_CERT_SYM '=' ulong_num { Lex->mi.ssl_verify_server_cert= $3 ? LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } - | MASTER_HEARTBEAT_PERIOD_SYM EQ NUM_literal + | MASTER_HEARTBEAT_PERIOD_SYM '=' NUM_literal { Lex->mi.heartbeat_period= (float) $3->val_real(); if (Lex->mi.heartbeat_period > SLAVE_MAX_HEARTBEAT_PERIOD || @@ -2004,7 +2001,7 @@ master_def: } Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } - | IGNORE_SERVER_IDS_SYM EQ '(' ignore_server_id_list ')' + | IGNORE_SERVER_IDS_SYM '=' '(' ignore_server_id_list ')' { Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } @@ -2025,11 +2022,11 @@ ignore_server_id: } master_file_def: - MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys + MASTER_LOG_FILE_SYM '=' TEXT_STRING_sys { Lex->mi.log_file_name = $3.str; } - | MASTER_LOG_POS_SYM EQ ulonglong_num + | MASTER_LOG_POS_SYM '=' ulonglong_num { Lex->mi.pos = $3; /* @@ -2045,11 +2042,11 @@ master_file_def: */ Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos); } - | RELAY_LOG_FILE_SYM EQ TEXT_STRING_sys + | RELAY_LOG_FILE_SYM '=' TEXT_STRING_sys { Lex->mi.relay_log_name = $3.str; } - | RELAY_LOG_POS_SYM EQ ulong_num + | RELAY_LOG_POS_SYM '=' ulong_num { Lex->mi.relay_log_pos = $3; /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ @@ -3032,7 +3029,7 @@ opt_set_signal_information: ; signal_information_item_list: - signal_condition_information_item_name EQ signal_allowed_expr + signal_condition_information_item_name '=' signal_allowed_expr { Set_signal_information *info; info= &thd->m_parser_state->m_yacc.m_set_signal_info; @@ -3041,7 +3038,7 @@ signal_information_item_list: info->m_item[index]= $3; } | signal_information_item_list ',' - signal_condition_information_item_name EQ signal_allowed_expr + signal_condition_information_item_name '=' signal_allowed_expr { Set_signal_information *info; info= &thd->m_parser_state->m_yacc.m_set_signal_info; @@ -4439,7 +4436,7 @@ opt_linear: opt_key_algo: /* empty */ { Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_NONE;} - | ALGORITHM_SYM EQ real_ulong_num + | ALGORITHM_SYM '=' real_ulong_num { switch ($3) { case 1: @@ -7076,7 +7073,7 @@ opt_place: opt_to: /* empty */ {} | TO_SYM {} - | EQ {} + | '=' {} | AS {} ; @@ -7943,13 +7940,13 @@ bool_pri: if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri comp_op predicate %prec EQ + | bool_pri comp_op predicate %prec '=' { $$= (*$2)(0)->create($1,$3); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri comp_op all_or_any '(' subselect ')' %prec EQ + | bool_pri comp_op all_or_any '(' subselect ')' %prec '=' { $$= all_any_subquery_creator($1, $2, $3, $5); if ($$ == NULL) @@ -8172,11 +8169,11 @@ not2: ; comp_op: - EQ { $$ = &comp_eq_creator; } + '=' { $$ = &comp_eq_creator; } | GE { $$ = &comp_ge_creator; } - | GT_SYM { $$ = &comp_gt_creator; } + | '>' { $$ = &comp_gt_creator; } | LE { $$ = &comp_le_creator; } - | LT { $$ = &comp_lt_creator; } + | '<' { $$ = &comp_lt_creator; } | NE { $$ = &comp_ne_creator; } ; @@ -10197,7 +10194,7 @@ date_time_type: table_alias: /* empty */ | AS - | EQ + | '=' ; opt_table_alias: @@ -11100,7 +11097,7 @@ ident_eq_value: ; equal: - EQ {} + '=' {} | SET_VAR {} ; @@ -13968,11 +13965,11 @@ handler_rkey_function: ; handler_rkey_mode: - EQ { $$=HA_READ_KEY_EXACT; } + '=' { $$=HA_READ_KEY_EXACT; } | GE { $$=HA_READ_KEY_OR_NEXT; } | LE { $$=HA_READ_KEY_OR_PREV; } - | GT_SYM { $$=HA_READ_AFTER_KEY; } - | LT { $$=HA_READ_BEFORE_KEY; } + | '>' { $$=HA_READ_AFTER_KEY; } + | '<' { $$=HA_READ_BEFORE_KEY; } ; /* GRANT / REVOKE */ @@ -14744,7 +14741,7 @@ no_definer: ; definer: - DEFINER_SYM EQ user + DEFINER_SYM '=' user { thd->lex->definer= get_current_user(thd, $3); } @@ -14771,11 +14768,11 @@ view_replace: ; view_algorithm: - ALGORITHM_SYM EQ UNDEFINED_SYM + ALGORITHM_SYM '=' UNDEFINED_SYM { Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; } - | ALGORITHM_SYM EQ MERGE_SYM + | ALGORITHM_SYM '=' MERGE_SYM { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } - | ALGORITHM_SYM EQ TEMPTABLE_SYM + | ALGORITHM_SYM '=' TEMPTABLE_SYM { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } ; -- cgit v1.2.1 From 0e50b924820d365bcc1659eec2cad606f6887597 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 16 Jun 2016 12:35:14 +0400 Subject: MDEV-9969 mysql_install_db error processing ignore_db_dirs. Check for same directories in the list added. --- sql/sql_show.cc | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b8926b986b0..931011dcbc2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -720,12 +720,24 @@ ignore_db_dirs_process_additions() for (i= 0; i < ignore_db_dirs_array.elements; i++) { get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i); - if (my_hash_insert(&ignore_db_dirs_hash, (uchar *) dir)) + if (my_hash_insert(&ignore_db_dirs_hash, (uchar *)dir)) + { + /* ignore duplicates from the config file */ + if (my_hash_search(&ignore_db_dirs_hash, (uchar *)dir->str, dir->length)) + { + sql_print_warning("Duplicate ignore-db-dir directory name '%.*s' " + "found in the config file(s). Ignoring the duplicate.", + (int) dir->length, dir->str); + my_free(dir); + goto continue_loop; + } + return true; + } ptr= strnmov(ptr, dir->str, dir->length); - if (i + 1 < ignore_db_dirs_array.elements) - ptr= strmov(ptr, ","); + *(ptr++)= ','; +continue_loop: /* Set the transferred array element to NULL to avoid double free in case of error. @@ -734,6 +746,12 @@ ignore_db_dirs_process_additions() set_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i); } + if (ptr > opt_ignore_db_dirs) + { + ptr--; + DBUG_ASSERT(*ptr == ','); + } + /* make sure the string is terminated */ DBUG_ASSERT(ptr - opt_ignore_db_dirs <= (ptrdiff_t) len); *ptr= 0; -- cgit v1.2.1 From 70ad689b11bfbd8a30a777f4893a5384628c00e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 20 Jun 2016 09:58:31 +0300 Subject: MDEV-8633: information_schema.index_statistics doesn't delete item when drop table indexes or drop table; Problem was that table and index statistics is removed from persistent tables but not from memory cache. Added functions to remove table and index statistics from memory cache. --- sql/sql_show.cc | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_show.h | 3 +- sql/sql_statistics.cc | 9 +++++ 3 files changed, 105 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 931011dcbc2..97f6b863058 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3460,6 +3460,100 @@ int fill_schema_table_stats(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_RETURN(0); } +/* Remove all indexes for a given table from global index statistics */ + +static +int del_global_index_stats_for_table(THD *thd, uchar* cache_key, uint cache_key_length) +{ + int res = 0; + DBUG_ENTER("del_global_index_stats_for_table"); + + mysql_mutex_lock(&LOCK_global_index_stats); + + for (uint i= 0; i < global_index_stats.records;) + { + INDEX_STATS *index_stats = + (INDEX_STATS*) my_hash_element(&global_index_stats, i); + + /* We search correct db\0table_name\0 string */ + if (index_stats && + index_stats->index_name_length >= cache_key_length && + !memcmp(index_stats->index, cache_key, cache_key_length)) + { + res= my_hash_delete(&global_index_stats, (uchar*)index_stats); + /* + In our HASH implementation on deletion one elements + is moved into a place where a deleted element was, + and the last element is moved into the empty space. + Thus we need to re-examine the current element, but + we don't have to restart the search from the beginning. + */ + } + else + i++; + } + + mysql_mutex_unlock(&LOCK_global_index_stats); + DBUG_RETURN(res); +} + +/* Remove a table from global table statistics */ + +int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table) +{ + TABLE_STATS *table_stats; + int res = 0; + uchar *cache_key; + uint cache_key_length; + DBUG_ENTER("del_global_table_stat"); + + cache_key_length= db->length + 1 + table->length + 1; + + if(!(cache_key= (uchar *)my_malloc(cache_key_length, + MYF(MY_WME | MY_ZEROFILL)))) + { + /* Out of memory error already given */ + res = 1; + goto end; + } + + memcpy(cache_key, db->str, db->length); + memcpy(cache_key + db->length + 1, table->str, table->length); + + res= del_global_index_stats_for_table(thd, cache_key, cache_key_length); + + mysql_mutex_lock(&LOCK_global_table_stats); + + if((table_stats= (TABLE_STATS*) my_hash_search(&global_table_stats, + cache_key, + cache_key_length))) + res= my_hash_delete(&global_table_stats, (uchar*)table_stats); + + my_free(cache_key); + mysql_mutex_unlock(&LOCK_global_table_stats); + +end: + DBUG_RETURN(res); +} + +/* Remove a index from global index statistics */ + +int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) +{ + INDEX_STATS *index_stats; + uint key_length= table->s->table_cache_key.length + key_info->name_length + 1; + int res = 0; + DBUG_ENTER("del_global_index_stat"); + mysql_mutex_lock(&LOCK_global_index_stats); + + if((index_stats= (INDEX_STATS*) my_hash_search(&global_index_stats, + key_info->cache_name, + key_length))) + res= my_hash_delete(&global_index_stats, (uchar*)index_stats); + + mysql_mutex_unlock(&LOCK_global_index_stats); + DBUG_RETURN(res); +} /* Fill information schema table with index statistics */ diff --git a/sql/sql_show.h b/sql/sql_show.h index 84064ae0a05..9ca60557cc0 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -113,7 +113,8 @@ void view_store_options(THD *thd, TABLE_LIST *table, String *buff); void init_fill_schema_files_row(TABLE* table); bool schema_table_store_record(THD *thd, TABLE *table); void initialize_information_schema_acl(); - +int del_global_index_stat(THD *thd, TABLE* tab, KEY* key_info); +int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table); ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name); ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx); int make_schema_select(THD *thd, SELECT_LEX *sel, diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index e86c84040b4..47a5a40ebeb 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -29,6 +29,7 @@ #include "sql_statistics.h" #include "opt_range.h" #include "my_atomic.h" +#include "sql_show.h" /* The system variable 'use_stat_tables' can take one of the @@ -3193,6 +3194,10 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab) rc= 1; } + err= del_global_table_stat(thd, db, tab); + if (err & !rc) + rc= 1; + thd->restore_stmt_binlog_format(save_binlog_format); close_system_tables(thd, &open_tables_backup); @@ -3339,6 +3344,10 @@ int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info, } } + err= del_global_index_stat(thd, tab, key_info); + if (err && !rc) + rc= 1; + thd->restore_stmt_binlog_format(save_binlog_format); close_system_tables(thd, &open_tables_backup); -- cgit v1.2.1 From a80dbe068ca650ef1f4daee2263f0bc6e7aeb0e1 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 20 Jun 2016 14:11:01 +0400 Subject: MDEV-10020 InnoDB NOT IN Query Crash When One Item Is NULL The problem was that the loop in get_func_mm_tree() accessed improperly initialized instances of String, which resided in the bzero'ed part of the in_vector::base array. Strings in in_vector::base are originally initialized in Item_func_in::fix_length_and_dec(), in in_vector::in_vector() using sql_calloc, rather than using a String constructor, so their str_charset members are originally equal to NULL. Strings in in_vector::base are later initialized to good values in Item_func_in::fix_length_and_dec(), using array->set(), in this code: uint j=0; for (uint i=1 ; i < arg_count ; i++) { array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values j++; else have_null= 1; } if ((array->used_count= j)) array->sort(); NULLs are not taken into account, so at the end array->used_count can be smaller than array->count. This patch fixes the loop in opt_range.cc, in get_func_mm_tree(), to access only properly initialized elements in in_vector::base, preventing access to its bzero'ed non-initialized tail. --- sql/opt_range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f051ed07a7e..ae5899d8de4 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7730,7 +7730,7 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, break; } SEL_TREE *tree2; - for (; i < func->array->count; i++) + for (; i < func->array->used_count; i++) { if (func->array->compare_elems(i, i-1)) { -- cgit v1.2.1 From 7f38a070baa503a37af186ff24f39606816f55ec Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 17 Jun 2016 18:54:11 +0400 Subject: MDEV-10043 - main.events_restart fails sporadically in buildbot (crashes upon shutdown) There was race condition between shutdown thread and event worker threads. Shutdown thread waits for thread_count to become 0 in close_connections(). It may happen so that event worker thread was started but didn't increment thread_count by this time. In this case shutdown thread may miss wait for this working thread and continue deinitialization. Worker thread in turn may continue execution and crash on deinitialized data. Fixed by incrementing thread_count before thread is actually created like it is done for connection threads. Also let event scheduler not to inc/dec running threads counter for symmetry with other "service" threads. --- sql/event_scheduler.cc | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index beb3c864662..a5a3f7110b3 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -131,12 +131,6 @@ post_init_event_thread(THD *thd) thd->cleanup(); return TRUE; } - - mysql_mutex_lock(&LOCK_thread_count); - threads.append(thd); - thread_count++; - inc_thread_running(); - mysql_mutex_unlock(&LOCK_thread_count); return FALSE; } @@ -158,7 +152,6 @@ deinit_event_thread(THD *thd) DBUG_PRINT("exit", ("Event thread finishing")); mysql_mutex_lock(&LOCK_thread_count); thread_count--; - dec_thread_running(); delete thd; mysql_cond_broadcast(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); @@ -195,6 +188,8 @@ pre_init_event_thread(THD* thd) thd->client_capabilities|= CLIENT_MULTI_RESULTS; mysql_mutex_lock(&LOCK_thread_count); thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + threads.append(thd); + thread_count++; mysql_mutex_unlock(&LOCK_thread_count); /* @@ -241,13 +236,8 @@ event_scheduler_thread(void *arg) my_free(arg); if (!res) scheduler->run(thd); - else - { - thd->proc_info= "Clearing"; - net_end(&thd->net); - delete thd; - } + deinit_event_thread(thd); DBUG_LEAVE; // Against gcc warnings my_thread_end(); return 0; @@ -308,6 +298,7 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) DBUG_ENTER("Event_worker_thread::run"); DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx", (long) my_time(0), (long) thd)); + inc_thread_running(); if (res) goto end; @@ -334,6 +325,7 @@ end: event->name.str)); delete event; + dec_thread_running(); deinit_event_thread(thd); DBUG_VOID_RETURN; @@ -432,13 +424,9 @@ Event_scheduler::start(int *err_no) " Can not create thread for event scheduler (errno=%d)", *err_no); - new_thd->proc_info= "Clearing"; - DBUG_ASSERT(new_thd->net.buff != 0); - net_end(&new_thd->net); - state= INITIALIZED; scheduler_thd= NULL; - delete new_thd; + deinit_event_thread(new_thd); delete scheduler_param_value; ret= true; @@ -505,7 +493,6 @@ Event_scheduler::run(THD *thd) } LOCK_DATA(); - deinit_event_thread(thd); scheduler_thd= NULL; state= INITIALIZED; DBUG_PRINT("info", ("Broadcasting COND_state back to the stoppers")); @@ -564,10 +551,7 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) sql_print_error("Event_scheduler::execute_top: Can not create event worker" " thread (errno=%d). Stopping event scheduler", res); - new_thd->proc_info= "Clearing"; - DBUG_ASSERT(new_thd->net.buff != 0); - net_end(&new_thd->net); - + deinit_event_thread(new_thd); goto error; } @@ -579,9 +563,6 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) error: DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res)); - if (new_thd) - delete new_thd; - delete event_name; DBUG_RETURN(TRUE); } -- cgit v1.2.1 From 82a96926a77b38a36a031e34b2c4ff3e36406f3d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 15 Jun 2016 13:57:44 +0400 Subject: MDEV-9728 - Hard crash in metadata_lock_info metadata_lock_info plugin called MDL_context::find_ticket() to obtain lock duration, which in turn iterates foreign thread private lists. These lists can be updated by owner thread without protection. Fixed by iterating threads (instead of MDL locks and tickets) and obtaining data through APC. Also fixed mdl_iterate_lock() to initialize iterator under prlock protection. --- sql/mdl.cc | 4 ++-- sql/mdl.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/mdl.cc b/sql/mdl.cc index b94a3710fd1..28d2006b023 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -706,10 +706,10 @@ static inline int mdl_iterate_lock(MDL_lock *lock, int (*callback)(MDL_ticket *ticket, void *arg), void *arg) { - MDL_lock::Ticket_iterator ticket_it(lock->m_granted); - MDL_ticket *ticket; int res= 0; mysql_prlock_rdlock(&lock->m_rwlock); + MDL_lock::Ticket_iterator ticket_it(lock->m_granted); + MDL_ticket *ticket; while ((ticket= ticket_it++) && !(res= callback(ticket, arg))) /* no-op */; mysql_prlock_unlock(&lock->m_rwlock); return res; diff --git a/sql/mdl.h b/sql/mdl.h index c4d792acd29..ec7b633a67d 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -953,7 +953,7 @@ private: MDL_context &operator=(MDL_context &rhs); /* not implemented */ /* metadata_lock_info plugin */ - friend int i_s_metadata_lock_info_fill_row(MDL_ticket*, void*); + friend class Ticket_info; }; -- cgit v1.2.1 From 911af69d1e13e5dff43b550da19d3d4a0ae07e96 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 20 Jun 2016 14:35:58 +0200 Subject: MDEV-5973: MySQL Bug#11757486:49539: NON-DESCRIPTIVE ERR (ERROR 0 FROM STORAGE ENGINE) WITH MULTI-TABLE UPDATE Condition in processing IGNORE clause for UPDATE & multi-table UPDATE made the same. --- sql/sql_update.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 2507c3fec53..b2af075e2f4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1584,7 +1584,7 @@ bool mysql_multi_update(THD *thd, DBUG_RETURN(TRUE); } - thd->abort_on_warning= thd->is_strict_mode(); + thd->abort_on_warning= !ignore && thd->is_strict_mode(); List total_list; res= mysql_select(thd, &select_lex->ref_pointer_array, -- cgit v1.2.1 From 69f1a3215e5062eb6c06ed35ec38e1d824efbef6 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 21 Jun 2016 19:20:11 +0200 Subject: Replace dynamic loading of mysqld.exe data for plugins, replace with MYSQL_PLUGIN_IMPORT --- sql/mysqld.h | 6 +++--- sql/slave.h | 4 ++-- sql/sql_class.h | 4 ++-- sql/sql_plugin.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.h b/sql/mysqld.h index dbc65cd2a43..02e3184404b 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -92,7 +92,7 @@ extern bool opt_disable_networking, opt_skip_show_db; extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; -extern bool volatile abort_loop; +extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; extern bool in_bootstrap; extern uint connection_count; extern my_bool opt_safe_user_create; @@ -155,7 +155,7 @@ extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern const double log_10[309]; extern ulonglong keybuff_size; extern ulonglong thd_startup_options; -extern ulong thread_id; +extern MYSQL_PLUGIN_IMPORT ulong thread_id; extern ulong binlog_cache_use, binlog_cache_disk_use; extern ulong binlog_stmt_cache_use, binlog_stmt_cache_disk_use; extern ulong aborted_threads,aborted_connects; @@ -226,7 +226,7 @@ extern MYSQL_FILE *bootstrap_file; extern my_bool old_mode; extern LEX_STRING opt_init_connect, opt_init_slave; extern int bootstrap_error; -extern I_List threads; +extern MYSQL_PLUGIN_IMPORT I_List threads; extern char err_shared_dir[]; extern ulong connection_errors_select; extern ulong connection_errors_accept; diff --git a/sql/slave.h b/sql/slave.h index 5cc02c8a10b..946cc956c41 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -244,7 +244,7 @@ void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); -extern bool volatile abort_loop; +extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; extern Master_info *active_mi; /* active_mi for multi-master */ extern Master_info *default_master_info; /* To replace active_mi */ extern Master_info_index *master_info_index; @@ -258,7 +258,7 @@ extern uint report_port; extern char *master_info_file, *report_user; extern char *report_host, *report_password; -extern I_List threads; +extern MYSQL_PLUGIN_IMPORT I_List threads; #else #define close_active_mi() /* no-op */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 46eeeceb112..799a6088d3f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1094,8 +1094,8 @@ typedef struct st_xid_state { uint rm_error; } XID_STATE; -extern mysql_mutex_t LOCK_xid_cache; -extern HASH xid_cache; +extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_xid_cache; +extern MYSQL_PLUGIN_IMPORT HASH xid_cache; bool xid_cache_init(void); void xid_cache_free(void); XID_STATE *xid_cache_search(XID *xid); diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index a0225f4a071..e5f985aa082 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -153,7 +153,7 @@ typedef int (*plugin_type_init)(struct st_plugin_int *); extern I_List *opt_plugin_load_list_ptr; extern char *opt_plugin_dir_ptr; -extern char opt_plugin_dir[FN_REFLEN]; +extern MYSQL_PLUGIN_IMPORT char opt_plugin_dir[FN_REFLEN]; extern const LEX_STRING plugin_type_names[]; extern ulong plugin_maturity; extern TYPELIB plugin_maturity_values; -- cgit v1.2.1 From 21479a6bb3cc37ffa1fb4f53a0ab71d22c7ad445 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 21 Jun 2016 21:26:31 +0400 Subject: MDEV-9524 Cannot load from mysql.event when sql_mode is set to PAD_CHAR_TO_FULL_LENGTH The patch fixes the problem with loading information from system tables (e.g. event and help related tables) when PAD_CHAR_TO_FULL_LENGTH is enabled, as well as includes some additional minor improvements: - refactoring in get_field() to return an error rather than success if strmake_root() failed - removing of duplicate code in similar functions: char *get_field(MEM_ROOT *mem, Field *field) bool get_field(MEM_ROOT *mem, Field *field, String *res) --- sql/sql_help.cc | 11 ++++++++++- sql/table.cc | 34 ++++++++++++++++------------------ 2 files changed, 26 insertions(+), 19 deletions(-) (limited to 'sql') diff --git a/sql/sql_help.cc b/sql/sql_help.cc index afeb9395a55..f509d8b8f99 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -647,7 +647,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, TRUE Error and send_error already commited */ -bool mysqld_help(THD *thd, const char *mask) +static bool mysqld_help_internal(THD *thd, const char *mask) { Protocol *protocol= thd->protocol; SQL_SELECT *select; @@ -823,3 +823,12 @@ error2: DBUG_RETURN(TRUE); } + +bool mysqld_help(THD *thd, const char *mask) +{ + ulonglong sql_mode_backup= thd->variables.sql_mode; + thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + bool rc= mysqld_help_internal(thd, mask); + thd->variables.sql_mode= sql_mode_backup; + return rc; +} diff --git a/sql/table.cc b/sql/table.cc index 5dae23116cc..e357d508e9e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3384,18 +3384,23 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) { char buff[MAX_FIELD_WIDTH], *to; String str(buff,sizeof(buff),&my_charset_bin); - uint length; + bool rc; + THD *thd= field->get_thd(); + ulonglong sql_mode_backup= thd->variables.sql_mode; + thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; field->val_str(&str); - if (!(length= str.length())) + if ((rc= !str.length() || + !(to= strmake_root(mem, str.ptr(), str.length())))) { res->length(0); - return 1; + goto ex; } - if (!(to= strmake_root(mem, str.ptr(), length))) - length= 0; // Safety fix - res->set(to, length, field->charset()); - return 0; + res->set(to, str.length(), field->charset()); + +ex: + thd->variables.sql_mode= sql_mode_backup; + return rc; } @@ -3414,17 +3419,10 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) char *get_field(MEM_ROOT *mem, Field *field) { - char buff[MAX_FIELD_WIDTH], *to; - String str(buff,sizeof(buff),&my_charset_bin); - uint length; - - field->val_str(&str); - length= str.length(); - if (!length || !(to= (char*) alloc_root(mem,length+1))) - return NullS; - memcpy(to,str.ptr(),(uint) length); - to[length]=0; - return to; + String str; + bool rc= get_field(mem, field, &str); + DBUG_ASSERT(rc || str.ptr()[str.length()] == '\0'); + return rc ? NullS : (char *) str.ptr(); } /* -- cgit v1.2.1 From 25f1a7ae69a28ff2b32cd0dfd39437384c9ed400 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Jun 2016 10:23:11 +0200 Subject: revert part of 69f1a32 in particular, revert changes to the spider (avoid diverging from the upstream if possible) --- sql/mysqld.h | 6 +++--- sql/slave.h | 4 ++-- sql/sql_class.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.h b/sql/mysqld.h index 02e3184404b..dbc65cd2a43 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -92,7 +92,7 @@ extern bool opt_disable_networking, opt_skip_show_db; extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; -extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; +extern bool volatile abort_loop; extern bool in_bootstrap; extern uint connection_count; extern my_bool opt_safe_user_create; @@ -155,7 +155,7 @@ extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern const double log_10[309]; extern ulonglong keybuff_size; extern ulonglong thd_startup_options; -extern MYSQL_PLUGIN_IMPORT ulong thread_id; +extern ulong thread_id; extern ulong binlog_cache_use, binlog_cache_disk_use; extern ulong binlog_stmt_cache_use, binlog_stmt_cache_disk_use; extern ulong aborted_threads,aborted_connects; @@ -226,7 +226,7 @@ extern MYSQL_FILE *bootstrap_file; extern my_bool old_mode; extern LEX_STRING opt_init_connect, opt_init_slave; extern int bootstrap_error; -extern MYSQL_PLUGIN_IMPORT I_List threads; +extern I_List threads; extern char err_shared_dir[]; extern ulong connection_errors_select; extern ulong connection_errors_accept; diff --git a/sql/slave.h b/sql/slave.h index 946cc956c41..5cc02c8a10b 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -244,7 +244,7 @@ void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); -extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; +extern bool volatile abort_loop; extern Master_info *active_mi; /* active_mi for multi-master */ extern Master_info *default_master_info; /* To replace active_mi */ extern Master_info_index *master_info_index; @@ -258,7 +258,7 @@ extern uint report_port; extern char *master_info_file, *report_user; extern char *report_host, *report_password; -extern MYSQL_PLUGIN_IMPORT I_List threads; +extern I_List threads; #else #define close_active_mi() /* no-op */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 799a6088d3f..46eeeceb112 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1094,8 +1094,8 @@ typedef struct st_xid_state { uint rm_error; } XID_STATE; -extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_xid_cache; -extern MYSQL_PLUGIN_IMPORT HASH xid_cache; +extern mysql_mutex_t LOCK_xid_cache; +extern HASH xid_cache; bool xid_cache_init(void); void xid_cache_free(void); XID_STATE *xid_cache_search(XID *xid); -- cgit v1.2.1 From a10fd659aacd3a23386e5ff61a8c0ef9165690a3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Jun 2016 00:24:42 +0200 Subject: Fixed for failures in buildbot: Replication 1. remove unnecessary rpl-tokudb combination file. 2. fix rpl_ignore_table to cleanup properly (not leave test grants in memory) 3. check_temp_dir() is supposed to set the error in stmt_da - do it even when called multiple times, this fixes a crash when rpl.rpl_slave_load_tmpdir_not_exist is run twice. --- sql/slave.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index 5dce7feed73..5d44fb2b6a8 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4292,7 +4292,8 @@ int check_temp_dir(char* tmp_file) mysql_mutex_lock(&LOCK_thread_count); if (check_temp_dir_run) { - result= check_temp_dir_result; + if ((result= check_temp_dir_result)) + my_message(result, tmp_file, MYF(0)); goto end; } check_temp_dir_run= 1; @@ -4327,7 +4328,6 @@ int check_temp_dir(char* tmp_file) mysql_file_delete(key_file_misc, tmp_file, MYF(0)); end: - check_temp_dir_result= result; mysql_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(result); } @@ -4603,11 +4603,14 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, if (check_temp_dir(rli->slave_patternload_file)) { + check_temp_dir_result= thd->get_stmt_da()->sql_errno(); rli->report(ERROR_LEVEL, thd->get_stmt_da()->sql_errno(), NULL, "Unable to use slave's temporary directory %s - %s", slave_load_tmpdir, thd->get_stmt_da()->message()); goto err; } + else + check_temp_dir_result= 0; /* Load the set of seen GTIDs, if we did not already. */ if (rpl_load_gtid_slave_state(thd)) -- cgit v1.2.1 From 5fd80875909c88e624a79a528eaaf9418089a211 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Mon, 30 May 2016 21:42:36 +0300 Subject: [MDEV-9614] Roles and Users longer than 6 characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bug is apparent when the username is longer than the rolename. It is caused by a simple typo that caused a memcmp call to compare a different number of bytes than necessary. The fix was proposed by Igor Pashev. I have reviewed it and it is the correct approach. Test case introduced by me, using the details provided in the MDEV. Signed-off-by: VicenÈ›iu Ciorbaru --- sql/sql_acl.cc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 8cc9469cd09..f06e9ce647c 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7195,8 +7195,7 @@ bool check_grant_db(THD *thd, const char *db) len= (uint) (end - helping) + 1; /* - If a role is set, we need to check for privileges - here aswell + If a role is set, we need to check for privileges here as well. */ if (sctx->priv_role[0]) { @@ -7210,11 +7209,10 @@ bool check_grant_db(THD *thd, const char *db) for (uint idx=0 ; idx < column_priv_hash.records ; idx++) { - GRANT_TABLE *grant_table= (GRANT_TABLE*) - my_hash_element(&column_priv_hash, - idx); + GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash, + idx); if (len < grant_table->key_length && - !memcmp(grant_table->hash_key,helping,len) && + !memcmp(grant_table->hash_key, helping, len) && compare_hostname(&grant_table->host, sctx->host, sctx->ip)) { error= FALSE; /* Found match. */ @@ -7222,7 +7220,7 @@ bool check_grant_db(THD *thd, const char *db) } if (sctx->priv_role[0] && len2 < grant_table->key_length && - !memcmp(grant_table->hash_key,helping2,len) && + !memcmp(grant_table->hash_key, helping2, len2) && (!grant_table->host.hostname || !grant_table->host.hostname[0])) { error= FALSE; /* Found role match */ -- cgit v1.2.1 From b449612907bd09bebf8d1280d80839cd16784fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 20 Jun 2016 23:43:01 +0300 Subject: MDEV-8638: REVOKE ALL PRIVILEGES, GRANT OPTION FROM CURRENT_ROLE breaks replication Fix the replication failure caused by incorect initialization of THD::invoker_host && THD::invoker_user. Breakdown of the failure is this: Query_log_event::host and Query_log_event::user can have their LEX_STRING's set to length 0, but the actual str member points to garbage. Code afterwards copies Query_log_event::host and user to THD::invoker_host and THD::invoker_user. Calling code for these members expects both members to be initialized. Eg. the str member be a NULL terminated string and length have appropriate size. --- sql/log_event.cc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 82cd82b5e7a..4a1d13a8004 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3631,10 +3631,25 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (time_zone_len) copy_str_and_move(&time_zone_str, &start, time_zone_len); - if (user.length > 0) + if (user.length) + { copy_str_and_move((const char **)&(user.str), &start, user.length); - if (host.length > 0) + } + else + { + user.str= (char *) start++; + user.str[0]= '\0'; + } + + if (host.length) + { copy_str_and_move((const char **)&(host.str), &start, host.length); + } + else + { + host.str= (char *) start++; + host.str[0]= '\0'; + } /** if time_zone_len or catalog_len are 0, then time_zone and catalog -- cgit v1.2.1 From 3e03b89b0a683dd3b14d6ea24d2ca93accdfd61f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 22 Jun 2016 23:20:41 +0300 Subject: MDEV-10185: Assertion `tree1->keys[key_no] && tree2->keys[key_no]' failed in Make tree_or set correct SEL_TREE::keys_map for the result. --- sql/opt_range.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3d059abd666..b262b0c4191 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8580,6 +8580,7 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) for e.g. "key IN (c1, ..., cN)" which produces a lot of ranges. */ result= tree1; + result->keys_map.clear_all(); } else { -- cgit v1.2.1 From 4abeebeed78a962e5dd10ff53b53ffd4e8699700 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 23 Jun 2016 12:06:16 +0400 Subject: MDEV-9728 - Hard crash in metadata_lock_info Reverted APC based fix. APC subsystem is not ready to serve metadata_lock_info needs. --- sql/mdl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mdl.h b/sql/mdl.h index ec7b633a67d..c4d792acd29 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -953,7 +953,7 @@ private: MDL_context &operator=(MDL_context &rhs); /* not implemented */ /* metadata_lock_info plugin */ - friend class Ticket_info; + friend int i_s_metadata_lock_info_fill_row(MDL_ticket*, void*); }; -- cgit v1.2.1 From 79f852a069fb6ba5e18fd66ea2a24fa91c245c24 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 22 Jun 2016 14:17:06 +0200 Subject: MDEV-10050: Crash in subselect thd should not be taken earlier then fix_field and reset on fix_fields if it is needed. --- sql/item_subselect.cc | 58 +++++++++++++++++++++++++++++++-------------------- sql/item_subselect.h | 34 +++++++++++++----------------- 2 files changed, 50 insertions(+), 42 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index ba674743724..690318c610a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -79,7 +79,6 @@ void Item_subselect::init(st_select_lex *select_lex, DBUG_PRINT("enter", ("select_lex: 0x%lx this: 0x%lx", (ulong) select_lex, (ulong) this)); unit= select_lex->master_unit(); - thd= unit->thd; if (unit->item) { @@ -90,7 +89,7 @@ void Item_subselect::init(st_select_lex *select_lex, engine= unit->item->engine; own_engine= FALSE; parsing_place= unit->item->parsing_place; - thd->change_item_tree((Item**)&unit->item, this); + unit->thd->change_item_tree((Item**)&unit->item, this); engine->change_result(this, result, TRUE); } else @@ -104,9 +103,9 @@ void Item_subselect::init(st_select_lex *select_lex, NO_MATTER : outer_select->parsing_place); if (unit->is_union()) - engine= new subselect_union_engine(thd, unit, result, this); + engine= new subselect_union_engine(unit, result, this); else - engine= new subselect_single_select_engine(thd, select_lex, result, this); + engine= new subselect_single_select_engine(select_lex, result, this); } { SELECT_LEX *upper= unit->outer_select(); @@ -220,6 +219,10 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) uint8 uncacheable; bool res; + thd= thd_param; + + DBUG_ASSERT(unit->thd == thd); + status_var_increment(thd_param->status_var.feature_subquery); DBUG_ASSERT(fixed == 0); @@ -242,7 +245,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) return TRUE; - if (!(res= engine->prepare())) + if (!(res= engine->prepare(thd))) { // all transformation is done (used by prepared statements) changed= 1; @@ -2651,7 +2654,10 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { uint outer_cols_num; List *inner_cols; - char const *save_where= thd->where; + char const *save_where= thd_arg->where; + + thd= thd_arg; + DBUG_ASSERT(unit->thd == thd); if (test_strategy(SUBS_SEMI_JOIN)) return !( (*ref)= new Item_int(1)); @@ -2769,7 +2775,8 @@ bool Item_in_subselect::setup_mat_engine() if (!(mat_engine= new subselect_hash_sj_engine(thd, this, select_engine))) DBUG_RETURN(TRUE); - if (mat_engine->init(&select_engine->join->fields_list, + if (mat_engine->prepare(thd) || + mat_engine->init(&select_engine->join->fields_list, engine->get_identifier())) DBUG_RETURN(TRUE); @@ -2885,10 +2892,10 @@ void subselect_engine::set_thd(THD *thd_arg) subselect_single_select_engine:: -subselect_single_select_engine(THD *thd_arg, st_select_lex *select, +subselect_single_select_engine(st_select_lex *select, select_result_interceptor *result_arg, Item_subselect *item_arg) - :subselect_engine(thd_arg, item_arg, result_arg), + :subselect_engine(item_arg, result_arg), prepared(0), executed(0), select_lex(select), join(0) { @@ -2966,10 +2973,10 @@ void subselect_uniquesubquery_engine::cleanup() } -subselect_union_engine::subselect_union_engine(THD *thd_arg, st_select_lex_unit *u, +subselect_union_engine::subselect_union_engine(st_select_lex_unit *u, select_result_interceptor *result_arg, Item_subselect *item_arg) - :subselect_engine(thd_arg, item_arg, result_arg) + :subselect_engine(item_arg, result_arg) { unit= u; unit->item= item_arg; @@ -3002,10 +3009,11 @@ subselect_union_engine::subselect_union_engine(THD *thd_arg, st_select_lex_unit @retval 1 if error */ -int subselect_single_select_engine::prepare() +int subselect_single_select_engine::prepare(THD *thd) { if (prepared) return 0; + set_thd(thd); if (select_lex->join) { select_lex->cleanup(); @@ -3034,12 +3042,13 @@ int subselect_single_select_engine::prepare() return 0; } -int subselect_union_engine::prepare() +int subselect_union_engine::prepare(THD *thd_arg) { + set_thd(thd_arg); return unit->prepare(thd, result, SELECT_NO_UNLOCK); } -int subselect_uniquesubquery_engine::prepare() +int subselect_uniquesubquery_engine::prepare(THD *) { /* Should never be called. */ DBUG_ASSERT(FALSE); @@ -4499,13 +4508,14 @@ subselect_hash_sj_engine::~subselect_hash_sj_engine() } -int subselect_hash_sj_engine::prepare() +int subselect_hash_sj_engine::prepare(THD *thd_arg) { /* Create and optimize the JOIN that will be used to materialize the subquery if not yet created. */ - return materialize_engine->prepare(); + set_thd(thd_arg); + return materialize_engine->prepare(thd); } @@ -4877,7 +4887,7 @@ int subselect_hash_sj_engine::exec() if (strategy == PARTIAL_MATCH_MERGE) { pm_engine= - new subselect_rowid_merge_engine(thd, (subselect_uniquesubquery_engine*) + new subselect_rowid_merge_engine((subselect_uniquesubquery_engine*) lookup_engine, tmp_table, count_pm_keys, has_covering_null_row, @@ -4886,6 +4896,7 @@ int subselect_hash_sj_engine::exec() item, result, semi_join_conds->argument_list()); if (!pm_engine || + pm_engine->prepare(thd) || ((subselect_rowid_merge_engine*) pm_engine)-> init(nn_key_parts, &partial_match_key_parts)) { @@ -4903,13 +4914,14 @@ int subselect_hash_sj_engine::exec() if (strategy == PARTIAL_MATCH_SCAN) { if (!(pm_engine= - new subselect_table_scan_engine(thd, (subselect_uniquesubquery_engine*) + new subselect_table_scan_engine((subselect_uniquesubquery_engine*) lookup_engine, tmp_table, item, result, semi_join_conds->argument_list(), has_covering_null_row, has_covering_null_columns, - count_columns_with_nulls))) + count_columns_with_nulls)) || + pm_engine->prepare(thd)) { /* This is an irrecoverable error. */ res= 1; @@ -5356,14 +5368,14 @@ void Ordered_key::print(String *str) subselect_partial_match_engine::subselect_partial_match_engine( - THD *thd_arg, subselect_uniquesubquery_engine *engine_arg, + subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg) - :subselect_engine(thd_arg, item_arg, result_arg), + :subselect_engine(item_arg, result_arg), tmp_table(tmp_table_arg), lookup_engine(engine_arg), equi_join_conds(equi_join_conds_arg), has_covering_null_row(has_covering_null_row_arg), @@ -5976,7 +5988,7 @@ end: subselect_table_scan_engine::subselect_table_scan_engine( - THD *thd_arg, subselect_uniquesubquery_engine *engine_arg, + subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, @@ -5984,7 +5996,7 @@ subselect_table_scan_engine::subselect_table_scan_engine( bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg) - :subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, item_arg, + :subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg, result_arg, equi_join_conds_arg, has_covering_null_row_arg, has_covering_null_columns_arg, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0ee5f73eb35..0abfe0d5abc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -715,7 +715,7 @@ public: INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE, ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE}; - subselect_engine(THD *thd_arg, Item_subselect *si, + subselect_engine(Item_subselect *si, select_result_interceptor *res) { result= res; @@ -723,7 +723,6 @@ public: cmp_type= res_type= STRING_RESULT; res_field_type= MYSQL_TYPE_VAR_STRING; maybe_null= 0; - set_thd(thd_arg); } virtual ~subselect_engine() {}; // to satisfy compiler virtual void cleanup()= 0; @@ -734,7 +733,7 @@ public: */ void set_thd(THD *thd_arg); THD * get_thd() { return thd; } - virtual int prepare()= 0; + virtual int prepare(THD *)= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; /* Execute the engine @@ -789,11 +788,11 @@ class subselect_single_select_engine: public subselect_engine st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: - subselect_single_select_engine(THD *thd_arg, st_select_lex *select, + subselect_single_select_engine(st_select_lex *select, select_result_interceptor *result, Item_subselect *item); void cleanup(); - int prepare(); + int prepare(THD *thd); void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); @@ -823,11 +822,11 @@ class subselect_union_engine: public subselect_engine { st_select_lex_unit *unit; /* corresponding unit structure */ public: - subselect_union_engine(THD *thd_arg, st_select_lex_unit *u, + subselect_union_engine(st_select_lex_unit *u, select_result_interceptor *result, Item_subselect *item); void cleanup(); - int prepare(); + int prepare(THD *); void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); @@ -880,11 +879,11 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, Item_subselect *subs, Item *where) - :subselect_engine(thd_arg, subs, 0), tab(tab_arg), cond(where) + :subselect_engine(subs, 0), tab(tab_arg), cond(where) {} ~subselect_uniquesubquery_engine(); void cleanup(); - int prepare(); + int prepare(THD *); void fix_length_and_dec(Item_cache** row); int exec(); uint cols() { return 1; } @@ -1012,7 +1011,7 @@ public: subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate, subselect_single_select_engine *old_engine) - : subselect_engine(thd, in_predicate, NULL), + : subselect_engine(in_predicate, NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL), count_partial_match_columns(0), count_null_only_columns(0), @@ -1022,7 +1021,7 @@ public: bool init(List *tmp_columns, uint subquery_id); void cleanup(); - int prepare(); + int prepare(THD *); int exec(); virtual void print(String *str, enum_query_type query_type); uint cols() @@ -1301,15 +1300,14 @@ protected: protected: virtual bool partial_match()= 0; public: - subselect_partial_match_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_partial_match_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg); - int prepare() { return 0; } + int prepare(THD *thd_arg) { set_thd(thd_arg); return 0; } int exec(); void fix_length_and_dec(Item_cache**) {} uint cols() { /* TODO: what is the correct value? */ return 1; } @@ -1396,8 +1394,7 @@ protected: bool exists_complementing_null_row(MY_BITMAP *keys_to_complement); bool partial_match(); public: - subselect_rowid_merge_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_rowid_merge_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, uint merge_keys_count_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, @@ -1405,7 +1402,7 @@ public: Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg) - :subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, + :subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg, result_arg, equi_join_conds_arg, has_covering_null_row_arg, has_covering_null_columns_arg, @@ -1424,8 +1421,7 @@ class subselect_table_scan_engine: public subselect_partial_match_engine protected: bool partial_match(); public: - subselect_table_scan_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_table_scan_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, -- cgit v1.2.1 From 652e799a387f63a582254a68363e720e47db97e4 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 27 Jun 2016 15:14:07 +0400 Subject: MDEV-8502 DECIMAL accepts out of range DEFAULT values MDEV-10277 Redundant NOTE when inserting '0.00001 ' into a DECIMAL(2,1) column --- sql/field.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++---------------- sql/field.h | 5 ++++ 2 files changed, 62 insertions(+), 20 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index ffa7beb275b..a7c655087c7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1477,10 +1477,12 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd, */ -int Field_num::check_edom_and_truncation(const char *type, bool edom, - CHARSET_INFO *cs, - const char *str, uint length, - const char *end) +int Field_num::check_edom_and_important_data_truncation(const char *type, + bool edom, + CHARSET_INFO *cs, + const char *str, + uint length, + const char *end) { /* Test if we get an empty string or garbage */ if (edom) @@ -1495,12 +1497,23 @@ int Field_num::check_edom_and_truncation(const char *type, bool edom, set_warning(WARN_DATA_TRUNCATED, 1); return 2; } - if (end < str + length) - set_note(WARN_DATA_TRUNCATED, 1); return 0; } +int Field_num::check_edom_and_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end) +{ + int rc= check_edom_and_important_data_truncation(type, edom, + cs, str, length, end); + if (!rc && end < str + length) + set_note(WARN_DATA_TRUNCATED, 1); + return rc; +} + + /* Conver a string to an integer then check bounds. @@ -3005,7 +3018,8 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, If it does, stores the decimal in the buffer using binary format. Otherwise sets maximal number that can be stored in the field. - @param decimal_value my_decimal + @param decimal_value my_decimal + @param [OUT] native_error the error returned by my_decimal2binary(). @retval 0 ok @@ -3013,7 +3027,8 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, 1 error */ -bool Field_new_decimal::store_value(const my_decimal *decimal_value) +bool Field_new_decimal::store_value(const my_decimal *decimal_value, + int *native_error) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int error= 0; @@ -3042,11 +3057,14 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) } #endif - if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - decimal_value, ptr, precision, dec))) + *native_error= my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, + decimal_value, ptr, precision, dec); + + if (*native_error == E_DEC_OVERFLOW) { my_decimal buff; DBUG_PRINT("info", ("overflow")); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); set_value_on_overflow(&buff, decimal_value->sign()); my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec); error= 1; @@ -3057,6 +3075,16 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) } +bool Field_new_decimal::store_value(const my_decimal *decimal_value) +{ + int native_error; + bool rc= store_value(decimal_value, &native_error); + if (!rc && native_error == E_DEC_TRUNCATED) + set_note(WARN_DATA_TRUNCATED, 1); + return rc; +} + + int Field_new_decimal::store(const char *from, uint length, CHARSET_INFO *charset_arg) { @@ -3084,9 +3112,10 @@ int Field_new_decimal::store(const char *from, uint length, if (thd->count_cuted_fields) { - if (check_edom_and_truncation("decimal", - err && err != E_DEC_TRUNCATED, - charset_arg, from, length, end)) + if (check_edom_and_important_data_truncation("decimal", + err && err != E_DEC_TRUNCATED, + charset_arg, + from, length, end)) { if (!thd->abort_on_warning) { @@ -3109,12 +3138,6 @@ int Field_new_decimal::store(const char *from, uint length, } DBUG_RETURN(1); } - /* - E_DEC_TRUNCATED means minor truncation '1e-1000000000000' -> 0.0 - A note should be enough. - */ - if (err == E_DEC_TRUNCATED) - set_note(WARN_DATA_TRUNCATED, 1); } #ifndef DBUG_OFF @@ -3122,7 +3145,21 @@ int Field_new_decimal::store(const char *from, uint length, DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, &decimal_value))); #endif - store_value(&decimal_value); + int err2; + if (store_value(&decimal_value, &err2)) + DBUG_RETURN(1); + + /* + E_DEC_TRUNCATED means minor truncation, a note should be enough: + - in err: str2my_decimal() truncated '1e-1000000000000' to 0.0 + - in err2: store_value() truncated 1.123 to 1.12, e.g. for DECIMAL(10,2) + Also, we send a note if a string had some trailing spaces: '1.12 ' + */ + if (thd->count_cuted_fields && + (err == E_DEC_TRUNCATED || + err2 == E_DEC_TRUNCATED || + end < from + length)) + set_note(WARN_DATA_TRUNCATED, 1); DBUG_RETURN(0); } diff --git a/sql/field.h b/sql/field.h index 08905f2c9e9..ca13fa9b9c2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1471,6 +1471,10 @@ protected: class Field_num :public Field { protected: + int check_edom_and_important_data_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end_of_num); int check_edom_and_truncation(const char *type, bool edom, CHARSET_INFO *cs, const char *str, uint length, @@ -1708,6 +1712,7 @@ public: Item_result result_type () const { return DECIMAL_RESULT; } int reset(void); bool store_value(const my_decimal *decimal_value); + bool store_value(const my_decimal *decimal_value, int *native_error); void set_value_on_overflow(my_decimal *decimal_value, bool sign); int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); -- cgit v1.2.1 From 09d902d84befaf3b1d247c2fcb9706e3f83522f4 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 27 Jun 2016 18:02:28 +0400 Subject: MDEV-9618 solaris sparc build fails on 10.1. Compiler on Sparc is strict about the 'const' modifiers in function declarations and definitions. Meaning they should be exactly same. --- sql/wsrep_applier.h | 2 ++ sql/wsrep_binlog.h | 8 ++++---- sql/wsrep_priv.h | 7 +++++-- sql/wsrep_utils.h | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h index b6497776e87..d58d3cdc54e 100644 --- a/sql/wsrep_applier.h +++ b/sql/wsrep_applier.h @@ -23,6 +23,7 @@ void wsrep_set_apply_format(THD* thd, Format_description_log_event* ev); Format_description_log_event* wsrep_get_apply_format(THD* thd); /* wsrep callback prototypes */ +extern "C" { wsrep_cb_status_t wsrep_apply_cb(void *ctx, const void* buf, size_t buf_len, @@ -39,4 +40,5 @@ wsrep_cb_status_t wsrep_unordered_cb(void* ctx, const void* data, size_t size); +} /* extern "C" */ #endif /* WSREP_APPLIER_H */ diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h index d8a2eb51d4a..1e820529211 100644 --- a/sql/wsrep_binlog.h +++ b/sql/wsrep_binlog.h @@ -38,10 +38,10 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len); @param len total amount of data written @return wsrep error status */ -int wsrep_write_cache (wsrep_t* wsrep, - THD* thd, - IO_CACHE* cache, - size_t* len); +int wsrep_write_cache (wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len); /* Dump replication buffer to disk */ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len); diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h index 30dce78c1a4..1f3fdda2560 100644 --- a/sql/wsrep_priv.h +++ b/sql/wsrep_priv.h @@ -40,8 +40,11 @@ extern wsrep_uuid_t local_uuid; extern wsrep_seqno_t local_seqno; // a helper function -void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t&, wsrep_seqno_t, - const void*, size_t); +void wsrep_sst_received (wsrep_t* const wsrep, + const wsrep_uuid_t& uuid, + wsrep_seqno_t const segno, + const void * const state, + size_t const state_len); /*! SST thread signals init thread about sst completion */ void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool); diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index ed699eabec9..6025423fe7f 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -19,7 +19,7 @@ #include "wsrep_priv.h" #include "wsrep_mysqld.h" -unsigned int wsrep_check_ip (const char* addr, bool *is_ipv6); +unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6); size_t wsrep_guess_ip (char* buf, size_t buf_len); namespace wsp { -- cgit v1.2.1 From b57232d3cb3dbf43551bf7aea42b6f439e0e49eb Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 17:56:59 -0400 Subject: MDEV-6699 : wsrep_node_name not automatically set to hostname Fixed by using hostname (glob_hostname) as default value for wsrep_node_name system variable. Added a test case. --- sql/mysqld.cc | 8 -------- sql/sys_vars.cc | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ee40df945ed..6c8f79bf37a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4190,14 +4190,6 @@ static int init_common_variables() else opt_log_basename= glob_hostname; -#ifdef WITH_WSREP - if (wsrep_node_name == 0 || wsrep_node_name[0] == 0) - { - my_free((void *)wsrep_node_name); - wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME)); - } -#endif /* WITH_WSREP */ - strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5); strmov(fn_ext(pidfile_name),".pid"); // Add proper extension SYSVAR_AUTOSIZE(pidfile_name_ptr, pidfile_name); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 3b043d92d75..29e167d4664 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4730,7 +4730,7 @@ static Sys_var_charptr Sys_wsrep_cluster_address ( static Sys_var_charptr Sys_wsrep_node_name ( "wsrep_node_name", "Node name", PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG), - IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + IN_SYSTEM_CHARSET, DEFAULT(glob_hostname), NO_MUTEX_GUARD, NOT_IN_BINLOG, wsrep_node_name_check, wsrep_node_name_update); static Sys_var_charptr Sys_wsrep_node_address ( -- cgit v1.2.1 From 2768829e5397756faeae706df80bdba468f77795 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 17:59:12 -0400 Subject: MDEV-10056: SST method mysqldump is broken errno must be reset before strtol()/strtoll() functions are invoked. --- sql/wsrep_sst.cc | 1 + sql/wsrep_utils.h | 1 + 2 files changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 4f6cc51c3f8..c2a1ab58660 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -340,6 +340,7 @@ static int sst_scan_uuid_seqno (const char* str, wsrep_uuid_t* uuid, wsrep_seqno_t* seqno) { int offt = wsrep_uuid_scan (str, strlen(str), uuid); + errno= 0; /* Reset the errno */ if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt]) { *seqno = strtoll (str + offt + 1, NULL, 10); diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index 6025423fe7f..f20e02d03a2 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -155,6 +155,7 @@ private: } bool parse_port(const char *port) { + errno= 0; /* Reset the errno */ m_port= strtol(port, NULL, 10); if (errno == EINVAL || errno == ERANGE) { -- cgit v1.2.1 From 7f9fcfe00efa7262b0b95e00a595083ab0e21426 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 18:07:43 -0400 Subject: Code cleanup (wsrep patch). --- sql/wsrep_mysqld.cc | 10 +++++++--- sql/wsrep_mysqld.h | 5 ----- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 1d96176a70d..2f35e6cc623 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1260,7 +1260,7 @@ wsrep_alter_query_string(THD *thd, String *buf) return 0; } -int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) +static int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) { String log_query; @@ -1356,6 +1356,10 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len) return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len); } +/* Forward declarations. */ +static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); +static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); + /* returns: 0: statement was replicated as TOI @@ -2167,7 +2171,7 @@ void wsrep_kill_mysql(THD *thd) } -int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) +static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) { String log_query; sp_head *sp = thd->lex->sphead; @@ -2494,7 +2498,7 @@ error: } -int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) +static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) { LEX *lex= thd->lex; String stmt_query; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index e91ed2302a2..ea81384da75 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -280,10 +280,7 @@ void wsrep_to_isolation_end(THD *thd); void wsrep_cleanup_transaction(THD *thd); int wsrep_to_buf_helper( THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len); -int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); -int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len); -int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len); extern bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx, @@ -304,14 +301,12 @@ void wsrep_close_applier_threads(int count); void wsrep_wait_appliers_close(THD *thd); void wsrep_kill_mysql(THD *thd); void wsrep_close_threads(THD *thd); -int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); void wsrep_copy_query(THD *thd); bool wsrep_is_show_query(enum enum_sql_command command); void wsrep_replay_transaction(THD *thd); bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, HA_CREATE_INFO *create_info); -int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); #else /* WITH_WSREP */ -- cgit v1.2.1 From 48a0a66ffa3241c91324606911f7964e956bc99f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 18:15:47 -0400 Subject: MDEV-10186: mysqld crash when runtime setting wsrep_cluster_address without wsrep_on=ON On wsrep_cluster_address update, node restarts the replication and attempts to connect to the new address. In this process it makes a call to wsrep provider's connect API, which could lead to segfault if wsrep provider is not loaded (wsrep_on=OFF). Fixed by making sure that it proceeds only if a provider is loaded. --- sql/wsrep_mysqld.cc | 3 +++ sql/wsrep_var.cc | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 2f35e6cc623..7b242af2cdb 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -881,6 +881,9 @@ bool wsrep_start_replication() { wsrep_status_t rcode; + /* wsrep provider must be loaded. */ + DBUG_ASSERT(wsrep); + /* if provider is trivial, don't even try to connect, but resume local node operation diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 9c01e54f48d..fb784cbcca3 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -348,7 +348,16 @@ bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var) bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) { - bool wsrep_on_saved= thd->variables.wsrep_on; + bool wsrep_on_saved; + + /* Do not proceed if wsrep provider is not loaded. */ + if (!wsrep) + { + WSREP_INFO("wsrep provider is not loaded, can't re(start) replication."); + return false; + } + + wsrep_on_saved= thd->variables.wsrep_on; thd->variables.wsrep_on= false; /* stop replication is heavy operation, and includes closing all client -- cgit v1.2.1 From 90f222ea7dea4bebdb3ad93c4c1439e3ab08bbba Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 18:21:00 -0400 Subject: MDEV-10235: Deadlock in CREATE TABLE .. AS SELECT .. if result set is empty in Galera In CTAS, handlers get registered under statement transaction (st_transactions::stmt), while ha_fake_trx_id(), used by CTAS, looked under standard transaction (st_transactions::all) for registered handlers, and thus it failed to grab a fake transaction ID. As a result, with no valid transaction ID, wsrep commit failed with an error. ha_fake_trx_id() now looks for handlers registered under 'stmt' in case 'all' is empty. Also modified the logic to print warning only once if none of the registered handlers have fake_trx_id. --- sql/handler.cc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 49e451e3836..147221abb97 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6104,25 +6104,42 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) void ha_fake_trx_id(THD *thd) { DBUG_ENTER("ha_fake_trx_id"); + + bool no_fake_trx_id= true; + if (!WSREP(thd)) { DBUG_VOID_RETURN; } - THD_TRANS *trans= &thd->transaction.all; + /* Try statement transaction if standard one is not set. */ + THD_TRANS *trans= (thd->transaction.all.ha_list) ? &thd->transaction.all : + &thd->transaction.stmt; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; for (; ha_info; ha_info= ha_info_next) { handlerton *hton= ha_info->ht(); - if (!hton->fake_trx_id) + if (hton->fake_trx_id) { - WSREP_WARN("cannot get fake InnoDB transaction ID"); - } - else hton->fake_trx_id(hton, thd); + + /* Got a fake trx id. */ + no_fake_trx_id= false; + + /* + We need transaction ID from just one storage engine providing + fake_trx_id (which will most likely be the case). + */ + break; + } ha_info_next= ha_info->next(); } + + if (unlikely(no_fake_trx_id)) + WSREP_WARN("Cannot get fake transaction ID from storage engine."); + DBUG_VOID_RETURN; } #endif /* WITH_WSREP */ -- cgit v1.2.1 From 7ff44b1a832b005264994cbdfc52f93f69b92cdc Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 18:30:07 -0400 Subject: MDEV-10161: wsrep_sync_wait not enabled when set to 1 in config file Since wsrep_sync_wait & wsrep_causal_reads variables are related, they are always kept in sync whenever one of them changes. Same is tried on server start, where wsrep_sync_wait get updated based on wsrep_causal_reads' value. But, since wsrep_causal_reads is OFF by default, wsrep_sync_wait's value gets modified and loses its WSREP_SYNC_WAIT_BEFORE_READ bit. Fixed by syncing wsrep_sync_wait & wsrep_causal_reads values individually on server start in mysqld_get_one_option() based on command line arguments used. --- sql/mysqld.cc | 10 ++++++++++ sql/mysqld.h | 4 ++++ sql/sys_vars.cc | 5 +++-- sql/wsrep_mysqld.cc | 2 -- 4 files changed, 17 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6c8f79bf37a..a19ac8aa968 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -9266,6 +9266,16 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) #endif break; } +#ifdef WITH_WSREP + case OPT_WSREP_CAUSAL_READS: + wsrep_causal_reads_update(&global_system_variables); + break; + case OPT_WSREP_SYNC_WAIT: + global_system_variables.wsrep_causal_reads= + MY_TEST(global_system_variables.wsrep_sync_wait & + WSREP_SYNC_WAIT_BEFORE_READ); + break; +#endif /* WITH_WSREP */ } return 0; } diff --git a/sql/mysqld.h b/sql/mysqld.h index 594afac521d..8454f2410dc 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -636,6 +636,10 @@ enum options_mysqld OPT_SSL_KEY, OPT_THREAD_CONCURRENCY, OPT_WANT_CORE, +#ifdef WITH_WSREP + OPT_WSREP_CAUSAL_READS, + OPT_WSREP_SYNC_WAIT, +#endif /* WITH_WSREP */ OPT_MYSQL_COMPATIBILITY, OPT_MYSQL_TO_BE_IMPLEMENTED, OPT_which_is_always_the_last diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 29e167d4664..c733976452c 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4872,7 +4872,8 @@ static bool fix_wsrep_causal_reads(sys_var *self, THD* thd, enum_var_type var_ty static Sys_var_mybool Sys_wsrep_causal_reads( "wsrep_causal_reads", "Setting this variable is equivalent " "to setting wsrep_sync_wait READ flag", - SESSION_VAR(wsrep_causal_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), + SESSION_VAR(wsrep_causal_reads), + CMD_LINE(OPT_ARG, OPT_WSREP_CAUSAL_READS), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_wsrep_causal_reads), DEPRECATED("'@@wsrep_sync_wait=1'")); @@ -4882,7 +4883,7 @@ static Sys_var_uint Sys_wsrep_sync_wait( "an operation of the type specified by bitmask: 1 - READ(includes " "SELECT, SHOW and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - " "INSERT and REPLACE", - SESSION_VAR(wsrep_sync_wait), CMD_LINE(OPT_ARG), + SESSION_VAR(wsrep_sync_wait), CMD_LINE(OPT_ARG, OPT_WSREP_SYNC_WAIT), VALID_RANGE(WSREP_SYNC_WAIT_NONE, WSREP_SYNC_WAIT_MAX), DEFAULT(WSREP_SYNC_WAIT_NONE), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 7b242af2cdb..823a2a76281 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -561,8 +561,6 @@ int wsrep_init() wsrep_sst_auth_init(wsrep_sst_auth); - wsrep_causal_reads_update(&global_system_variables); - wsrep_ready_set(FALSE); assert(wsrep_provider); -- cgit v1.2.1 From 56a34960678874fad2ec99cc94c37f4e82dfccaa Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 28 Jun 2016 13:11:04 +0400 Subject: MDEV-10236 Where expression with NOT function gives incorrect result Item_cache::is_null() erroneously returned null_value in a non-cached state. Now Item_cache::is_null() uses has_value(), which caches the value if not cached yet, similar to what other value methods do (e.g. val_int, val_real, etc). --- sql/item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index bef57c4a967..93da3985d4c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5050,7 +5050,7 @@ public: bool basic_const_item() const { return MY_TEST(example && example->basic_const_item()); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } - bool is_null() { return null_value; } + bool is_null() { return !has_value(); } virtual bool is_expensive() { if (value_cached) -- cgit v1.2.1 From 6ce20fb2b9fe57330c797694b9dbea4028f40d7c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 28 Jun 2016 10:10:49 +0200 Subject: MDEV-9428 NO_AUTO_VALUE_ON_ZERO is ignored when a trigger before insert is defined fix the *other* fill_record() too, arrgh! --- sql/sql_base.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e808fbafb50..8c1c32e28f6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8728,7 +8728,8 @@ fill_record(THD *thd, TABLE *table_arg, List &fields, List &values, value=v++; Field *rfield= field->field; TABLE* table= rfield->table; - if (rfield == table->next_number_field) + if (table->next_number_field && + rfield->field_index == table->next_number_field->field_index) table->auto_increment_field_not_null= TRUE; if (rfield->vcol_info && value->type() != Item::DEFAULT_VALUE_ITEM && -- cgit v1.2.1 From 341e5f4411f6b958d139c634cce7b95773ef510e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 28 Jun 2016 15:38:41 +0200 Subject: MDEV-10054 Secure login fails when CIPHER is required SSL: do not require client certificate to exist, if GRANT didn't require that --- sql/sql_acl.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d2ef9b4690d..06e38546f43 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -12199,6 +12199,9 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) return 1; } } + if (!acl_user->x509_issuer && !acl_user->x509_subject) + return 0; // all done + /* Prepare certificate (if exists) */ if (!(cert= SSL_get_peer_certificate(ssl))) return 1; -- cgit v1.2.1