diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-06-30 16:38:05 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-06-30 16:38:05 +0200 |
commit | 932646b1ff6a8f5815a961340a9e1ee4702f5b44 (patch) | |
tree | 5bc42ace8ae1f7e4d00baffd468bdb7564e851f1 /sql | |
parent | 0bb30f3603b519780eaf3fe0527b1c6af285229a (diff) | |
parent | 33492ec8d4e2077cf8e07d0628a959d8729bd1f9 (diff) | |
download | mariadb-git-932646b1ff6a8f5815a961340a9e1ee4702f5b44.tar.gz |
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
74 files changed, 1676 insertions, 1281 deletions
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"}, diff --git a/sql/create_options.cc b/sql/create_options.cc index 3011c4b2d7e..40382c7887e 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..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 { @@ -66,7 +67,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(); diff --git a/sql/debug_sync.h b/sql/debug_sync.h index 339a21139b1..999667b9efc 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -44,7 +44,6 @@ 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, size_t len); extern uchar *debug_sync_value_ptr(THD *thd); 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; diff --git a/sql/field.cc b/sql/field.cc index 36a5daaa165..c684e6a8046 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1503,10 +1503,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) @@ -1521,12 +1523,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. @@ -2050,6 +2063,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); } @@ -3048,7 +3062,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 @@ -3056,7 +3071,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; @@ -3085,11 +3101,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; @@ -3100,6 +3119,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) { @@ -3127,9 +3156,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) { @@ -3152,12 +3182,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 @@ -3165,7 +3189,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 08d125d051b..afc9efab57c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1260,11 +1260,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; } bool set_warning(Sql_condition::enum_warning_level, unsigned int code, int cuted_increment) const; @@ -1517,6 +1518,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, @@ -1594,8 +1599,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: bool can_be_substituted_to_equal_item(const Context &ctx, const Item_equal *item_equal); @@ -1619,15 +1626,15 @@ public: { return store(str, length, &my_charset_bin); } - 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; @@ -1815,6 +1822,7 @@ public: } 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); @@ -3172,10 +3180,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) 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); } diff --git a/sql/handler.cc b/sql/handler.cc index d3ad6a085d2..3fbd1b3a71a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4196,6 +4196,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? */ @@ -6113,26 +6114,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(); - ha_info->reset(); /* keep it conveniently zero-filled */ } + + if (unlikely(no_fake_trx_id)) + WSREP_WARN("Cannot get fake transaction ID from storage engine."); + DBUG_VOID_RETURN; } #endif /* WITH_WSREP */ @@ -6326,3 +6343,98 @@ bool HA_CREATE_INFO::check_conflicting_charset_declarations(CHARSET_INFO *cs) } return false; } + +/* 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); +} diff --git a/sql/handler.h b/sql/handler.h index 56c2c87dfd7..cae95ea4ae6 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1,8 +1,8 @@ #ifndef HANDLER_INCLUDED #define HANDLER_INCLUDED /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, Monty Program Ab. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -130,7 +130,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 @@ -144,7 +144,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) @@ -249,6 +249,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 @@ -407,7 +416,9 @@ static const uint MYSQL_START_TRANS_OPT_READ_WRITE = 4; /* 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) +#define HA_CHECK_ALL (~0U) enum legacy_db_type { @@ -1935,7 +1946,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; static const HA_ALTER_FLAGS ALTER_ADD_CHECK_CONSTRAINT = 1LL << 32; @@ -2953,7 +2967,10 @@ public: ((flags & HA_CHECK_DUP_KEY) && (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)) || - error == HA_ERR_AUTOINC_ERANGE) + error == HA_ERR_AUTOINC_ERANGE || + ((flags & HA_CHECK_FK_ERROR) && + (error == HA_ERR_ROW_IS_REFERENCED || + error == HA_ERR_NO_REFERENCED_ROW))) return FALSE; return TRUE; } @@ -4300,4 +4317,7 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name) void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag); void print_keydup_error(TABLE *table, KEY *key, myf errflag); -#endif + +int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info); +int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table); +#endif /* HANDLER_INCLUDED */ diff --git a/sql/item.cc b/sql/item.cc index 99034d849ec..65b8cf25c9b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -202,9 +202,6 @@ bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime, */ 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; @@ -212,11 +209,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; } @@ -1246,8 +1247,8 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) to it's possible that the converter will not be needed at all: PREPARE stmt FROM 'SELECT * FROM t1 WHERE field = ?'; - SET @@arg= 1; - EXECUTE stms USING @arg; + SET @arg= 1; + EXECUTE stmt USING @arg; In the above example result_type is STRING_RESULT at prepare time, and INT_RESULT at execution time. @@ -3783,7 +3784,7 @@ Item_param::eq(const Item *item, 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('?'); } @@ -6716,7 +6717,8 @@ Item *Item_field::update_value_transformer(THD *thd, 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)) { print_value(str); return; diff --git a/sql/item.h b/sql/item.h index 31d87b9f8e4..e5b71eb1845 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2590,7 +2590,7 @@ public: max_length= 0; name= name_par ? name_par : (char*) "NULL"; fixed= 1; - collation.set(cs, DERIVATION_IGNORABLE); + collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } enum Type type() const { return NULL_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return null_eq(item); } @@ -5126,7 +5126,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) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 2d38e705b0a..eafb6b1c91b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -120,10 +120,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]); /* When aggregating types of two row expressions we have to check @@ -135,6 +136,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; } @@ -2328,10 +2335,7 @@ bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, uint fuzzydate) DBUG_ASSERT(fixed == 1); if (!args[0]->get_date_with_conversion(ltime, fuzzydate & ~TIME_FUZZY_DATES)) return (null_value= false); - if (!args[1]->get_date_with_conversion(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_with_conversion(ltime, fuzzydate & ~TIME_FUZZY_DATES)); } @@ -2497,6 +2501,23 @@ void Item_func_nullif::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, } +bool Item_func_nullif::walk(Item_processor processor, + bool walk_subquery, void *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) @@ -2507,7 +2528,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); } } @@ -3361,16 +3389,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_with_conversion(ltime, - fuzzydate & ~TIME_FUZZY_DATES); - if (!args[i]->null_value) - return res; + if (!args[i]->get_date_with_conversion(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); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c1140b61efb..3285b5c6d50 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1028,6 +1028,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, void *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); @@ -1039,13 +1040,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; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index c98630e0431..7f8c89cc228 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6246,6 +6246,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++) { diff --git a/sql/item_func.h b/sql/item_func.h index 474f7b802c0..8316bb72c7d 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. - Copyright (c) 2009, 2014, MariaDB +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -209,7 +209,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.cc b/sql/item_geofunc.cc index 39d06fd7a26..bc4bde575b0 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,6 +1,5 @@ -/* - Copyright (c) 2003-2007 MySQL AB, 2009, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2003, 2016, Oracle and/or its affiliates. + Copyright (c) 2011, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 5a0a26ea779..93d52013e89 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,8 +1,8 @@ #ifndef ITEM_GEOFUNC_INCLUDED #define ITEM_GEOFUNC_INCLUDED -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. - Copyright (C) 2011, 2015 MariaDB +/* Copyright (c) 2000, 2016 Oracle and/or its affiliates. + Copyright (C) 2011, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -259,7 +259,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/item_strfunc.cc b/sql/item_strfunc.cc index b1d59c6170a..76ae66b9cfe 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -814,9 +814,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); @@ -909,9 +910,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); @@ -3568,7 +3570,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; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 28d33ac4f7c..8bb12ce0ac8 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -86,7 +86,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) { @@ -105,7 +104,7 @@ void Item_subselect::init(st_select_lex *select_lex, Item can be changed in JOIN::prepare while engine in JOIN::optimize => we do not copy old_engine here */ - thd->change_item_tree((Item**)&unit->item, this); + unit->thd->change_item_tree((Item**)&unit->item, this); engine->change_result(this, result, TRUE); } } @@ -120,9 +119,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(); @@ -239,6 +238,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); @@ -261,7 +264,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; @@ -565,22 +568,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()) @@ -3163,9 +3178,12 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { uint outer_cols_num; List<Item> *inner_cols; - char const *save_where= thd->where; + char const *save_where= thd_arg->where; DBUG_ENTER("Item_in_subselect::fix_fields"); + thd= thd_arg; + DBUG_ASSERT(unit->thd == thd); + if (test_strategy(SUBS_SEMI_JOIN)) DBUG_RETURN( !( (*ref)= new (thd->mem_root) Item_int(thd, 1)) ); @@ -3282,7 +3300,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); @@ -3399,10 +3418,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) { @@ -3483,10 +3502,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; @@ -3519,10 +3538,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(); @@ -3550,12 +3570,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); @@ -5012,13 +5033,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); } @@ -5393,7 +5415,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, @@ -5402,6 +5424,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)) { @@ -5419,13 +5442,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; @@ -5874,14 +5898,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<Item> *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), @@ -6494,7 +6518,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, @@ -6502,7 +6526,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 bec04813bcf..c39735384ed 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -754,7 +754,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; @@ -762,7 +762,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; @@ -773,7 +772,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 @@ -828,11 +827,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(); @@ -862,11 +861,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(); @@ -919,11 +918,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; } @@ -1051,7 +1050,7 @@ public: subselect_hash_sj_engine(THD *thd_arg, Item_subselect *in_predicate, subselect_single_select_engine *old_engine) - : subselect_engine(thd_arg, 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), @@ -1061,7 +1060,7 @@ public: bool init(List<Item> *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() @@ -1340,15 +1339,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<Item> *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; } @@ -1435,8 +1433,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, @@ -1444,7 +1441,7 @@ public: Item_subselect *item_arg, select_result_interceptor *result_arg, List<Item> *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, @@ -1463,8 +1460,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<Item> *equi_join_conds_arg, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 69eb3d63dd8..a4a694fe5eb 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -939,9 +939,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; @@ -1086,9 +1085,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/lex.h b/sql/lex.h index 0aaec5ffdda..d1762b2b20e 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -47,12 +47,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/log.cc b/sql/log.cc index 39f001af554..fa8f10e5464 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify diff --git a/sql/log.h b/sql/log.h index 40e9e4fdc58..a74a01f9c67 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab +/* Copyright (c) 2005, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/log_event.cc b/sql/log_event.cc index dfd84b99d49..b1cf6a9024a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -3743,10 +3743,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 @@ -9835,9 +9850,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) /* 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. */ { @@ -9856,10 +9868,37 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) NOTE: The base tables are added here are removed when close_thread_tables is called. */ - RPL_TABLE_LIST *ptr= rgi->tables_to_lock; - for (uint i= 0 ; ptr && (i < rgi->tables_to_lock_count); - ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rgi->tables_to_lock; + for (uint i=0 ; table_list_ptr && (i < rgi->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<RPL_TABLE_LIST*>(table_list_ptr); DBUG_ASSERT(ptr->m_tabledef_valid); TABLE *conv_table; if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table)) @@ -9901,6 +9940,12 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) TABLE_LIST *ptr= rgi->tables_to_lock; for (uint i=0 ; ptr && (i < rgi->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; rgi->m_table_map.set_table(ptr->table_id, ptr->table); /* Following is passing flag about triggers on the server. The problem was diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index ff2f7b156d5..0502f20d2b1 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. +/* Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -120,16 +120,25 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, rpl_group_info *rgi) /* 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= rgi->tables_to_lock; - for (uint i= 0 ; ptr&& (i< rgi->tables_to_lock_count); - ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rgi->tables_to_lock; + for (uint i=0 ; table_list_ptr&& (i< rgi->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<RPL_TABLE_LIST*>(table_list_ptr); DBUG_ASSERT(ptr->m_tabledef_valid); TABLE *conv_table; if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table)) @@ -162,7 +171,15 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, rpl_group_info *rgi) */ TABLE_LIST *ptr= rgi->tables_to_lock; for (uint i=0; ptr && (i < rgi->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; rgi->m_table_map.set_table(ptr->table_id, ptr->table); + } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock); #endif @@ -1420,16 +1437,25 @@ int Old_rows_log_event::do_apply_event(rpl_group_info *rgi) /* 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= rgi->tables_to_lock; - for (uint i= 0 ; ptr&& (i< rgi->tables_to_lock_count); - ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++) + TABLE_LIST *table_list_ptr= rgi->tables_to_lock; + for (uint i=0; table_list_ptr&& (i< rgi->tables_to_lock_count); + table_list_ptr= static_cast<RPL_TABLE_LIST*>(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<RPL_TABLE_LIST*>(table_list_ptr); TABLE *conv_table; if (ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table)) { 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<typename Element_type, bool has_trivial_destructor> 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/mysqld.cc b/sql/mysqld.cc index 7173ee66959..fa8f143335d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -290,7 +290,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= { @@ -4271,14 +4271,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); @@ -9214,6 +9206,7 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) log_error_file_ptr= const_cast<char*>(""); break; 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 @@ -9307,6 +9300,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 a49778db012..6783eeff810 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. + Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -639,6 +639,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 @@ -686,7 +690,12 @@ enum enum_query_type /// Be more detailed than QT_EXPLAIN. /// Perhaps we should eventually include QT_ITEM_IDENT_SKIP_CURRENT_DATABASE /// here, as it would give better readable results - QT_EXPLAIN_EXTENDED= QT_TO_SYSTEM_CHARSET + QT_EXPLAIN_EXTENDED= QT_TO_SYSTEM_CHARSET, + + // 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), }; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 08c93d3a6ed..bd191f715e0 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -255,12 +255,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 @@ -268,7 +275,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<SEL_ARG *, true> keys; + key_map keys_map; /* bitmask of non-NULL elements in keys */ /* @@ -578,7 +586,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)) @@ -787,7 +795,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; @@ -3022,9 +3033,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)); @@ -3069,11 +3078,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; @@ -3081,10 +3091,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; + } } } @@ -4948,8 +4958,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(); @@ -6726,8 +6736,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 */ @@ -6750,9 +6760,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; @@ -6760,14 +6771,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); @@ -6781,7 +6792,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) @@ -6795,6 +6806,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; } @@ -6805,17 +6817,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)); } } @@ -7104,7 +7115,7 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param, DBUG_RETURN(NULL); } SEL_TREE *tree2; - for (; i < array->count; i++) + for (; i < array->used_count; i++) { if (array->compare_elems(i, i-1)) { @@ -7443,9 +7454,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); } @@ -7471,7 +7484,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)); } @@ -7589,7 +7603,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)) { @@ -8552,14 +8567,31 @@ 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())) - 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; + result->keys_map.clear_all(); + } + 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) @@ -8576,7 +8608,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()) @@ -14381,16 +14419,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)) { 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); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 55c6c075f48..a835c5824ff 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2247,7 +2247,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); /* @@ -3349,7 +3350,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); @@ -3365,8 +3366,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/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index fad639a5ec5..f440b9b3a3d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6138,7 +6138,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 @@ -6508,8 +6508,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/slave.cc b/sql/slave.cc index 27825c431d3..d83bafa5b3d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2016, MariaDB Corporation +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1358,6 +1358,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; } @@ -4345,7 +4349,8 @@ int check_temp_dir(char* tmp_file) mysql_mutex_lock(&LOCK_start_thread); 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; @@ -4380,7 +4385,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_start_thread); DBUG_RETURN(result); } @@ -4660,11 +4664,14 @@ pthread_handler_t handle_slave_sql(void *arg) 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)) diff --git a/sql/slave.h b/sql/slave.h index ca89064d773..7f412c1091c 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -1,5 +1,5 @@ -/* - Copyright (c) 2000, 2010, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 06a2022d914..6b048cec68b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2013, Monty Program Ab + Copyright (c) 2002, 2016, Oracle and/or its affiliates. + Copyright (c) 2011, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -514,8 +514,10 @@ 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); + DBUG_ASSERT(ident->str); + + if (!ident->str[0] || ident->str[ident->length-1] == ' ') { my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fde894c0cf6..37e6e769a89 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -742,9 +742,8 @@ static ACL_USER *find_user_wild(const char *host, const char *user, const char * static ACL_ROLE *find_acl_role(const char *user); static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_STRING *u, const LEX_STRING *h, const LEX_STRING *r); static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host); -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); static bool acl_load(THD *thd, TABLE_LIST *tables); static bool grant_load(THD *thd, TABLE_LIST *tables); static inline void get_grantor(THD *thd, char* grantor); @@ -897,7 +896,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<LEX_STRING *>(&empty_lex_str) }; if (plugin_foreach(NULL, do_validate, MariaDB_PASSWORD_VALIDATION_PLUGIN, &data)) { @@ -1203,7 +1204,6 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) grant_version++; /* Privileges updated */ init_sql_alloc(&acl_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); - (void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST), 20, 50, MYF(0)); if ((table= tables[HOST_TABLE].table)) // "host" table may not exist (e.g. in MySQL 5.6.7+) { if (init_read_record(&read_record_info, thd, table, NULL, NULL, @@ -1265,10 +1265,6 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) NULL, 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); username_char_length= MY_MIN(table->field[1]->char_length(), USERNAME_CHAR_LENGTH); @@ -1527,7 +1523,6 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) NULL, NULL, 1, 1, FALSE)) goto end; table->use_all_columns(); - (void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB), 50, 100, MYF(0)); while (!(read_record_info.read_record(&read_record_info))) { ACL_DB db; @@ -1589,8 +1584,6 @@ static 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, MYF(0)); if ((table= tables[PROXIES_PRIV_TABLE].table)) { if (init_read_record(&read_record_info, thd, table, @@ -1627,10 +1620,7 @@ static bool acl_load(THD *thd, TABLE_LIST *tables) FALSE)) goto end; table->use_all_columns(); - /* account for every role mapping */ - (void) my_hash_init2(&acl_roles_mappings, 50, system_charset_info, 0, 0, 0, - (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); MEM_ROOT temp_root; init_alloc_root(&temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); while (!(read_record_info.read_record(&read_record_info))) @@ -1669,6 +1659,7 @@ static 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); } @@ -1685,12 +1676,12 @@ void acl_free(bool end) delete_dynamic(&acl_proxy_users); my_hash_free(&acl_check_hosts); my_hash_free(&acl_roles_mappings); - 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; } @@ -1752,6 +1743,15 @@ bool acl_reload(THD *thd) old_acl_roles_mappings= acl_roles_mappings; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; + my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); + my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); + my_init_dynamic_array(&acl_dbs, sizeof(ACL_DB), 50, 100, MYF(0)); + my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); + 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); + my_hash_init2(&acl_roles_mappings, 50, system_charset_info, 0, 0, 0, + (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); old_mem= acl_memroot; delete_dynamic(&acl_wild_hosts); my_hash_free(&acl_check_hosts); @@ -2034,7 +2034,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); @@ -3459,7 +3459,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 */ @@ -7378,8 +7378,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]) { @@ -7393,11 +7392,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. */ @@ -7405,7 +7403,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 */ @@ -7641,7 +7639,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); @@ -7813,23 +7812,71 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role) } +/** checks privileges for SHOW GRANTS and SHOW CREATE USER + + @note that in case of SHOW CREATE USER the parser guarantees + that a role can never happen here, so *rolename will never + be assigned to +*/ +static bool check_show_access(THD *thd, LEX_USER *lex_user, char **username, + char **hostname, char **rolename) +{ + DBUG_ENTER("check_show_access"); + + if (lex_user->user.str == current_user.str) + { + *username= thd->security_ctx->priv_user; + *hostname= thd->security_ctx->priv_host; + } + else if (lex_user->user.str == current_role.str) + { + *rolename= thd->security_ctx->priv_role; + } + else if (lex_user->user.str == current_user_and_current_role.str) + { + *username= thd->security_ctx->priv_user; + *hostname= thd->security_ctx->priv_host; + *rolename= thd->security_ctx->priv_role; + } + else + { + Security_context *sctx= thd->security_ctx; + bool do_check_access; + + lex_user= get_current_user(thd, lex_user); + if (!lex_user) + 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_RETURN(FALSE); +} bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) { - const char *username = safe_str(lex_user->user.str); - const char *hostname = safe_str(lex_user->host.str); + char *username= NULL, *hostname= NULL; char buff[1024]; //Show create user should not take more than 1024 bytes. Protocol *protocol= thd->protocol; bool error= false; ACL_USER *acl_user; DBUG_ENTER("mysql_show_create_user"); - // Check if the command specifies a username or not. - if (lex_user->user.str == current_user.str) - { - username= thd->security_ctx->priv_user; - hostname= thd->security_ctx->priv_host; - } + if (check_show_access(thd, lex_user, &username, &hostname, NULL)) + DBUG_RETURN(TRUE); List<Item> field_list; strxmov(buff, "CREATE USER for ", username, "@", hostname, NullS); @@ -7918,9 +7965,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) ACL_ROLE *acl_role= NULL; char buff[1024]; Protocol *protocol= thd->protocol; - char *username= NULL; - char *hostname= NULL; - char *rolename= NULL; + char *username= NULL, *hostname= NULL, *rolename= NULL; DBUG_ENTER("mysql_show_grants"); if (!initialized) @@ -7929,44 +7974,8 @@ 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; - hostname= thd->security_ctx->priv_host; - } - else if (lex_user->user.str == current_role.str) - { - rolename= thd->security_ctx->priv_role; - } - else if (lex_user->user.str == current_user_and_current_role.str) - { - username= thd->security_ctx->priv_user; - hostname= thd->security_ctx->priv_host; - rolename= thd->security_ctx->priv_role; - } - else - { - lex_user= get_current_user(thd, lex_user, false); - 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; - } - else - { - username= lex_user->user.str; - hostname= lex_user->host.str; - } - } + if (check_show_access(thd, lex_user, &username, &hostname, &rolename)) + DBUG_RETURN(TRUE); DBUG_ASSERT(rolename || username); List<Item> field_list; @@ -7978,14 +7987,11 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) mysql_show_grants_get_fields(thd, &field_list, buff); 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); - + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - } + + mysql_rwlock_rdlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); if (username) { @@ -12342,6 +12348,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; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index e76e5d830c9..578b78d8f35 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -384,9 +384,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; @@ -486,6 +490,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) { @@ -524,7 +542,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } } #endif - } DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table)); if (prepare_func) @@ -625,18 +642,18 @@ 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. + + 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)) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f4af7dae207..3481bf1a2d3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7741,7 +7741,8 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &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 && diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 251f3eadfd8..9710ea8bbe3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2030,46 +2030,63 @@ 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()) + for (TABLE *thd_table= in_use->open_tables; + thd_table ; + thd_table= thd_table->next) { - signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (this && WSREP(this) && wsrep_thd_is_BF(this, FALSE)) + /* + 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()) { - WSREP_DEBUG("remove_table_from_cache: %llu", - (unsigned long long) this->real_id); - wsrep_abort_thd((void *)this, (void *)in_use, FALSE); + signalled|= mysql_lock_abort_for_thread(this, thd_table); + if (this && WSREP(this) && wsrep_thd_is_BF(this, FALSE)) + { + WSREP_DEBUG("remove_table_from_cache: %llu", + (unsigned long long) this->real_id); + wsrep_abort_thd((void *)this, (void *)in_use, FALSE); + } } } } mysql_mutex_unlock(&in_use->LOCK_thd_data); } - return signalled; + DBUG_RETURN(signalled); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 0b952203a6c..0318b6a249c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -2280,6 +2280,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()); + } enum binlog_filter_state { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7869f7f540c..fe6a101f999 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1165,7 +1165,8 @@ void end_connection(THD *thd) } if (!thd->killed && (net->error && net->vio != 0)) - thd->print_aborted_warning(1, ER_THD(thd, ER_UNKNOWN_ERROR)); + thd->print_aborted_warning(1, thd->get_stmt_da()->is_error() + ? thd->get_stmt_da()->message() : ER_THD(thd, ER_UNKNOWN_ERROR)); } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index a50b90fc111..1ddddaf1b40 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -672,7 +672,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; @@ -854,3 +854,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/sql_insert.cc b/sql/sql_insert.cc index fcfac2ed6af..d237360190e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -1607,9 +1607,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)) + 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) { /* @@ -1730,7 +1731,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)) + !table->file->is_fatal_error(error, HA_CHECK_ALL)) { if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) @@ -1860,7 +1861,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_ALL)) goto err; if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) @@ -1990,7 +1991,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; bool retry; /** @@ -2676,14 +2677,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<Delayed_insert> 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); @@ -2704,6 +2707,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; } @@ -2905,6 +2909,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); + di->table->mark_columns_needed_for_insert(); /* Now wait until we get an insert or lock to handle */ @@ -2915,6 +2925,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 @@ -2925,11 +2936,15 @@ 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 } /* 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; @@ -2969,6 +2984,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) { @@ -3029,9 +3047,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 diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f83fd4cef3d..638f6832355 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1691,32 +1691,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_load.cc b/sql/sql_load.cc index 951022e5085..b1167534491 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -348,6 +348,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. diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 5ac069de98b..58443a9a977 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -427,7 +427,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] = diff --git a/sql/sql_locale.h b/sql/sql_locale.h index e231393eec6..ec2f3d29e15 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 */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 63b44c53f94..5ff0bd98dba 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5335,27 +5335,21 @@ end_with_restore_list: #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_SHOW_CREATE_USER: - 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; + res = mysql_show_create_user(thd, grant_user); + break; + } + case SQLCOM_SHOW_GRANTS: + { + LEX_USER *grant_user= lex->grant_user; + if (!grant_user) + goto error; - 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)) - { - if (lex->sql_command == SQLCOM_SHOW_GRANTS) - res = mysql_show_grants(thd, grant_user); - else - res = mysql_show_create_user(thd, grant_user); - } + res = mysql_show_grants(thd, grant_user); break; } #endif @@ -7063,6 +7057,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. @@ -7071,7 +7066,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> key_iterator(alter_info->key_list); @@ -7111,10 +7107,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) @@ -9327,7 +9341,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; /* diff --git a/sql/sql_parse.h b/sql/sql_parse.h index aa8d0813870..ad29bb2cdd3 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -49,7 +49,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, Object_creation_ctx *creation_ctx, bool do_pfs_digest=false); diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 2bfdcb29dfc..efa48b22ce8 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -152,7 +152,7 @@ typedef int (*plugin_type_init)(struct st_plugin_int *); extern I_List<i_string> *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; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 5ac58f8cda7..40349d3802a 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -225,7 +225,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_reload.cc b/sql/sql_reload.cc index 25d4d93d75f..2fef615831b 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. + Copyright (c) 2011, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bb68c44087b..cde2cc43b0f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015 Oracle and/or its affiliates. +/* Copyright (c) 2000, 2016 Oracle and/or its affiliates. Copyright (c) 2009, 2016 MariaDB This program is free software; you can redistribute it and/or modify @@ -12215,7 +12215,50 @@ 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 (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) + { + table_map first_table_bit= + join->join_tab[join->const_tables].table->map; + + Item *item= order->item[0]; + + /* + 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); + Item_equal *item_eq; + if ((item_eq= res->get_item_equal())) + { + 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 + } } } } @@ -14315,6 +14358,8 @@ simplify_joins(JOIN *join, List<TABLE_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. */ @@ -15725,7 +15770,7 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) new_field= tmp_table_field_from_field_type(table, true, false); else new_field= make_string_field(table); - new_field->set_derivation(collation.derivation); + new_field->set_derivation(collation.derivation, collation.repertoire); break; case DECIMAL_RESULT: new_field= Field_new_decimal::create_from_item(mem_root, this); @@ -15992,7 +16037,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, modify_item); 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; @@ -20366,6 +20412,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 @@ -20388,7 +20436,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; @@ -20411,7 +20460,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; /* @@ -20453,6 +20503,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); @@ -20582,7 +20643,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; @@ -20721,6 +20782,71 @@ 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); + + if (!optimizer_flag(join->thd, OPTIMIZER_SWITCH_ORDERBY_EQ_PROP)) + return; + + 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<Item_equal> 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. @@ -20777,7 +20903,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 } @@ -20935,7 +21081,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; } @@ -24594,33 +24740,53 @@ static void print_join(THD *thd, /* List is reversed => we should reverse it before using */ List_iterator_fast<TABLE_LIST> ti(*tables); TABLE_LIST **table; - uint non_const_tables= 0; DBUG_ENTER("print_join"); + /* + 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++) { - /* - See comment in print_table_array() about the second part of the - condition - */ - if (!t->optimized_away && !is_eliminated_table(eliminated_tables, t)) - non_const_tables++; + /* See comment in print_table_array() about the second condition */ + if (print_const_tables || !t->optimized_away) + if (!is_eliminated_table(eliminated_tables, t)) + tables_to_print++; } - if (!non_const_tables) + if (tables_to_print == 0) { str->append(STRING_WITH_LEN("dual")); DBUG_VOID_RETURN; // all tables were optimized away } ti.rewind(); - if (!(table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) * - non_const_tables))) + if (!(table= static_cast<TABLE_LIST **>(thd->alloc(sizeof(TABLE_LIST*) * + tables_to_print)))) DBUG_VOID_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 || is_eliminated_table(eliminated_tables, tmp)) + if (tmp->optimized_away && !print_const_tables) + continue; + if (is_eliminated_table(eliminated_tables, tmp)) continue; *t--= tmp; } @@ -24640,7 +24806,7 @@ static void print_join(THD *thd, */ if ((*table)->sj_inner_tables) { - TABLE_LIST **end= table + non_const_tables; + TABLE_LIST **end= table + tables_to_print; for (TABLE_LIST **t2= table; t2!=end; t2++) { if (!(*t2)->sj_inner_tables) @@ -24653,7 +24819,7 @@ static void print_join(THD *thd, } } print_table_array(thd, eliminated_tables, str, table, - table + non_const_tables, query_type); + table + tables_to_print, query_type); DBUG_VOID_RETURN; } @@ -25076,7 +25242,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<TABLE_LIST> it(select_lex->sj_nests); @@ -25504,7 +25670,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 @@ -25747,7 +25914,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 d4dc691c547..92ba74fac35 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1939,8 +1939,6 @@ 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 *sortorder); int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List<Item> &fields, List <Item> &all_fields, ORDER *order, bool search_in_all_fields= true); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5176bcbbc00..30c65e6e279 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -815,12 +815,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. @@ -829,6 +841,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; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index f6811b020eb..83c7db8b510 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -30,6 +30,7 @@ #include "opt_range.h" #include "uniques.h" #include "my_atomic.h" +#include "sql_show.h" /* The system variable 'use_stat_tables' can take one of the @@ -3195,6 +3196,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); @@ -3341,6 +3346,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); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 83aae3f5038..cb272402e90 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -37,8 +37,7 @@ #include "sql_time.h" // make_truncated_value_warning #include "records.h" // init_read_record, end_read_record #include "filesort.h" // filesort_free_buffers -#include "sql_select.h" // setup_order, - // make_unireg_sortorder +#include "sql_select.h" // setup_order #include "sql_handler.h" // mysql_ha_rm_tables #include "discover.h" // readfrm #include "my_pthread.h" // pthread_mutex_t @@ -5488,6 +5487,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* We have to write the query before we unlock the tables. */ + if (thd->is_current_stmt_binlog_disabled()) + goto err; + if (thd->is_current_stmt_binlog_format_row()) { /* @@ -5558,6 +5560,21 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, */ if (!table->view) { + /* + 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))= show_create_table(thd, table, &query, create_info, WITH_DB_NAME); @@ -8599,7 +8616,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_info::ADD_FOREIGN_KEY) && - check_fk_parent_table_access(thd, create_info, alter_info)) + check_fk_parent_table_access(thd, create_info, alter_info, new_db)) DBUG_RETURN(true); /* diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 5c20b72930e..d59b8b7e048 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2015, MariaDB +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2011, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -818,7 +818,7 @@ 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_ALL)) { /* If (ignore && error is ignorable) we don't have to @@ -826,7 +826,7 @@ 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_ALL)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); @@ -1593,7 +1593,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<Item> total_list; res= mysql_select(thd, @@ -2140,7 +2140,7 @@ int multi_update::send_data(List<Item> ¬_used_values) { updated--; if (!ignore || - table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) + table->file->is_fatal_error(error, HA_CHECK_ALL)) { /* If (ignore && error == is ignorable) we don't have to @@ -2148,7 +2148,7 @@ int multi_update::send_data(List<Item> ¬_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_ALL)) flags|= ME_FATALERROR; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); @@ -2426,7 +2426,7 @@ 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_ALL)) { err_table= table; goto err; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a1483645002..9d7e735fc78 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -102,6 +102,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 @@ -1245,7 +1248,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 @@ -1297,7 +1299,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 @@ -1377,7 +1378,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_GTID_POS_SYM %token MASTER_HOST_SYM @@ -1749,7 +1749,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 @@ -2110,10 +2110,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; } @@ -2296,10 +2294,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 { @@ -2326,77 +2321,73 @@ 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_SSL_CRL_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CRL_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_crl= $3.str; } - | MASTER_SSL_CRLPATH_SYM EQ TEXT_STRING_sys + | MASTER_SSL_CRLPATH_SYM '=' TEXT_STRING_sys { Lex->mi.ssl_crlpath= $3.str; } - | 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 || 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, @@ -2416,15 +2407,15 @@ 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; } - | DO_DOMAIN_IDS_SYM EQ '(' do_domain_id_list ')' + | DO_DOMAIN_IDS_SYM '=' '(' do_domain_id_list ')' { Lex->mi.repl_do_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } - | IGNORE_DOMAIN_IDS_SYM EQ '(' ignore_domain_id_list ')' + | IGNORE_DOMAIN_IDS_SYM '=' '(' ignore_domain_id_list ')' { Lex->mi.repl_ignore_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } @@ -2472,11 +2463,11 @@ ignore_domain_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 { /* If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it @@ -2491,41 +2482,32 @@ master_file_def: */ Lex->mi.pos= MY_MAX(BIN_LOG_HEADER_SIZE, $3); } - | 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) */ Lex->mi.relay_log_pos= MY_MAX(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); } - | MASTER_USE_GTID_SYM EQ CURRENT_POS_SYM + | MASTER_USE_GTID_SYM '=' 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 + | MASTER_USE_GTID_SYM '=' 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 + | MASTER_USE_GTID_SYM '=' 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; } ; @@ -2545,10 +2527,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 } ; @@ -2859,10 +2838,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; @@ -2901,14 +2877,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; @@ -2924,7 +2895,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); @@ -3029,10 +3000,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); @@ -3100,17 +3068,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; @@ -3175,16 +3135,11 @@ sp_decl: /* The last instruction is responsible for freeing LEX. */ - sp_instr_set *is= (new (lex->thd->mem_root) + sp_instr_set *is= new (lex->thd->mem_root) sp_instr_set(lex->sphead->instructions(), - pctx, - var_idx, - dflt_value_item, - $4.field_type(), - lex, - last)); - if (is == NULL || - lex->sphead->add_instr(is)) + pctx, var_idx, dflt_value_item, + $4.field_type(), lex, last); + if (is == NULL || lex->sphead->add_instr(is)) MYSQL_YYABORT; } @@ -3200,10 +3155,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; @@ -3222,7 +3174,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)) @@ -3246,7 +3198,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)) @@ -3254,7 +3206,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) || @@ -3277,17 +3229,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; @@ -3305,11 +3252,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)) @@ -3338,17 +3281,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); } ; @@ -3356,10 +3292,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; @@ -3379,10 +3312,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; @@ -3403,10 +3333,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??? */ { @@ -3447,23 +3374,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 @@ -3486,7 +3405,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; @@ -3495,17 +3414,14 @@ 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; 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; } ; @@ -3634,7 +3550,7 @@ statement_information: ; statement_information_item: - simple_target_specification EQ statement_information_item_name + simple_target_specification '=' statement_information_item_name { $$= new (thd->mem_root) Statement_information_item($3, $1); if ($$ == NULL) @@ -3691,7 +3607,7 @@ condition_information: ; condition_information_item: - simple_target_specification EQ condition_information_item_name + simple_target_specification '=' condition_information_item_name { $$= new (thd->mem_root) Condition_information_item($3, $1); if ($$ == NULL) @@ -3736,10 +3652,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; } @@ -3751,10 +3664,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; } @@ -3825,11 +3735,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 @@ -3839,7 +3747,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; @@ -3873,22 +3781,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; } @@ -3903,49 +3806,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(thd, 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(thd, i, lab); /* Jumping forward */ + sp->add_instr(i); } ; @@ -3958,40 +3856,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; } ; @@ -4004,11 +3897,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)) @@ -4025,11 +3915,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)) @@ -4048,11 +3935,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)) @@ -4075,17 +3959,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 { @@ -4095,17 +3973,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); } ; @@ -4117,7 +3989,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(thd, i, ctx->push_label(thd, empty_lex_str, 0)) || @@ -4325,10 +4197,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 @@ -4336,10 +4205,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)); } } ; @@ -4393,7 +4259,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)) @@ -4410,7 +4276,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)) @@ -4424,7 +4290,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 */ @@ -4440,7 +4306,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)) @@ -4457,7 +4323,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)) @@ -4478,10 +4344,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)); } } ; @@ -4848,10 +4711,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; } ; @@ -4861,10 +4721,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; } ; @@ -4874,11 +4731,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; } ; @@ -4898,10 +4752,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; } ; @@ -4933,23 +4784,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; } ; @@ -5076,15 +4918,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 } ; @@ -5142,7 +4980,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: @@ -5179,11 +5017,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")); } ; @@ -5224,10 +5059,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; @@ -5264,11 +5096,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")); } ; @@ -5291,10 +5120,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; } @@ -5305,17 +5131,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 ')' { @@ -5385,17 +5205,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; @@ -5407,11 +5221,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; @@ -5424,11 +5235,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; @@ -6042,12 +5850,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); @@ -6102,10 +5914,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, @@ -6122,10 +5931,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)); } ; @@ -6303,10 +6109,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; @@ -6461,12 +6264,9 @@ field_type: int err; ulonglong tmp_length= my_strtoll10($2.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) $$.set(MYSQL_TYPE_DOUBLE); else $$.set(MYSQL_TYPE_FLOAT); @@ -6572,9 +6372,8 @@ field_type: Lex->last_field->geom_type= $1; $$.set(MYSQL_TYPE_GEOMETRY, $2); #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 @@ -6679,7 +6478,7 @@ srid_option: /* empty */ { Lex->last_field->srid= 0; } | - REF_SYSTEM_ID_SYM EQ NUM + REF_SYSTEM_ID_SYM '=' NUM { Lex->last_field->srid=atoi($3.str); } @@ -6780,24 +6579,22 @@ 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 { + 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); @@ -6839,10 +6636,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; } ; @@ -6862,10 +6656,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; } ; @@ -6904,10 +6695,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")); } ; @@ -7123,9 +6911,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 } ; @@ -7184,12 +6971,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); @@ -7223,10 +7014,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)); } ; @@ -7258,9 +7046,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; @@ -7340,10 +7126,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; } @@ -7352,10 +7135,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 @@ -7370,10 +7150,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 @@ -7388,10 +7165,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 @@ -7406,10 +7180,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; } @@ -7897,10 +7668,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; } @@ -7912,15 +7680,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 { @@ -7961,10 +7725,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)); } ; @@ -7977,10 +7738,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)); } ; @@ -8040,7 +7798,7 @@ opt_place: opt_to: /* empty */ {} | TO_SYM {} - | EQ {} + | '=' {} | AS {} ; @@ -8156,13 +7914,9 @@ 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 + | UNTIL_SYM MASTER_GTID_POS_SYM '=' TEXT_STRING_sys { Lex->mi.gtid_pos_str = $4; } @@ -8375,10 +8129,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) @@ -8475,9 +8226,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; } @@ -8839,10 +8590,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")); } ; @@ -8860,26 +8608,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 { @@ -8888,26 +8625,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; } ; @@ -8960,10 +8686,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(thd, $4.str, $4.length, system_charset_info); } @@ -9190,13 +8913,13 @@ bool_pri: if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri comp_op predicate %prec EQ + | bool_pri comp_op predicate %prec '=' { $$= (*$2)(0)->create(thd, $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(thd, $1, $2, $3, $5); if ($$ == NULL) @@ -9420,11 +9143,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; } ; @@ -9631,11 +9354,7 @@ column_default_non_parenthesized_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) @@ -10302,9 +10021,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 } ; @@ -10466,10 +10184,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; @@ -10779,10 +10494,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 { @@ -10974,7 +10686,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; @@ -11237,7 +10949,7 @@ table_primary_derived: 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))) @@ -11592,7 +11304,7 @@ date_time_type: table_alias: /* empty */ | AS - | EQ + | '=' ; opt_table_alias: @@ -11688,14 +11400,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 { @@ -11708,11 +11417,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; } ; @@ -11926,7 +11632,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) @@ -12043,15 +11749,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; } @@ -12172,7 +11872,7 @@ 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); @@ -12256,10 +11956,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->sql_type(), Lex->sphead)) : @@ -12346,7 +12043,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)) @@ -12363,17 +12060,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); @@ -12385,14 +12076,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); @@ -12402,10 +12090,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; } @@ -12661,7 +12346,7 @@ ident_eq_value: ; equal: - EQ {} + '=' {} | SET_VAR {} ; @@ -13439,19 +13124,14 @@ opt_extended_describe: opt_format_json: /* empty */ {} - | FORMAT_SYM EQ ident_or_text + | FORMAT_SYM '=' ident_or_text { 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)); } ; @@ -13548,10 +13228,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; } @@ -13572,10 +13249,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; } @@ -14054,19 +13728,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))); } ; @@ -14348,10 +14016,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) @@ -14427,17 +14092,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 || @@ -14546,26 +14205,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 */ @@ -15202,10 +14852,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(); } @@ -15534,10 +15181,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), @@ -15545,10 +15189,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; @@ -15640,10 +15281,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; @@ -15696,10 +15334,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 @@ -15749,10 +15384,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 @@ -15768,34 +15400,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 */ @@ -15805,7 +15428,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 @@ -15849,11 +15472,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 */ @@ -16011,10 +15634,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; @@ -16109,30 +15729,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; } ; @@ -16147,11 +15758,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 '.' '*' { @@ -16160,11 +15767,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))); } | '*' '.' '*' { @@ -16173,16 +15776,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) @@ -16749,7 +16348,7 @@ no_definer: ; definer: - DEFINER_SYM EQ user_or_role + DEFINER_SYM '=' user_or_role { Lex->definer= $3; Lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; @@ -16765,11 +16364,11 @@ definer: **************************************************************************/ 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; } ; @@ -16897,10 +16496,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; @@ -16957,10 +16553,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; @@ -16983,10 +16576,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; @@ -17029,10 +16619,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)) { /* @@ -17079,10 +16666,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; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 79743dbfc13..db054a635af 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2383,7 +2383,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) @@ -4725,7 +4727,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 ( @@ -4867,7 +4869,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'")); @@ -4877,7 +4880,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/sys_vars.ic b/sql/sys_vars.ic index 2488e804310..ca6634849a1 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -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 diff --git a/sql/table.cc b/sql/table.cc index cee16cd9e77..d4adb5ca356 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3755,18 +3755,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; } @@ -3785,17 +3790,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(); } /* diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc index 91b392eb766..4079091e217 100644 --- a/sql/threadpool_unix.cc +++ b/sql/threadpool_unix.cc @@ -170,6 +170,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; @@ -607,12 +608,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; } @@ -624,6 +625,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; } 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; } 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_mysqld.cc b/sql/wsrep_mysqld.cc index 9f7c3c9baa7..e3b503a82fb 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -564,8 +564,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); @@ -891,6 +889,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 @@ -1268,7 +1269,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; @@ -1364,6 +1365,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 @@ -2173,7 +2178,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; @@ -2487,7 +2492,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 */ diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h index a6e57e33e6d..e2dc526608f 100644 --- a/sql/wsrep_priv.h +++ b/sql/wsrep_priv.h @@ -40,8 +40,12 @@ extern wsrep_uuid_t local_uuid; extern wsrep_seqno_t local_seqno; // a helper function -bool wsrep_sst_received(wsrep_t*, const wsrep_uuid_t&, wsrep_seqno_t, - const void*, size_t, bool const); +bool wsrep_sst_received (wsrep_t* const wsrep, + const wsrep_uuid_t& uuid, + const wsrep_seqno_t seqno, + const void* const state, + const size_t state_len, + const bool implicit); /*! 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_sst.cc b/sql/wsrep_sst.cc index 4fb162f9995..6d0cfc1c43a 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -398,6 +398,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 54235cf5273..e4f421930f4 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 { @@ -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) { diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 1407f715fb4..8e443b573cb 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -384,7 +384,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 |