diff options
Diffstat (limited to 'sql')
59 files changed, 875 insertions, 400 deletions
diff --git a/sql/contributors.h b/sql/contributors.h index f52d3243453..0359ec54022 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -46,6 +46,7 @@ struct show_table_contributors_st show_table_contributors[]= { {"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"}, {"Verkkokauppa.com", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"}, {"Virtuozzo", "https://virtuozzo.com/", "Bronze Sponsor of the MariaDB Foundation"}, + {"Tencent Game DBA", "http://tencentdba.com/about/", "Bronze Sponsor of the MariaDB Foundation"}, /* Sponsors of important features */ {"Google", "USA", "Sponsoring encryption, parallel replication and GTID"}, diff --git a/sql/encryption.cc b/sql/encryption.cc index 52aaef896dd..a92296e8b66 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -29,6 +29,10 @@ uint no_key(uint) { return ENCRYPTION_KEY_VERSION_INVALID; } +uint zero_size(uint,uint) +{ + return 0; +} static int ctx_init(void *ctx, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, @@ -97,6 +101,7 @@ int finalize_encryption_plugin(st_plugin_int *plugin) encryption_handler.encryption_key_get_func= (uint (*)(uint, uint, uchar*, uint*))no_key; encryption_handler.encryption_key_get_latest_version_func= no_key; + encryption_handler.encryption_ctx_size_func= zero_size; if (plugin && plugin->plugin->deinit && plugin->plugin->deinit(NULL)) { diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 9de55c44dd0..c96060cd5df 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -166,20 +166,8 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] = static const TABLE_FIELD_DEF event_table_def= {ET_FIELD_COUNT, event_table_fields, 0, (uint*) 0}; -class Event_db_intact : public Table_check_intact -{ -protected: - void report_error(uint, const char *fmt, ...) - { - va_list args; - va_start(args, fmt); - error_log_print(ERROR_LEVEL, fmt, args); - va_end(args); - } -}; - /** In case of an error, a message is printed to the error log. */ -static Event_db_intact table_intact; +static Table_check_intact_log_error table_intact; /** diff --git a/sql/field.cc b/sql/field.cc index 673bf22a4a5..8d53fca27d7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -355,7 +355,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP MYSQL_TYPE_LONGLONG, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24 - MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONG, + MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONGLONG, //MYSQL_TYPE_DATE MYSQL_TYPE_TIME MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR diff --git a/sql/handler.cc b/sql/handler.cc index 37e60f5c9bd..a91a97598d6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5926,6 +5926,10 @@ static int check_wsrep_max_ws_rows() if (wsrep_max_ws_rows) { THD *thd= current_thd; + + if (!WSREP(thd)) + return 0; + thd->wsrep_affected_rows++; if (thd->wsrep_exec_mode != REPL_RECV && thd->wsrep_affected_rows > wsrep_max_ws_rows) diff --git a/sql/hostname.cc b/sql/hostname.cc index a84aebdf3c8..e8d6780d095 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -28,7 +28,6 @@ #include "sql_priv.h" #include "unireg.h" // SPECIAL_NO_HOST_CACHE #include "hostname.h" -#include "unireg.h" #ifndef __WIN__ #include <netdb.h> // getservbyname, servent #endif diff --git a/sql/item.cc b/sql/item.cc index 6d9274759e4..682f88317f1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2879,9 +2879,28 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) if (context) { Name_resolution_context *ctx= new Name_resolution_context(); - ctx->outer_context= NULL; // We don't build a complete name resolver - ctx->table_list= NULL; // We rely on first_name_resolution_table instead + if (context->select_lex == new_parent) + { + /* + This field was pushed in then pulled out + (for example left part of IN) + */ + ctx->outer_context= context->outer_context; + } + else if (context->outer_context) + { + /* just pull to the upper context */ + ctx->outer_context= context->outer_context->outer_context; + } + else + { + /* No upper context (merging Derived/VIEW where context chain ends) */ + ctx->outer_context= NULL; + } + ctx->table_list= context->first_name_resolution_table; ctx->select_lex= new_parent; + if (context->select_lex == NULL) + ctx->select_lex= NULL; ctx->first_name_resolution_table= context->first_name_resolution_table; ctx->last_name_resolution_table= context->last_name_resolution_table; ctx->error_processor= context->error_processor; @@ -4710,8 +4729,6 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) const char *field_name; ORDER *found_group= NULL; int found_match_degree= 0; - Item_ident *cur_field; - int cur_match_degree= 0; char name_buff[SAFE_NAME_LEN+1]; if (find_item->type() == Item::FIELD_ITEM || @@ -4736,54 +4753,70 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next) { - if ((*(cur_group->item))->real_item()->type() == Item::FIELD_ITEM) + int cur_match_degree= 0; + + /* SELECT list element with explicit alias */ + if ((*(cur_group->item))->name && + !(*(cur_group->item))->is_autogenerated_name && + !my_strcasecmp(system_charset_info, + (*(cur_group->item))->name, field_name)) { - cur_field= (Item_ident*) *cur_group->item; - cur_match_degree= 0; - - DBUG_ASSERT(cur_field->field_name != 0); + ++cur_match_degree; + } + /* Reference on the field or view/derived field. */ + else if ((*(cur_group->item))->type() == Item::FIELD_ITEM || + (*(cur_group->item))->type() == Item::REF_ITEM ) + { + Item_ident *cur_field= (Item_ident*) *cur_group->item; + const char *l_db_name= cur_field->db_name; + const char *l_table_name= cur_field->table_name; + const char *l_field_name= cur_field->field_name; + + DBUG_ASSERT(l_field_name != 0); if (!my_strcasecmp(system_charset_info, - cur_field->field_name, field_name)) + l_field_name, field_name)) ++cur_match_degree; else continue; - if (cur_field->table_name && table_name) + if (l_table_name && table_name) { /* If field_name is qualified by a table name. */ - if (my_strcasecmp(table_alias_charset, cur_field->table_name, table_name)) + if (my_strcasecmp(table_alias_charset, l_table_name, table_name)) /* Same field names, different tables. */ return NULL; ++cur_match_degree; - if (cur_field->db_name && db_name) + if (l_db_name && db_name) { /* If field_name is also qualified by a database name. */ - if (strcmp(cur_field->db_name, db_name)) + if (strcmp(l_db_name, db_name)) /* Same field names, different databases. */ return NULL; ++cur_match_degree; } } + } + else + continue; - if (cur_match_degree > found_match_degree) - { - found_match_degree= cur_match_degree; - found_group= cur_group; - } - else if (found_group && (cur_match_degree == found_match_degree) && - ! (*(found_group->item))->eq(cur_field, 0)) - { - /* - If the current resolve candidate matches equally well as the current - best match, they must reference the same column, otherwise the field - is ambiguous. - */ - my_error(ER_NON_UNIQ_ERROR, MYF(0), - find_item->full_name(), current_thd->where); - return NULL; - } + if (cur_match_degree > found_match_degree) + { + found_match_degree= cur_match_degree; + found_group= cur_group; + } + else if (found_group && (cur_match_degree == found_match_degree) && + !(*(found_group->item))->eq((*(cur_group->item)), 0)) + { + /* + If the current resolve candidate matches equally well as the current + best match, they must reference the same column, otherwise the field + is ambiguous. + */ + my_error(ER_NON_UNIQ_ERROR, MYF(0), + find_item->full_name(), current_thd->where); + return NULL; } } @@ -5832,6 +5865,7 @@ String *Item::check_well_formed_result(String *str, bool send_error) /* Check whether we got a well-formed string */ CHARSET_INFO *cs= str->charset(); uint wlen= str->well_formed_length(); + null_value= false; if (wlen < str->length()) { THD *thd= current_thd; diff --git a/sql/item.h b/sql/item.h index 5b3c3a6a0d5..1f3e0f02971 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4456,7 +4456,7 @@ public: if (result_type() == ROW_RESULT) orig_item->bring_value(); } - virtual bool is_expensive() { return orig_item->is_expensive(); } + bool is_expensive() { return orig_item->is_expensive(); } bool is_expensive_processor(void *arg) { return orig_item->is_expensive_processor(arg); } bool check_vcol_func_processor(void *arg) @@ -5119,6 +5119,8 @@ public: return false; } table_map used_tables() const { return (table_map)0L; } + Field *get_tmp_table_field() { return 0; } + Item *get_tmp_table_item(THD *thd) { return this; } Item_field *field_for_view_update() { return 0; } bool update_vcol_processor(void *arg) { return 0; } bool check_func_default_processor(void *arg) { return true; } @@ -5195,6 +5197,8 @@ public: */ table_map used_tables() const { return RAND_TABLE_BIT; } + Item_field *field_for_view_update() { return 0; } + bool walk(Item_processor processor, bool walk_subquery, void *args) { return arg->walk(processor, walk_subquery, args) || diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9891d117912..2856cea0697 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2538,7 +2538,7 @@ Item_func_nullif::fix_length_and_dec() See also class Item_func_nullif declaration. */ if (arg_count == 2) - args[arg_count++]= args[0]; + args[arg_count++]= m_arg0 ? m_arg0 : args[0]; THD *thd= current_thd; /* @@ -2689,7 +2689,47 @@ Item_func_nullif::fix_length_and_dec() unsigned_flag= args[2]->unsigned_flag; fix_char_length(args[2]->max_char_length()); maybe_null=1; + m_arg0= args[0]; setup_args_and_comparator(thd, &cmp); + /* + A special code for EXECUTE..PREPARE. + + If args[0] did not change, then we don't remember it, as it can point + to a temporary Item object which will be destroyed between PREPARE + and EXECUTE. EXECUTE time fix_length_and_dec() will correctly set args[2] + from args[0] again. + + If args[0] changed, then it can be Item_func_conv_charset() for the + original args[0], which was permanently installed during PREPARE time + into the item tree as a wrapper for args[0], using change_item_tree(), i.e. + + NULLIF(latin1_field, 'a' COLLATE utf8_bin) + + was "rewritten" to: + + CASE WHEN CONVERT(latin1_field USING utf8) = 'a' COLLATE utf8_bin + THEN NULL + ELSE latin1_field + + - m_args0 points to Item_field corresponding to latin1_field + - args[0] points to Item_func_conv_charset + - args[0]->args[0] is equal to m_args0 + - args[1] points to Item_func_set_collation + - args[2] points is eqial to m_args0 + + In this case we remember and reuse m_arg0 during EXECUTE time as args[2]. + + QQ: How to make sure that m_args0 does not point + to something temporary which will be destoyed between PREPARE and EXECUTE. + The condition below should probably be more strict and somehow check that: + - change_item_tree() was called for the new args[0] + - m_args0 is referenced from inside args[0], e.g. as a function argument, + and therefore it is also something that won't be destroyed between + PREPARE and EXECUTE. + Any ideas? + */ + if (args[0] == m_arg0) + m_arg0= NULL; } @@ -4494,7 +4534,8 @@ Item_cond::fix_fields(THD *thd, Item **ref) was: <field> become: <field> = 1 */ - if (item->type() == FIELD_ITEM) + Item::Type type= item->type(); + if (type == Item::FIELD_ITEM || type == Item::REF_ITEM) { Query_arena backup, *arena; Item *new_item; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c691797e2c5..7774663bd57 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1075,6 +1075,7 @@ class Item_func_nullif :public Item_func_hybrid_field_type if (arg_count == 3 && args[0] != args[2]) args[0]= args[2]; } + Item *m_arg0; public: /* Here we pass three arguments to the parent constructor, as NULLIF @@ -1086,8 +1087,14 @@ public: */ Item_func_nullif(THD *thd, Item *a, Item *b): Item_func_hybrid_field_type(thd, a, b, a), - m_cache(NULL) + m_cache(NULL), + m_arg0(NULL) { arg_count--; } + void cleanup() + { + Item_func_hybrid_field_type::cleanup(); + arg_count= 2; // See the comment to the constructor + } bool date_op(MYSQL_TIME *ltime, uint fuzzydate); double real_op(); longlong int_op(); @@ -1772,10 +1779,26 @@ public: const char *func_name() const { return "isnull"; } void print(String *str, enum_query_type query_type); enum precedence precedence() const { return CMP_PRECEDENCE; } + + bool arg_is_datetime_notnull_field() + { + Item **args= arguments(); + if (args[0]->type() == Item::FIELD_ITEM) + { + Field *field=((Item_field*) args[0])->field; + + if (((field->type() == MYSQL_TYPE_DATE) || + (field->type() == MYSQL_TYPE_DATETIME)) && + (field->flags & NOT_NULL_FLAG)) + return true; + } + return false; + } + /* Optimize case of not_null_column IS NULL */ virtual void update_used_tables() { - if (!args[0]->maybe_null) + if (!args[0]->maybe_null && !arg_is_datetime_notnull_field()) { used_tables_cache= 0; /* is always false */ const_item_cache= 1; @@ -2695,4 +2718,3 @@ extern Ge_creator ge_creator; extern Le_creator le_creator; #endif /* ITEM_CMPFUNC_INCLUDED */ - diff --git a/sql/item_func.cc b/sql/item_func.cc index 9bafe25e431..c38bdba05c2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6596,7 +6596,8 @@ Item_func_sp::init_result_field(THD *thd) bool Item_func_sp::is_expensive() { - return !(m_sp->m_chistics->detistic); + return !m_sp->m_chistics->detistic || + current_thd->locked_tables_mode < LTM_LOCK_TABLES; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b7efa60c520..9740dc9dae1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -164,31 +164,6 @@ String *Item_func_md5::val_str_ascii(String *str) } -/* - The MD5()/SHA() functions treat their parameter as being a case sensitive. - Thus we set binary collation on it so different instances of MD5() will be - compared properly. -*/ -static CHARSET_INFO *get_checksum_charset(const char *csname) -{ - CHARSET_INFO *cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0)); - if (!cs) - { - // Charset has no binary collation: use my_charset_bin. - cs= &my_charset_bin; - } - return cs; -} - - -void Item_func_md5::fix_length_and_dec() -{ - CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname); - args[0]->collation.set(cs, DERIVATION_COERCIBLE); - fix_length_and_charset(32, default_charset()); -} - - String *Item_func_sha::val_str_ascii(String *str) { DBUG_ASSERT(fixed == 1); @@ -214,8 +189,6 @@ String *Item_func_sha::val_str_ascii(String *str) void Item_func_sha::fix_length_and_dec() { - CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname); - args[0]->collation.set(cs, DERIVATION_COERCIBLE); // size of hex representation of hash fix_length_and_charset(SHA1_HASH_SIZE * 2, default_charset()); } @@ -345,9 +318,6 @@ void Item_func_sha2::fix_length_and_dec() "sha2"); } - CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname); - args[0]->collation.set(cs, DERIVATION_COERCIBLE); - #else THD *thd= current_thd; push_warning_printf(thd, diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index be23f45c286..65c6dacbc73 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -97,23 +97,69 @@ public: }; -class Item_func_md5 :public Item_str_ascii_func +/** + Functions that return a checksum or a hash of the argument, + or somehow else encode or decode the argument, + returning an ASCII-repertoire string. +*/ +class Item_str_ascii_checksum_func: public Item_str_ascii_func +{ +public: + Item_str_ascii_checksum_func(THD *thd, Item *a) + :Item_str_ascii_func(thd, a) { } + Item_str_ascii_checksum_func(THD *thd, Item *a, Item *b) + :Item_str_ascii_func(thd, a, b) { } + bool eq(const Item *item, bool binary_cmp) const + { + // Always use binary argument comparison: MD5('x') != MD5('X') + return Item_func::eq(item, true); + } +}; + + +/** + Functions that return a checksum or a hash of the argument, + or somehow else encode or decode the argument, + returning a binary string. +*/ +class Item_str_binary_checksum_func: public Item_str_func +{ +public: + Item_str_binary_checksum_func(THD *thd, Item *a) + :Item_str_func(thd, a) { } + Item_str_binary_checksum_func(THD *thd, Item *a, Item *b) + :Item_str_func(thd, a, b) { } + bool eq(const Item *item, bool binary_cmp) const + { + /* + Always use binary argument comparison: + FROM_BASE64('test') != FROM_BASE64('TEST') + */ + return Item_func::eq(item, true); + } +}; + + +class Item_func_md5 :public Item_str_ascii_checksum_func { String tmp_value; public: - Item_func_md5(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); - void fix_length_and_dec(); + void fix_length_and_dec() + { + fix_length_and_charset(32, default_charset()); + } const char *func_name() const { return "md5"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_md5>(thd, mem_root, this); } }; -class Item_func_sha :public Item_str_ascii_func +class Item_func_sha :public Item_str_ascii_checksum_func { public: - Item_func_sha(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_sha(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); void fix_length_and_dec(); const char *func_name() const { return "sha"; } @@ -121,10 +167,11 @@ public: { return get_item_copy<Item_func_sha>(thd, mem_root, this); } }; -class Item_func_sha2 :public Item_str_ascii_func +class Item_func_sha2 :public Item_str_ascii_checksum_func { public: - Item_func_sha2(THD *thd, Item *a, Item *b): Item_str_ascii_func(thd, a, b) {} + Item_func_sha2(THD *thd, Item *a, Item *b) + :Item_str_ascii_checksum_func(thd, a, b) {} String *val_str_ascii(String *); void fix_length_and_dec(); const char *func_name() const { return "sha2"; } @@ -132,11 +179,12 @@ public: { return get_item_copy<Item_func_sha2>(thd, mem_root, this); } }; -class Item_func_to_base64 :public Item_str_ascii_func +class Item_func_to_base64 :public Item_str_ascii_checksum_func { String tmp_value; public: - Item_func_to_base64(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_to_base64(THD *thd, Item *a) + :Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); void fix_length_and_dec(); const char *func_name() const { return "to_base64"; } @@ -144,11 +192,12 @@ public: { return get_item_copy<Item_func_to_base64>(thd, mem_root, this); } }; -class Item_func_from_base64 :public Item_str_func +class Item_func_from_base64 :public Item_str_binary_checksum_func { String tmp_value; public: - Item_func_from_base64(THD *thd, Item *a): Item_str_func(thd, a) {} + Item_func_from_base64(THD *thd, Item *a) + :Item_str_binary_checksum_func(thd, a) { } String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "from_base64"; } @@ -158,7 +207,7 @@ public: #include <my_crypt.h> -class Item_aes_crypt :public Item_str_func +class Item_aes_crypt :public Item_str_binary_checksum_func { enum { AES_KEY_LENGTH = 128 }; void create_key(String *user_key, uchar* key); @@ -166,7 +215,8 @@ class Item_aes_crypt :public Item_str_func protected: int what; public: - Item_aes_crypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} + Item_aes_crypt(THD *thd, Item *a, Item *b) + :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *); }; @@ -481,7 +531,7 @@ public: authentication procedure works, see comments in password.c. */ -class Item_func_password :public Item_str_ascii_func +class Item_func_password :public Item_str_ascii_checksum_func { public: enum PW_Alg {OLD, NEW}; @@ -491,9 +541,9 @@ private: bool deflt; public: Item_func_password(THD *thd, Item *a): - Item_str_ascii_func(thd, a), alg(NEW), deflt(1) {} + Item_str_ascii_checksum_func(thd, a), alg(NEW), deflt(1) {} Item_func_password(THD *thd, Item *a, PW_Alg al): - Item_str_ascii_func(thd, a), alg(al), deflt(0) {} + Item_str_ascii_checksum_func(thd, a), alg(al), deflt(0) {} String *val_str_ascii(String *str); bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec() @@ -513,12 +563,14 @@ public: -class Item_func_des_encrypt :public Item_str_func +class Item_func_des_encrypt :public Item_str_binary_checksum_func { String tmp_value,tmp_arg; public: - Item_func_des_encrypt(THD *thd, Item *a): Item_str_func(thd, a) {} - Item_func_des_encrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} + Item_func_des_encrypt(THD *thd, Item *a) + :Item_str_binary_checksum_func(thd, a) {} + Item_func_des_encrypt(THD *thd, Item *a, Item *b) + :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *); void fix_length_and_dec() { @@ -531,12 +583,14 @@ public: { return get_item_copy<Item_func_des_encrypt>(thd, mem_root, this); } }; -class Item_func_des_decrypt :public Item_str_func +class Item_func_des_decrypt :public Item_str_binary_checksum_func { String tmp_value; public: - Item_func_des_decrypt(THD *thd, Item *a): Item_str_func(thd, a) {} - Item_func_des_decrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} + Item_func_des_decrypt(THD *thd, Item *a) + :Item_str_binary_checksum_func(thd, a) {} + Item_func_des_decrypt(THD *thd, Item *a, Item *b) + :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *); void fix_length_and_dec() { @@ -551,7 +605,13 @@ public: { return get_item_copy<Item_func_des_decrypt>(thd, mem_root, this); } }; -class Item_func_encrypt :public Item_str_func + +/** + QQ: Item_func_encrypt should derive from Item_str_ascii_checksum_func. + However, it should be fixed to handle UCS2, UTF16, UTF32 properly first, + as the underlying crypt() call expects a null-terminated input string. +*/ +class Item_func_encrypt :public Item_str_binary_checksum_func { String tmp_value; @@ -561,11 +621,12 @@ class Item_func_encrypt :public Item_str_func collation.set(&my_charset_bin); } public: - Item_func_encrypt(THD *thd, Item *a): Item_str_func(thd, a) + Item_func_encrypt(THD *thd, Item *a): Item_str_binary_checksum_func(thd, a) { constructor_helper(); } - Item_func_encrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) + Item_func_encrypt(THD *thd, Item *a, Item *b) + :Item_str_binary_checksum_func(thd, a, b) { constructor_helper(); } @@ -583,7 +644,7 @@ public: #include "sql_crypt.h" -class Item_func_encode :public Item_str_func +class Item_func_encode :public Item_str_binary_checksum_func { private: /** Whether the PRNG has already been seeded. */ @@ -592,7 +653,7 @@ protected: SQL_CRYPT sql_crypt; public: Item_func_encode(THD *thd, Item *a, Item *seed_arg): - Item_str_func(thd, a, seed_arg) {} + Item_str_binary_checksum_func(thd, a, seed_arg) {} String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "encode"; } @@ -911,12 +972,12 @@ public: }; -class Item_func_hex :public Item_str_ascii_func +class Item_func_hex :public Item_str_ascii_checksum_func { String tmp_value; public: Item_func_hex(THD *thd, Item *a): - Item_str_ascii_func(thd, a) {} + Item_str_ascii_checksum_func(thd, a) {} const char *func_name() const { return "hex"; } String *val_str_ascii(String *); void fix_length_and_dec() @@ -1291,11 +1352,12 @@ public: #define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; } #endif -class Item_func_compress: public Item_str_func +class Item_func_compress: public Item_str_binary_checksum_func { String buffer; public: - Item_func_compress(THD *thd, Item *a): Item_str_func(thd, a) {} + Item_func_compress(THD *thd, Item *a) + :Item_str_binary_checksum_func(thd, a) {} void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} const char *func_name() const{return "compress";} String *val_str(String *) ZLIB_DEPENDED_FUNCTION @@ -1303,11 +1365,12 @@ public: { return get_item_copy<Item_func_compress>(thd, mem_root, this); } }; -class Item_func_uncompress: public Item_str_func +class Item_func_uncompress: public Item_str_binary_checksum_func { String buffer; public: - Item_func_uncompress(THD *thd, Item *a): Item_str_func(thd, a) {} + Item_func_uncompress(THD *thd, Item *a) + :Item_str_binary_checksum_func(thd, a) {} void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; } const char *func_name() const{return "uncompress";} String *val_str(String *) ZLIB_DEPENDED_FUNCTION diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f7105086e55..89c663b5f16 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -228,6 +228,7 @@ bool Item_subselect::select_transformer(JOIN *join) { DBUG_ENTER("Item_subselect::select_transformer"); + DBUG_ASSERT(thd == join->thd); DBUG_RETURN(false); } @@ -629,6 +630,7 @@ bool Item_subselect::is_expensive() examined_rows+= cur_join->get_examined_rows(); } + // here we are sure that subquery is optimized so thd is set return !all_are_simple && (examined_rows > thd->variables.expensive_subquery_limit); } @@ -693,6 +695,7 @@ bool Item_subselect::exec() subselect_engine *org_engine= engine; DBUG_ENTER("Item_subselect::exec"); + DBUG_ASSERT(fixed); /* Do not execute subselect in case of a fatal error @@ -741,6 +744,7 @@ int Item_in_subselect::optimize(double *out_rows, double *cost) { int res; DBUG_ENTER("Item_in_subselect::optimize"); + DBUG_ASSERT(fixed); SELECT_LEX *save_select= thd->lex->current_select; JOIN *join= unit->first_select()->join; @@ -857,6 +861,7 @@ bool Item_in_subselect::expr_cache_is_needed(THD *thd) bool Item_in_subselect::exec() { DBUG_ENTER("Item_in_subselect::exec"); + DBUG_ASSERT(fixed); /* Initialize the cache of the left predicate operand. This has to be done as late as now, because Cached_item directly contains a resolved field (not @@ -911,6 +916,7 @@ table_map Item_subselect::used_tables() const bool Item_subselect::const_item() const { + DBUG_ASSERT(thd); return (thd->lex->context_analysis_only ? FALSE : forced_const || const_item_cache); @@ -1112,10 +1118,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join) DBUG_ENTER("Item_singlerow_subselect::select_transformer"); if (changed) DBUG_RETURN(false); + DBUG_ASSERT(join->thd == thd); SELECT_LEX *select_lex= join->select_lex; Query_arena *arena= thd->stmt_arena; - + if (!select_lex->master_unit()->is_union() && !select_lex->table_list.elements && select_lex->item_list.elements == 1 && @@ -1790,6 +1797,7 @@ Item_in_subselect::single_value_transformer(JOIN *join) { SELECT_LEX *select_lex= join->select_lex; DBUG_ENTER("Item_in_subselect::single_value_transformer"); + DBUG_ASSERT(thd == join->thd); /* Check that the right part of the subselect contains no more than one @@ -1904,6 +1912,7 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join) Item **place= optimizer->arguments() + 1; SELECT_LEX *select_lex= join->select_lex; Item *subs; + DBUG_ASSERT(thd == join->thd); /* */ @@ -2012,6 +2021,7 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join) bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex) { bool fix_res= 0; + DBUG_ASSERT(thd); if (!having->fixed) { select_lex->having_fix_field= 1; @@ -2074,6 +2084,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, Item **having_item) { SELECT_LEX *select_lex= join->select_lex; + DBUG_ASSERT(thd == join->thd); /* The non-transformed HAVING clause of 'join' may be stored in two ways during JOIN::optimize: this->tmp_having= this->having; this->having= 0; @@ -2215,6 +2226,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) uint cols_num= left_expr->cols(); DBUG_ENTER("Item_in_subselect::row_value_transformer"); + DBUG_ASSERT(thd == join->thd); // psergey: duplicated_subselect_card_check if (select_lex->item_list.elements != cols_num) @@ -2326,6 +2338,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, !select_lex->table_list.elements); DBUG_ENTER("Item_in_subselect::create_row_in_to_exists_cond"); + DBUG_ASSERT(thd == join->thd); *where_item= NULL; *having_item= NULL; @@ -2571,6 +2584,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg) Item *having_item= join_arg->in_to_exists_having; DBUG_ENTER("Item_in_subselect::inject_in_to_exists_cond"); + DBUG_ASSERT(thd == join_arg->thd); if (where_item) { @@ -2700,8 +2714,8 @@ static bool check_equality_for_exist2in(Item_func *func, args[0]->all_used_tables() == OUTER_REF_TABLE_BIT) { /* It is Item_field or Item_direct_view_ref) */ - DBUG_ASSERT(args[0]->type() == Item::FIELD_ITEM || - args[0]->type() == Item::REF_ITEM); + DBUG_ASSERT(args[1]->type() == Item::FIELD_ITEM || + args[1]->type() == Item::REF_ITEM); *local_field= (Item_ident *)args[1]; *outer_exp= args[0]; return TRUE; @@ -3099,6 +3113,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join) bool result; DBUG_ENTER("Item_in_subselect::select_in_like_transformer"); + DBUG_ASSERT(thd == join->thd); /* IN/SOME/ALL/ANY subqueries aren't support LIMIT clause. Without it @@ -3309,6 +3324,7 @@ bool Item_in_subselect::setup_mat_engine() subselect_single_select_engine *select_engine; DBUG_ENTER("Item_in_subselect::setup_mat_engine"); + DBUG_ASSERT(thd); /* The select_engine (that executes transformed IN=>EXISTS subselects) is @@ -3347,6 +3363,7 @@ bool Item_in_subselect::setup_mat_engine() bool Item_in_subselect::init_left_expr_cache() { JOIN *outer_join; + DBUG_ASSERT(thd); outer_join= unit->outer_select()->join; /* @@ -3374,6 +3391,7 @@ bool Item_in_subselect::init_left_expr_cache() bool Item_in_subselect::init_cond_guards() { + DBUG_ASSERT(thd); uint cols_num= left_expr->cols(); if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) { @@ -6662,4 +6680,3 @@ void Item_subselect::init_expr_cache_tracker(THD *thd) DBUG_ASSERT(expr_cache->type() == Item::EXPR_CACHE_ITEM); node->cache_tracker= ((Item_cache_wrapper *)expr_cache)->init_tracker(qw->mem_root); } - diff --git a/sql/item_sum.h b/sql/item_sum.h index b9075db0196..84049814ef9 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1195,7 +1195,6 @@ public: fixed= true; } table_map used_tables() const { return (table_map) 1L; } - void set_result_field(Field *) { DBUG_ASSERT(0); } void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); } bool check_vcol_func_processor(void *arg) { diff --git a/sql/log.cc b/sql/log.cc index d2fc98b80ef..57984bd03f4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -301,6 +301,9 @@ public: { compute_statistics(); truncate(0); + if(cache_log.file != -1) + my_chsize(cache_log.file, 0, 0, MYF(MY_WME)); + changes_to_non_trans_temp_table_flag= FALSE; incident= FALSE; before_stmt_pos= MY_OFF_T_UNDEF; @@ -3106,7 +3109,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, if (! write_error) { write_error= 1; - sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, error); + sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, tmp_errno); } } } @@ -3399,7 +3402,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, if (init_and_set_log_file_name(log_name, new_name, next_log_number, log_type_arg, io_cache_type_arg)) { - sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name."); + sql_print_error("MYSQL_BIN_LOG::open failed to generate new file name."); DBUG_RETURN(1); } @@ -3428,7 +3431,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, } }); - sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file."); + sql_print_error("MYSQL_BIN_LOG::open failed to sync the index file."); DBUG_RETURN(1); } DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_SUICIDE();); @@ -4534,14 +4537,14 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, if ((error= sync_purge_index_file())) { - sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file."); + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to flush register file."); goto err; } /* We know how many files to delete. Update index file. */ if ((error=update_log_index(&log_info, need_update_threads))) { - sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file"); + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to update the index file"); goto err; } @@ -4551,7 +4554,7 @@ err: /* Read each entry from purge_index_file and delete the file. */ if (is_inited_purge_index_file() && (error= purge_index_entry(thd, reclaimed_space, FALSE))) - sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files" + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to process registered files" " that would be purged."); close_purge_index_file(); @@ -4668,7 +4671,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space, if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0))) { - sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file " + sql_print_error("MYSQL_BIN_LOG::purge_index_entry failed to reinit register file " "for read"); goto err; } @@ -4683,7 +4686,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space, if (purge_index_file.error) { error= purge_index_file.error; - sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from " + sql_print_error("MYSQL_BIN_LOG::purge_index_entry error %d reading from " "register file.", error); goto err; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 3b4d5e8f9a4..85dce217743 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1897,6 +1897,10 @@ err: if (error) { DBUG_ASSERT(!res); +#ifdef MYSQL_CLIENT + if (force_opt) + DBUG_RETURN(new Unknown_log_event()); +#endif if (event.length() >= OLD_HEADER_LEN) sql_print_error("Error in Log_event::read_log_event(): '%s'," " data_len: %lu, event_type: %d", error, @@ -8680,8 +8684,13 @@ void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info if (print_event_info->short_form) return; - print_header(&cache, print_event_info, FALSE); - my_b_printf(&cache, "\n# %s", "Unknown event\n"); + if (what != ENCRYPTED) + { + print_header(&cache, print_event_info, FALSE); + my_b_printf(&cache, "\n# Unknown event\n"); + } + else + my_b_printf(&cache, "# Encrypted event\n"); } #endif diff --git a/sql/log_event.h b/sql/log_event.h index bbefbe26f41..7b8704636af 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1213,7 +1213,7 @@ public: return thd ? thd->db : 0; } #else - Log_event() : temp_buf(0), flags(0) {} + Log_event() : temp_buf(0), when(0), flags(0) {} ha_checksum crc; /* print*() functions are used by mysqlbinlog */ virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0; @@ -3768,6 +3768,7 @@ private: class Unknown_log_event: public Log_event { public: + enum { UNKNOWN, ENCRYPTED } what; /* Even if this is an unknown event, we still pass description_event to Log_event's ctor, this way we can extract maximum information from the @@ -3775,8 +3776,10 @@ public: */ Unknown_log_event(const char* buf, const Format_description_log_event *description_event): - Log_event(buf, description_event) + Log_event(buf, description_event), what(UNKNOWN) {} + /* constructor for hopelessly corrupted events */ + Unknown_log_event(): Log_event(), what(ENCRYPTED) {} ~Unknown_log_event() {} void print(FILE* file, PRINT_EVENT_INFO* print_event_info); Log_event_type get_type_code() { return UNKNOWN_EVENT;} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e7fb7b7e0c9..84d6e3b582f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4189,6 +4189,7 @@ static int init_common_variables() max_system_variables.pseudo_thread_id= ~(my_thread_id) 0; server_start_time= flush_status_time= my_time(0); + my_disable_copystat_in_redel= 1; global_rpl_filter= new Rpl_filter; binlog_filter= new Rpl_filter; @@ -4260,6 +4261,8 @@ static int init_common_variables() return 1; } + opt_log_basename= const_cast<char *>("mysql"); + if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0) { /* @@ -4269,9 +4272,8 @@ static int init_common_variables() strmake(glob_hostname, STRING_WITH_LEN("localhost")); sql_print_warning("gethostname failed, using '%s' as hostname", glob_hostname); - opt_log_basename= const_cast<char *>("mysql"); } - else + else if (is_filename_allowed(glob_hostname, strlen(glob_hostname), FALSE)) opt_log_basename= glob_hostname; strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5); @@ -5895,6 +5897,12 @@ int mysqld_main(int argc, char **argv) setbuf(stderr, NULL); FreeConsole(); // Remove window } + + if (fileno(stdin) >= 0) + { + /* Disable CRLF translation (MDEV-9409). */ + _setmode(fileno(stdin), O_BINARY); + } #endif #ifdef WITH_WSREP @@ -9061,9 +9069,10 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) case (int) OPT_LOG_BASENAME: { if (opt_log_basename[0] == 0 || strchr(opt_log_basename, FN_EXTCHAR) || - strchr(opt_log_basename,FN_LIBCHAR)) + strchr(opt_log_basename,FN_LIBCHAR) || + !is_filename_allowed(opt_log_basename, strlen(opt_log_basename), FALSE)) { - sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'"); + sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'. It must be valid filename."); return 1; } if (log_error_file_ptr != disabled_my_option) @@ -9946,9 +9955,9 @@ static int test_if_case_insensitive(const char *dir_name) MY_STAT stat_info; DBUG_ENTER("test_if_case_insensitive"); - fn_format(buff, glob_hostname, dir_name, ".lower-test", + fn_format(buff, opt_log_basename, dir_name, ".lower-test", MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); - fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST", + fn_format(buff2, opt_log_basename, dir_name, ".LOWER-TEST", MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); mysql_file_delete(key_file_casetest, buff2, MYF(0)); if ((file= mysql_file_create(key_file_casetest, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 70111f1b5d6..f9635689e63 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2012, 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/opt_range.cc b/sql/opt_range.cc index 4b535769d6c..01b836fddf7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2760,9 +2760,16 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param, { Field *field= *field_ptr; uint16 store_length; + uint16 max_key_part_length= (uint16) table->file->max_key_part_length(); key_part->key= keys; key_part->part= 0; - key_part->length= (uint16) field->key_length(); + if (field->flags & BLOB_FLAG) + key_part->length= max_key_part_length; + else + { + key_part->length= (uint16) field->key_length(); + set_if_smaller(key_part->length, max_key_part_length); + } store_length= key_part->length; if (field->real_maybe_null()) store_length+= HA_KEY_NULL_LENGTH; @@ -3108,6 +3115,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) } free_alloc: + thd->no_errors= 0; thd->mem_root= param.old_root; free_root(&alloc, MYF(0)); diff --git a/sql/parse_file.h b/sql/parse_file.h index e4756e6c8af..87917dbd71b 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -42,9 +42,9 @@ enum file_opt_type { struct File_option { - LEX_STRING name; /**< Name of the option */ - int offset; /**< offset to base address of value */ - file_opt_type type; /**< Option type */ + LEX_STRING name; /**< Name of the option */ + my_ptrdiff_t offset; /**< offset to base address of value */ + file_opt_type type; /**< Option type */ }; diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index f1c6d76f7ff..b82e7bada45 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -282,6 +282,9 @@ Rpl_filter::parse_filter_rule(const char* spec, Add_filter add) int status= 0; char *arg, *ptr, *pstr; + if (!spec) + return false; + if (! (ptr= my_strdup(spec, MYF(MY_WME)))) return true; diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 4adea76b3cb..1d9cb39075b 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -448,19 +448,7 @@ static const TABLE_FIELD_DEF mysql_gtid_slave_pos_tabledef= { mysql_rpl_slave_state_pk_parts }; -class Gtid_db_intact : public Table_check_intact -{ -protected: - void report_error(uint, const char *fmt, ...) - { - va_list args; - va_start(args, fmt); - error_log_print(ERROR_LEVEL, fmt, args); - va_end(args); - } -}; - -static Gtid_db_intact gtid_table_intact; +static Table_check_intact_log_error gtid_table_intact; /* Check that the mysql.gtid_slave_pos table has the correct definition. diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index ec5ea725487..f7aab704c43 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -2773,7 +2773,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, /* Queue the event for processing. */ - rli->event_relay_log_pos= rli->future_event_relay_log_pos; qev->ir= rli->last_inuse_relaylog; ++qev->ir->queued_count; cur_thread->enqueue(qev); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index f687f645171..cd189b4ab2d 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1245,8 +1245,8 @@ bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos) if (until_condition == UNTIL_MASTER_POS) { - log_name= (mi->using_parallel() ? - future_event_master_log_name : group_master_log_name); + log_name= (mi->using_parallel() ? future_event_master_log_name + : group_master_log_name); log_pos= master_beg_pos; } else diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index aa11b55da0d..03fba3fde49 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6781,7 +6781,7 @@ ER_FK_COLUMN_NOT_NULL ger "Spalte '%-.192s' kann nicht NOT NULL sein: wird für eine Fremdschlüsselbeschränkung '%-.192s' SET NULL benötigt" ER_DUP_INDEX - eng "Duplicate index '%-.64s' defined on the table '%-.64s.%-.64s'. This is deprecated and will be disallowed in a future release" + eng "Duplicate index %`s. This is deprecated and will be disallowed in a future release" ER_FK_COLUMN_CANNOT_CHANGE eng "Cannot change column '%-.192s': used in a foreign key constraint '%-.192s'" diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index f9478134ab4..ad7fb873c68 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -64,18 +64,18 @@ extern "C" sig_handler handle_fatal_signal(int sig) struct tm tm; #ifdef HAVE_STACKTRACE THD *thd; -#endif /* This flag remembers if the query pointer was found invalid. We will try and print the query at the end of the signal handler, in case we're wrong. */ bool print_invalid_query_pointer= false; +#endif if (segfaulted) { my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig); - _exit(1); /* Quit without running destructors */ + goto end; } segfaulted = 1; @@ -276,6 +276,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) "\"mlockall\" bugs.\n"); } +#ifdef HAVE_STACKTRACE if (print_invalid_query_pointer) { my_safe_printf_stderr( @@ -285,6 +286,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) my_write_stderr(thd->query(), MY_MIN(65536U, thd->query_length())); my_safe_printf_stderr("\n\n"); } +#endif #ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) @@ -299,9 +301,11 @@ end: #ifndef __WIN__ /* Quit, without running destructors (etc.) + Use a signal, because the parent (systemd) can check that with WIFSIGNALED On Windows, do not terminate, but pass control to exception filter. */ - _exit(1); // Using _exit(), since exit() is not async signal safe + signal(sig, SIG_DFL); + kill(getpid(), sig); #else return; #endif diff --git a/sql/slave.cc b/sql/slave.cc index 77fde743184..05e967c4edb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3344,8 +3344,13 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings, *suppress_warnings= TRUE; } else - sql_print_error("Error reading packet from server: %s ( server_errno=%d)", - mysql_error(mysql), mysql_errno(mysql)); + { + if (!mi->rli.abort_slave) + { + sql_print_error("Error reading packet from server: %s (server_errno=%d)", + mysql_error(mysql), mysql_errno(mysql)); + } + } DBUG_RETURN(packet_error); } @@ -3929,6 +3934,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, if (rli->mi->using_parallel()) { int res= rli->parallel.do_event(serial_rgi, ev, event_size); + /* + In parallel replication, we need to update the relay log position + immediately so that it will be the correct position from which to + read the next event. + */ + if (res == 0) + rli->event_relay_log_pos= rli->future_event_relay_log_pos; if (res >= 0) DBUG_RETURN(res); /* @@ -4928,7 +4940,21 @@ pthread_handler_t handle_slave_sql(void *arg) serial_rgi->gtid_sub_id= 0; serial_rgi->gtid_pending= false; - rli->gtid_skip_flag = GTID_SKIP_NOT; + if (mi->using_gtid != Master_info::USE_GTID_NO && mi->using_parallel() && + rli->restart_gtid_pos.count() > 0) + { + /* + With parallel replication in GTID mode, if we have a multi-domain GTID + position, we need to start some way back in the relay log and skip any + GTID that was already applied before. Since event groups can be split + across multiple relay logs, this earlier starting point may be in the + middle of an already applied event group, so we also need to skip any + remaining part of such group. + */ + rli->gtid_skip_flag = GTID_SKIP_TRANSACTION; + } + else + rli->gtid_skip_flag = GTID_SKIP_NOT; if (init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6334d3fa1dd..ce7de2ed72b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1755,7 +1755,7 @@ bool acl_reload(THD *thd) 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_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0, (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); old_mem= acl_memroot; delete_dynamic(&acl_wild_hosts); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ed23d9cccd6..bc5b9bde8e8 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -380,7 +380,19 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table, } thd->prepare_derived_at_open= FALSE; - table->next_global= save_next_global; + /* + MERGE engine may adjust table->next_global chain, thus we have to + append save_next_global after merge children. + */ + if (save_next_global) + { + TABLE_LIST *table_list_iterator= table; + while (table_list_iterator->next_global) + table_list_iterator= table_list_iterator->next_global; + table_list_iterator->next_global= save_next_global; + save_next_global->prev_global= &table_list_iterator->next_global; + } + table->next_local= save_next_local; return open_error; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e947e9dd90a..b6cfd2f2cc1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8446,6 +8446,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, */ lex->reset_n_backup_query_tables_list(&query_tables_list_backup); thd->reset_n_backup_open_tables_state(backup); + thd->lex->sql_command= SQLCOM_SELECT; if (open_and_lock_tables(thd, table_list, FALSE, MYSQL_OPEN_IGNORE_FLUSH | diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2f4856fc4e2..6b13dba876e 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -962,7 +962,7 @@ inline void Query_cache_query::unlock_reading() void Query_cache_query::init_n_lock() { DBUG_ENTER("Query_cache_query::init_n_lock"); - res=0; wri = 0; len = 0; + res=0; wri = 0; len = 0; ready= 0; mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock); lock_writing(); DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx", @@ -1227,6 +1227,7 @@ void Query_cache::end_of_result(THD *thd) query_cache.split_block(last_result_block,len); header->found_rows(limit_found_rows); + header->set_results_ready(); // signal for plugin header->result()->type= Query_cache_block::RESULT; /* Drop the writer. */ diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 6984c2115f2..945de307ffb 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -156,8 +156,9 @@ struct Query_cache_query Query_cache_block *res; Query_cache_tls *wri; ulong len; - uint8 tbls_type; unsigned int last_pkt_nr; + uint8 tbls_type; + uint8 ready; Query_cache_query() {} /* Remove gcc warning */ inline void init_n_lock(); @@ -177,6 +178,12 @@ struct Query_cache_query { return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query))); } + /** + following used to check if result ready in plugin without + locking rw_lock of the query. + */ + inline void set_results_ready() { ready= 1; } + inline bool is_results_ready() { return ready; } void lock_writing(); void lock_reading(); bool try_lock_writing(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d7d2944ba89..1837f2878c7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5713,9 +5713,11 @@ int THD::decide_logging_format(TABLE_LIST *tables) { static const char *prelocked_mode_name[] = { "NON_PRELOCKED", + "LOCK_TABLES", "PRELOCKED", "PRELOCKED_UNDER_LOCK_TABLES", }; + compile_time_assert(array_elements(prelocked_mode_name) == LTM_always_last); DBUG_PRINT("debug", ("prelocked_mode: %s", prelocked_mode_name[locked_tables_mode])); } diff --git a/sql/sql_class.h b/sql/sql_class.h index f0052f8fe57..ef10d7e4053 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1372,7 +1372,8 @@ enum enum_locked_tables_mode LTM_NONE= 0, LTM_LOCK_TABLES, LTM_PRELOCKED, - LTM_PRELOCKED_UNDER_LOCK_TABLES + LTM_PRELOCKED_UNDER_LOCK_TABLES, + LTM_always_last }; /** diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 20538fe1fb4..8b7d4ee5ed2 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -815,7 +815,7 @@ static bool mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) { ulong deleted_tables= 0; - bool error= true; + bool error= true, rm_mysql_schema; char path[FN_REFLEN + 16]; MY_DIR *dirp; uint length; @@ -840,6 +840,18 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name del_dbopt(path); // Remove dboption hash entry + /* + Now remove the db.opt file. + The 'find_db_tables_and_rm_known_files' doesn't remove this file + if there exists a table with the name 'db', so let's just do it + separately. We know this file exists and needs to be deleted anyway. + */ + if (my_delete_with_symlink(path, MYF(0)) && my_errno != ENOENT) + { + my_error(EE_DELETE, MYF(0), path, my_errno); + DBUG_RETURN(true); + } + path[length]= '\0'; // Remove file name /* See if the directory exists */ @@ -867,7 +879,8 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) Disable drop of enabled log tables, must be done before name locking. This check is only needed if we are dropping the "mysql" database. */ - if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0)) + if ((rm_mysql_schema= + (my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))) { for (table= tables; table; table= table->next_local) if (check_if_log_table(table, TRUE, "DROP")) @@ -880,7 +893,7 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) lock_db_routines(thd, dbnorm)) goto exit; - if (!in_bootstrap) + if (!in_bootstrap && !rm_mysql_schema) { for (table= tables; table; table= table->next_local) { @@ -921,10 +934,13 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) ha_drop_database(path); tmp_disable_binlog(thd); query_cache_invalidate1(thd, dbnorm); - (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */ + if (!rm_mysql_schema) + { + (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */ #ifdef HAVE_EVENT_SCHEDULER - Events::drop_schema_events(thd, dbnorm); + Events::drop_schema_events(thd, dbnorm); #endif + } reenable_binlog(thd); /* diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 1156b3b8305..daac90d56f6 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -713,6 +713,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) } unit->derived= derived; + derived->fill_me= FALSE; if (!(derived->derived_result= new (thd->mem_root) select_union(thd))) DBUG_RETURN(TRUE); // out of memory diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 45a6bf59b99..b2dd04d8fd5 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1319,7 +1319,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd) state= (enum my_lex_states) state_map[c]; break; case MY_LEX_ESCAPE: - if (lip->yyGet() == 'N') + if (!lip->eof() && lip->yyGet() == 'N') { // Allow \N as shortcut for NULL yylval->lex_str.str=(char*) "\\N"; yylval->lex_str.length=2; @@ -3740,12 +3740,28 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length) bool st_select_lex::optimize_unflattened_subqueries(bool const_only) { - for (SELECT_LEX_UNIT *un= first_inner_unit(); un; un= un->next_unit()) + SELECT_LEX_UNIT *next_unit= NULL; + for (SELECT_LEX_UNIT *un= first_inner_unit(); + un; + un= next_unit ? next_unit : un->next_unit()) { Item_subselect *subquery_predicate= un->item; - + next_unit= NULL; + if (subquery_predicate) { + if (!subquery_predicate->fixed) + { + /* + This subquery was excluded as part of some expression so it is + invisible from all prepared expression. + */ + next_unit= un->next_unit(); + un->exclude_level(); + if (next_unit) + continue; + break; + } if (subquery_predicate->substype() == Item_subselect::IN_SUBS) { Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 509df96e89d..c25e73e7346 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -616,7 +616,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, *enclosed, skip_lines, ignore); thd_proc_info(thd, "End bulk insert"); - thd_progress_next_stage(thd); + if (!error) + thd_progress_next_stage(thd); if (thd->locked_tables_mode <= LTM_LOCK_TABLES && table->file->ha_end_bulk_insert() && !error) { @@ -1525,6 +1526,54 @@ inline bool READ_INFO::terminator(const uchar *ptr, uint length) } +/** + Read a field. + + The data in the loaded file was presumably escaped using + - either select_export::send_data() OUTFILE + - or mysql_real_escape_string() + using the same character set with the one specified in the current + "LOAD DATA INFILE ... CHARACTER SET ..." (or the default LOAD character set). + + Note, non-escaped multi-byte characters are scanned as a single entity. + This is needed to correctly distinguish between: + - 0x5C as an escape character versus + - 0x5C as the second byte in a multi-byte sequence (big5, cp932, gbk, sjis) + + Parts of escaped multi-byte characters are scanned on different loop + iterations. See the comment about 0x5C handling in select_export::send_data() + in sql_class.cc. + + READ_INFO::read_field() does not check wellformedness. + Raising wellformedness errors or warnings in READ_INFO::read_field() + would be wrong, as the data after unescaping can go into a BLOB field, + or into a TEXT/VARCHAR field of a different character set. + The loop below only makes sure to revert escaping made by + select_export::send_data() or mysql_real_escape_string(). + Wellformedness is checked later, during Field::store(str,length,cs) time. + + Note, in some cases users can supply data which did not go through + escaping properly. For example, utf8 "\<C3><A4>" + (backslash followed by LATIN SMALL LETTER A WITH DIAERESIS) + is improperly escaped data that could not be generated by + select_export::send_data() / mysql_real_escape_string(): + - either there should be two backslashes: "\\<C3><A4>" + - or there should be no backslashes at all: "<C3><A4>" + "\<C3>" and "<A4> are scanned on two different loop iterations and + store "<C3><A4>" into the field. + + Note, adding useless escapes before multi-byte characters like in the + example above is safe in case of utf8, but is not safe in case of + character sets that have escape_with_backslash_is_dangerous==TRUE, + such as big5, cp932, gbk, sjis. This can lead to mis-interpretation of the + data. Suppose we have a big5 character "<EE><5C>" followed by <30> (digit 0). + If we add an extra escape before this sequence, then we'll get + <5C><EE><5C><30>. The first loop iteration will turn <5C><EE> into <EE>. + The second loop iteration will turn <5C><30> into <30>. + So the program that generates a dump file for further use with LOAD DATA + must make sure to use escapes properly. +*/ + int READ_INFO::read_field() { int chr,found_enclosed_char; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 370a4bd7400..06387c2b894 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3106,13 +3106,16 @@ mysql_execute_command(THD *thd) } /* - Bail out if DB snapshot has not been installed. We however, allow SET, - SHOW and SELECT queries (only if wsrep_dirty_reads is set). + Bail out if DB snapshot has not been installed. SET and SHOW commands, + however, are always allowed. + + We additionally allow all other commands that do not change data in + case wsrep_dirty_reads is enabled. */ if (lex->sql_command != SQLCOM_SET_OPTION && !wsrep_is_show_query(lex->sql_command) && !(thd->variables.wsrep_dirty_reads && - lex->sql_command == SQLCOM_SELECT) && + !is_update_query(lex->sql_command)) && !wsrep_node_is_ready(thd)) goto error; } @@ -3730,12 +3733,6 @@ mysql_execute_command(THD *thd) } /* - For CREATE TABLE we should not open the table even if it exists. - If the table exists, we should either not create it or replace it - */ - lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; - - /* If we are a slave, we should add OR REPLACE if we don't have IF EXISTS. This will help a slave to recover from CREATE TABLE OR EXISTS failures by dropping the table and @@ -9445,12 +9442,6 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, create_table->db)) goto err; - /* - For CREATE TABLE we should not open the table even if it exists. - If the table exists, we should either not create it or replace it - */ - lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; - error= FALSE; err: diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 58d6ff4cd00..aea83f41527 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2864,6 +2864,22 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name, } +static size_t var_storage_size(int flags) +{ + switch (flags & PLUGIN_VAR_TYPEMASK) { + case PLUGIN_VAR_BOOL: return sizeof(my_bool); + case PLUGIN_VAR_INT: return sizeof(int); + case PLUGIN_VAR_LONG: return sizeof(long); + case PLUGIN_VAR_ENUM: return sizeof(long); + case PLUGIN_VAR_LONGLONG: return sizeof(ulonglong); + case PLUGIN_VAR_SET: return sizeof(ulonglong); + case PLUGIN_VAR_STR: return sizeof(char*); + case PLUGIN_VAR_DOUBLE: return sizeof(double); + default: DBUG_ASSERT(0); return 0; + } +} + + /* returns a bookmark for thd-local variables, creating if neccessary. returns null for non thd-local variables. @@ -2872,39 +2888,13 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name, static st_bookmark *register_var(const char *plugin, const char *name, int flags) { - uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size; + uint length= strlen(plugin) + strlen(name) + 3, size, offset, new_size; st_bookmark *result; char *varname, *p; - if (!(flags & PLUGIN_VAR_THDLOCAL)) - return NULL; - - switch (flags & PLUGIN_VAR_TYPEMASK) { - case PLUGIN_VAR_BOOL: - size= sizeof(my_bool); - break; - case PLUGIN_VAR_INT: - size= sizeof(int); - break; - case PLUGIN_VAR_LONG: - case PLUGIN_VAR_ENUM: - size= sizeof(long); - break; - case PLUGIN_VAR_LONGLONG: - case PLUGIN_VAR_SET: - size= sizeof(ulonglong); - break; - case PLUGIN_VAR_STR: - size= sizeof(char*); - break; - case PLUGIN_VAR_DOUBLE: - size= sizeof(double); - break; - default: - DBUG_ASSERT(0); - return NULL; - }; + DBUG_ASSERT(flags & PLUGIN_VAR_THDLOCAL); + size= var_storage_size(flags); varname= ((char*) my_alloca(length)); strxmov(varname + 1, plugin, "_", name, NullS); for (p= varname + 1; *p; p++) @@ -2998,25 +2988,17 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock) */ for (idx= 0; idx < bookmark_hash.records; idx++) { - sys_var_pluginvar *pi; - sys_var *var; st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); if (v->version <= thd->variables.dynamic_variables_version) continue; /* already in thd->variables */ - if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) || - !(pi= var->cast_pluginvar()) || - v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags)) - continue; - /* Here we do anything special that may be required of the data types */ - if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && - pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC) + if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + v->key[0] & BOOKMARK_MEMALLOC) { - int offset= ((thdvar_str_t *)(pi->plugin_var))->offset; - char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset); + char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset); if (*pp) *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); } @@ -3454,69 +3436,58 @@ bool sys_var_pluginvar::session_update(THD *thd, set_var *var) return false; } -bool sys_var_pluginvar::global_update(THD *thd, set_var *var) +static const void *var_def_ptr(st_mysql_sys_var *pv) { - DBUG_ASSERT(!is_readonly()); - mysql_mutex_assert_owner(&LOCK_global_system_variables); - - void *tgt= real_value_ptr(thd, OPT_GLOBAL); - const void *src= &var->save_result; - - if (!var->value) - { - switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) { + switch (pv->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) { case PLUGIN_VAR_INT: - src= &((sysvar_uint_t*) plugin_var)->def_val; - break; + return &((sysvar_uint_t*) pv)->def_val; case PLUGIN_VAR_LONG: - src= &((sysvar_ulong_t*) plugin_var)->def_val; - break; + return &((sysvar_ulong_t*) pv)->def_val; case PLUGIN_VAR_LONGLONG: - src= &((sysvar_ulonglong_t*) plugin_var)->def_val; - break; + return &((sysvar_ulonglong_t*) pv)->def_val; case PLUGIN_VAR_ENUM: - src= &((sysvar_enum_t*) plugin_var)->def_val; - break; + return &((sysvar_enum_t*) pv)->def_val; case PLUGIN_VAR_SET: - src= &((sysvar_set_t*) plugin_var)->def_val; - break; + return &((sysvar_set_t*) pv)->def_val; case PLUGIN_VAR_BOOL: - src= &((sysvar_bool_t*) plugin_var)->def_val; - break; + return &((sysvar_bool_t*) pv)->def_val; case PLUGIN_VAR_STR: - src= &((sysvar_str_t*) plugin_var)->def_val; - break; + return &((sysvar_str_t*) pv)->def_val; case PLUGIN_VAR_DOUBLE: - src= &((sysvar_double_t*) plugin_var)->def_val; - break; + return &((sysvar_double_t*) pv)->def_val; case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_uint_t*) plugin_var)->def_val; - break; + return &((thdvar_uint_t*) pv)->def_val; case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_ulong_t*) plugin_var)->def_val; - break; + return &((thdvar_ulong_t*) pv)->def_val; case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_ulonglong_t*) plugin_var)->def_val; - break; + return &((thdvar_ulonglong_t*) pv)->def_val; case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_enum_t*) plugin_var)->def_val; - break; + return &((thdvar_enum_t*) pv)->def_val; case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_set_t*) plugin_var)->def_val; - break; + return &((thdvar_set_t*) pv)->def_val; case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_bool_t*) plugin_var)->def_val; - break; + return &((thdvar_bool_t*) pv)->def_val; case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_str_t*) plugin_var)->def_val; - break; + return &((thdvar_str_t*) pv)->def_val; case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL: - src= &((thdvar_double_t*) plugin_var)->def_val; - break; + return &((thdvar_double_t*) pv)->def_val; default: DBUG_ASSERT(0); + return NULL; } - } +} + + +bool sys_var_pluginvar::global_update(THD *thd, set_var *var) +{ + DBUG_ASSERT(!is_readonly()); + mysql_mutex_assert_owner(&LOCK_global_system_variables); + + void *tgt= real_value_ptr(thd, OPT_GLOBAL); + const void *src= &var->save_result; + + if (!var->value) + src= var_def_ptr(plugin_var); plugin_var->update(thd, plugin_var, tgt, src); return false; @@ -3869,7 +3840,18 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, *(int*)(opt + 1)= offset= v->offset; if (opt->flags & PLUGIN_VAR_NOCMDOPT) + { + char *val= global_system_variables.dynamic_variables_ptr + offset; + if (((opt->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) && + (opt->flags & PLUGIN_VAR_MEMALLOC)) + { + char *def_val= *(char**)var_def_ptr(opt); + *(char**)val= def_val ? my_strdup(def_val, MYF(0)) : NULL; + } + else + memcpy(val, var_def_ptr(opt), var_storage_size(opt->flags)); continue; + } optname= (char*) memdup_root(mem_root, v->key + 1, (optnamelen= v->name_len) + 1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fcd778d556c..d7a23a41002 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4034,9 +4034,14 @@ Prepared_statement::execute_loop(String *expanded_query, bool error; int reprepare_attempt= 0; iterations= 0; -#ifndef DBUG_OFF - Item *free_list_state= thd->free_list; -#endif + + /* + - In mysql_sql_stmt_execute() we hide all "external" Items + e.g. those created in the "SET STATEMENT" part of the "EXECUTE" query. + - In case of mysqld_stmt_execute() there should not be "external" Items. + */ + DBUG_ASSERT(thd->free_list == NULL); + thd->select_number= select_number_after_prepare; /* Check if we got an error when sending long data */ if (state == Query_arena::STMT_ERROR) @@ -4058,12 +4063,8 @@ Prepared_statement::execute_loop(String *expanded_query, #endif reexecute: - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. - */ - DBUG_ASSERT(thd->free_list == free_list_state); + // Make sure that reprepare() did not create any new Items. + DBUG_ASSERT(thd->free_list == NULL); /* Install the metadata observer. If some metadata version is diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c115ac5f0ec..2a22810b8c2 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2205,6 +2205,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, THD *thd= info->thd; String *packet= info->packet; Log_event_type event_type; + DBUG_ENTER("send_format_descriptor_event"); /** * 1) reset fdev before each log-file @@ -2219,12 +2220,12 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, { info->errmsg= "Out of memory initializing format_description event"; info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; - return 1; + DBUG_RETURN(1); } /* reset transmit packet for the event read from binary log file */ if (reset_transmit_packet(info, info->flags, &ev_offset, &info->errmsg)) - return 1; + DBUG_RETURN(1); /* Try to find a Format_description_log_event at the beginning of @@ -2240,7 +2241,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, if (error) { set_read_error(info, error); - return 1; + DBUG_RETURN(1); } event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET+ev_offset]); @@ -2261,7 +2262,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, sql_print_warning("Failed to find format descriptor event in " "start of binlog: %s", info->log_file_name); - return 1; + DBUG_RETURN(1); } info->current_checksum_alg= get_checksum_alg(packet->ptr() + ev_offset, @@ -2281,7 +2282,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, sql_print_warning("Master is configured to log replication events " "with checksum, but will not send such events to " "slaves that cannot process them"); - return 1; + DBUG_RETURN(1); } uint ev_len= packet->length() - ev_offset; @@ -2295,7 +2296,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; info->errmsg= "Corrupt Format_description event found " "or out-of-memory"; - return 1; + DBUG_RETURN(1); } delete info->fdev; info->fdev= tmp; @@ -2354,7 +2355,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, { info->errmsg= "Failed on my_net_write()"; info->error= ER_UNKNOWN_ERROR; - return 1; + DBUG_RETURN(1); } /* @@ -2374,7 +2375,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, if (error) { set_read_error(info, error); - return 1; + DBUG_RETURN(1); } event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET]); @@ -2386,14 +2387,15 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, if (!sele) { info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; - return 1; + DBUG_RETURN(1); } if (info->fdev->start_decryption(sele)) { info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; info->errmsg= "Could not decrypt binlog: encryption key error"; - return 1; + delete sele; + DBUG_RETURN(1); } delete sele; } @@ -2409,7 +2411,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, /** all done */ - return 0; + DBUG_RETURN(0); } static bool should_stop(binlog_send_info *info) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 89a9eeb1e32..2889e1e1549 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11857,7 +11857,7 @@ void JOIN::join_free() /** Free resources of given join. - @param fill true if we should free all resources, call with full==1 + @param full true if we should free all resources, call with full==1 should be last, before it this function can be called with full==0 @@ -11969,7 +11969,7 @@ void JOIN::cleanup(bool full) /* If we have tmp_join and 'this' JOIN is not tmp_join and tmp_table_param.copy_field's of them are equal then we have to remove - pointer to tmp_table_param.copy_field from tmp_join, because it qill + pointer to tmp_table_param.copy_field from tmp_join, because it will be removed in tmp_table_param.cleanup(). */ tmp_table_param.cleanup(); @@ -15111,20 +15111,9 @@ bool cond_is_datetime_is_null(Item *cond) if (cond->type() == Item::FUNC_ITEM && ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC) { - Item **args= ((Item_func_isnull*) cond)->arguments(); - if (args[0]->type() == Item::FIELD_ITEM) - { - Field *field=((Item_field*) args[0])->field; - - if (((field->type() == MYSQL_TYPE_DATE) || - (field->type() == MYSQL_TYPE_DATETIME)) && - (field->flags & NOT_NULL_FLAG)) - { - return TRUE; - } - } + return ((Item_func_isnull*) cond)->arg_is_datetime_notnull_field(); } - return FALSE; + return false; } @@ -16082,6 +16071,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::CACHE_ITEM: case Item::WINDOW_FUNC_ITEM: // psergey-winfunc: case Item::EXPR_CACHE_ITEM: + case Item::PARAM_ITEM: if (make_copy_field) { DBUG_ASSERT(((Item_result_field*)item)->result_field); @@ -22853,7 +22843,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, err: if (copy) delete [] param->copy_field; // This is never 0 - param->copy_field=0; + param->copy_field= 0; err2: DBUG_RETURN(TRUE); } diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index adbc52d1eec..6de8727876c 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -130,6 +130,128 @@ inline void init_table_list_for_single_stat_table(TABLE_LIST *tbl, } +static Table_check_intact_log_error stat_table_intact; + +static const +TABLE_FIELD_TYPE table_stat_fields[TABLE_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("cardinality") }, + { C_STRING_WITH_LEN("bigint(21)") }, + { NULL, 0 } + }, +}; +static const uint table_stat_pk_col[]= {0,1}; +static const TABLE_FIELD_DEF +table_stat_def= {TABLE_STAT_N_FIELDS, table_stat_fields, 2, table_stat_pk_col }; + +static const +TABLE_FIELD_TYPE column_stat_fields[COLUMN_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("column_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("min_value") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("max_value") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("nulls_ratio") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_length") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_frequency") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("hist_size") }, + { C_STRING_WITH_LEN("tinyint(3)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("hist_type") }, + { C_STRING_WITH_LEN("enum('SINGLE_PREC_HB','DOUBLE_PREC_HB')") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("histogram") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + } +}; +static const uint column_stat_pk_col[]= {0,1,2}; +static const TABLE_FIELD_DEF +column_stat_def= {COLUMN_STAT_N_FIELDS, column_stat_fields, 3, column_stat_pk_col}; + +static const +TABLE_FIELD_TYPE index_stat_fields[INDEX_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("index") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("prefix_arity") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_frequency") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + } +}; +static const uint index_stat_pk_col[]= {0,1,2,3}; +static const TABLE_FIELD_DEF +index_stat_def= {INDEX_STAT_N_FIELDS, index_stat_fields, 4, index_stat_pk_col}; + + /** @brief Open all statistical tables and lock them @@ -140,10 +262,30 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables, Open_tables_backup *backup, bool for_write) { + int rc; + + Dummy_error_handler deh; // suppress errors + thd->push_internal_handler(&deh); init_table_list_for_stat_tables(tables, for_write); init_mdl_requests(tables); - return open_system_tables_for_read(thd, tables, backup); -} + rc= open_system_tables_for_read(thd, tables, backup); + thd->pop_internal_handler(); + + + /* If the number of tables changes, we should revise the check below. */ + DBUG_ASSERT(STATISTICS_TABLES == 3); + + if (!rc && + (stat_table_intact.check(tables[TABLE_STAT].table, &table_stat_def) || + stat_table_intact.check(tables[COLUMN_STAT].table, &column_stat_def) || + stat_table_intact.check(tables[INDEX_STAT].table, &index_stat_def))) + { + close_system_tables(thd, backup); + rc= 1; + } + + return rc; +} /** @@ -1004,11 +1146,13 @@ public: switch (i) { case COLUMN_STAT_MIN_VALUE: + table_field->read_stats->min_value->set_notnull(); stat_field->val_str(&val); table_field->read_stats->min_value->store(val.ptr(), val.length(), &my_charset_bin); break; case COLUMN_STAT_MAX_VALUE: + table_field->read_stats->max_value->set_notnull(); stat_field->val_str(&val); table_field->read_stats->max_value->store(val.ptr(), val.length(), &my_charset_bin); @@ -2725,10 +2869,7 @@ int update_statistics_for_table(THD *thd, TABLE *table) DEBUG_SYNC(thd, "statistics_update_start"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); DBUG_RETURN(rc); - } save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); @@ -3156,10 +3297,7 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab) DBUG_ENTER("delete_statistics_for_table"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); DBUG_RETURN(rc); - } save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); @@ -3398,10 +3536,7 @@ int rename_table_in_stat_tables(THD *thd, LEX_STRING *db, LEX_STRING *tab, DBUG_ENTER("rename_table_in_stat_tables"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); - DBUG_RETURN(rc); - } + DBUG_RETURN(0); // not an error save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); @@ -3661,17 +3796,8 @@ double get_column_range_cardinality(Field *field, { double avg_frequency= col_stats->get_avg_frequency(); res= avg_frequency; - /* - psergey-todo: what does check for min_value, max_value mean? - min/max_value are set to NULL in alloc_statistics_for_table() and - alloc_statistics_for_table_share(). Both functions will immediately - call create_min_max_statistical_fields_for_table and - create_min_max_statistical_fields_for_table_share() respectively, - which will set min/max_value to be valid pointers, unless OOM - occurs. - */ if (avg_frequency > 1.0 + 0.000001 && - col_stats->min_value && col_stats->max_value) + col_stats->min_max_values_are_provided()) { Histogram *hist= &col_stats->histogram; if (hist->is_available()) @@ -3694,7 +3820,7 @@ double get_column_range_cardinality(Field *field, } else { - if (col_stats->min_value && col_stats->max_value) + if (col_stats->min_max_values_are_provided()) { double sel, min_mp_pos, max_mp_pos; diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index daffd792ba0..f46583839d1 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -52,7 +52,8 @@ enum enum_table_stat_col { TABLE_STAT_DB_NAME, TABLE_STAT_TABLE_NAME, - TABLE_STAT_CARDINALITY + TABLE_STAT_CARDINALITY, + TABLE_STAT_N_FIELDS }; enum enum_column_stat_col @@ -67,7 +68,8 @@ enum enum_column_stat_col COLUMN_STAT_AVG_FREQUENCY, COLUMN_STAT_HIST_SIZE, COLUMN_STAT_HIST_TYPE, - COLUMN_STAT_HISTOGRAM + COLUMN_STAT_HISTOGRAM, + COLUMN_STAT_N_FIELDS }; enum enum_index_stat_col @@ -76,7 +78,8 @@ enum enum_index_stat_col INDEX_STAT_TABLE_NAME, INDEX_STAT_INDEX_NAME, INDEX_STAT_PREFIX_ARITY, - INDEX_STAT_AVG_FREQUENCY + INDEX_STAT_AVG_FREQUENCY, + INDEX_STAT_N_FIELDS }; inline @@ -389,6 +392,11 @@ public: avg_frequency= (ulong) (val * Scale_factor_avg_frequency); } + bool min_max_values_are_provided() + { + return !is_null(COLUMN_STAT_MIN_VALUE) && + !is_null(COLUMN_STAT_MIN_VALUE); + } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f8a61b641c0..b22f831ddab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -671,7 +671,7 @@ static bool read_ddl_log_file_entry(uint entry_no) bool error= FALSE; File file_id= global_ddl_log.file_id; uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf; - uint io_size= global_ddl_log.io_size; + size_t io_size= global_ddl_log.io_size; DBUG_ENTER("read_ddl_log_file_entry"); mysql_mutex_assert_owner(&LOCK_gdl); @@ -2441,7 +2441,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (table_type && table_type != view_pseudo_hton) ha_lock_engine(thd, table_type); - if (thd->locked_tables_mode) + if (thd->locked_tables_mode == LTM_LOCK_TABLES || + thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) { if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) { @@ -3103,8 +3104,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions) @param key_info Key meta-data info. @param key_list List of existing keys. */ -static void check_duplicate_key(THD *thd, - Key *key, KEY *key_info, +static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, List<Key> *key_list) { /* @@ -3166,14 +3166,11 @@ static void check_duplicate_key(THD *thd, // Report a warning if we have two identical keys. - DBUG_ASSERT(thd->lex->query_tables->alias); if (all_columns_are_identical) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DUP_INDEX, ER_THD(thd, ER_DUP_INDEX), - key_info->name, - thd->lex->query_tables->db, - thd->lex->query_tables->alias); + key_info->name); break; } } diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 5ef036965b8..cad4bae03e8 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -929,7 +929,10 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, my_bool neg= 0; enum enum_mysql_timestamp_type time_type= ltime->time_type; - if ((ulong) interval.day > MAX_DAY_NUMBER) + if (((ulonglong) interval.day + + (ulonglong) interval.hour / 24 + + (ulonglong) interval.minute / 24 / 60 + + (ulonglong) interval.second / 24 / 60 / 60) > MAX_DAY_NUMBER) goto invalid_date; if (time_type != MYSQL_TIMESTAMP_TIME) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2cd84a27d45..ff4a5e12e56 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15720,6 +15720,7 @@ grant_role: CHARSET_INFO *cs= system_charset_info; /* trim end spaces (as they'll be lost in mysql.user anyway) */ $1.length= cs->cset->lengthsp(cs, $1.str, $1.length); + $1.str[$1.length] = '\0'; if ($1.length == 0) my_yyabort_error((ER_INVALID_ROLE, MYF(0), "")); if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 27e6463eb58..bdfedc30d46 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3236,7 +3236,7 @@ static bool fix_table_open_cache(sys_var *, THD *, enum_var_type) static Sys_var_ulong Sys_table_cache_size( "table_open_cache", "The number of cached open tables", GLOBAL_VAR(tc_size), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, 512*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT), + VALID_RANGE(1, 1024*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_table_open_cache)); @@ -5042,8 +5042,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave( GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static Sys_var_mybool Sys_wsrep_dirty_reads( - "wsrep_dirty_reads", "Do not reject SELECT queries even when the node " - "is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE, + "wsrep_dirty_reads", + "Allow reads even when the node is not in the primary component.", + SESSION_VAR(wsrep_dirty_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG); static Sys_var_uint Sys_wsrep_gtid_domain_id( diff --git a/sql/table.cc b/sql/table.cc index 71c70e2df2e..4688b77ecd7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4203,6 +4203,15 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) } +void Table_check_intact_log_error::report_error(uint, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + error_log_print(ERROR_LEVEL, fmt, args); + va_end(args); +} + + /** Traverse portion of wait-for graph which is reachable through edge represented by this flush ticket in search for deadlocks. diff --git a/sql/table.h b/sql/table.h index c2c523181a0..6552a8e13da 100644 --- a/sql/table.h +++ b/sql/table.h @@ -480,6 +480,16 @@ public: }; +/* + If the table isn't valid, report the error to the server log only. +*/ +class Table_check_intact_log_error : public Table_check_intact +{ +protected: + void report_error(uint, const char *fmt, ...); +}; + + /** Class representing the fact that some thread waits for table share to be flushed. Is used to represent information about diff --git a/sql/table_cache.cc b/sql/table_cache.cc index 6a6b8ab827e..2feace30672 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -964,6 +964,8 @@ void tdc_release_share(TABLE_SHARE *share) mysql_mutex_lock(&share->tdc->LOCK_table_share); if (--share->tdc->ref_count) { + if (!share->is_view) + mysql_cond_broadcast(&share->tdc->COND_release); mysql_mutex_unlock(&share->tdc->LOCK_table_share); mysql_mutex_unlock(&LOCK_unused_shares); DBUG_VOID_RETURN; diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 2308f4277d6..643ff80de2a 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -84,17 +84,16 @@ struct Worker_thread_context void save() { -#ifdef HAVE_PSI_INTERFACE - psi_thread= PSI_server?PSI_server->get_thread():0; +#ifdef HAVE_PSI_THREAD_INTERFACE + psi_thread = PSI_THREAD_CALL(get_thread)(); #endif mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys); } void restore() { -#ifdef HAVE_PSI_INTERFACE - if (PSI_server) - PSI_server->set_thread(psi_thread); +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_THREAD_CALL(set_thread)(psi_thread); #endif pthread_setspecific(THR_KEY_mysys,mysys_var); pthread_setspecific(THR_THD, 0); @@ -102,6 +101,41 @@ struct Worker_thread_context }; +#ifdef HAVE_PSI_INTERFACE + +/* + The following fixes PSI "idle" psi instrumentation. + The server assumes that connection becomes idle + just before net_read_packet() and switches to active after it. + In out setup, server becomes idle when async socket io is made. +*/ + +extern void net_before_header_psi(struct st_net *net, void *user_data, size_t); + +static void dummy_before_header(struct st_net *, void *, size_t) +{ +} + +static void re_init_net_server_extension(THD *thd) +{ + thd->m_net_server_extension.m_before_header = dummy_before_header; +} + +#else + +#define re_init_net_server_extension(thd) + +#endif /* HAVE_PSI_INTERFACE */ + + +static inline void set_thd_idle(THD *thd) +{ + thd->net.reading_or_writing= 1; +#ifdef HAVE_PSI_INTERFACE + net_before_header_psi(&thd->net, thd, 0); +#endif +} + /* Attach/associate the connection with the OS thread, */ @@ -110,10 +144,10 @@ static void thread_attach(THD* thd) pthread_setspecific(THR_KEY_mysys,thd->mysys_var); thd->thread_stack=(char*)&thd; thd->store_globals(); -#ifdef HAVE_PSI_INTERFACE - if (PSI_server) - PSI_server->set_thread(thd->event_scheduler.m_psi); +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_THREAD_CALL(set_thread)(thd->event_scheduler.m_psi); #endif + mysql_socket_set_thread_owner(thd->net.vio->mysql_socket); } /* @@ -188,8 +222,6 @@ error: static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) { THD *thd= NULL; - int error=1; - /* Create a new connection context: mysys_thread_var and PSI thread @@ -222,45 +254,40 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) thd->event_scheduler.data= scheduler_data; /* Create new PSI thread for use with the THD. */ -#ifdef HAVE_PSI_INTERFACE - if (PSI_server) - { - thd->event_scheduler.m_psi = - PSI_server->new_thread(key_thread_one_connection, thd, thd->thread_id); - } +#ifdef HAVE_PSI_THREAD_INTERFACE + thd->event_scheduler.m_psi= + PSI_THREAD_CALL(new_thread)(key_thread_one_connection, thd, thd->thread_id); #endif /* Login. */ thread_attach(thd); + re_init_net_server_extension(thd); ulonglong now= microsecond_interval_timer(); thd->prior_thr_create_utime= now; thd->start_utime= now; thd->thr_create_utime= now; - if (!setup_connection_thread_globals(thd)) - { - if (!thd_prepare_connection(thd)) - { - - /* - Check if THD is ok, as prepare_new_connection_state() - can fail, for example if init command failed. - */ - if (thd_is_connection_alive(thd)) - { - error= 0; - thd->net.reading_or_writing= 1; - thd->skip_wait_timeout= true; - } - } - } - if (error) - { - threadpool_remove_connection(thd); - thd= NULL; - } + if (setup_connection_thread_globals(thd)) + goto end; + + if (thd_prepare_connection(thd)) + goto end; + + /* + Check if THD is ok, as prepare_new_connection_state() + can fail, for example if init command failed. + */ + if (!thd_is_connection_alive(thd)) + goto end; + + thd->skip_wait_timeout= true; + set_thd_idle(thd); return thd; + +end: + threadpool_remove_connection(thd); + return NULL; } @@ -325,12 +352,13 @@ static int threadpool_process_request(THD *thd) goto end; } + set_thd_idle(thd); + vio= thd->net.vio; if (!vio->has_data(vio)) { /* More info on this debug sync is in sql_parse.cc*/ DEBUG_SYNC(thd, "before_do_command_net_read"); - thd->net.reading_or_writing= 1; goto end; } } diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index 059aabe7b46..cef59513485 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -72,6 +72,9 @@ Format_description_log_event* wsrep_get_apply_format(THD* thd) { return (Format_description_log_event*) thd->wsrep_apply_format; } + + DBUG_ASSERT(thd->wsrep_rgi); + return thd->wsrep_rgi->rli->relay_log.description_event_for_exec; } @@ -361,8 +364,10 @@ wsrep_cb_status_t wsrep_commit_cb(void* const ctx, else rcode = wsrep_rollback(thd); + /* Cleanup */ wsrep_set_apply_format(thd, NULL); thd->mdl_context.release_transactional_locks(); + thd->reset_query(); /* Mutex protected */ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 7884df586a1..08b7e3f1e3d 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -442,11 +442,13 @@ void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, size_t buf_len) { + DBUG_ENTER("wsrep_dump_rbr_buf_with_header"); + char filename[PATH_MAX]= {0}; File file; IO_CACHE cache; Log_event_writer writer(&cache); - Format_description_log_event *ev= wsrep_get_apply_format(thd); + Format_description_log_event *ev; int len= my_snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld_v2.log", wsrep_data_home_dir, (longlong) thd->thread_id, @@ -455,7 +457,7 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, if (len >= PATH_MAX) { WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); - return; + DBUG_VOID_RETURN; } if ((file= mysql_file_open(key_file_wsrep_gra_log, filename, @@ -477,6 +479,13 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, goto cleanup2; } + /* + Instantiate an FDLE object for non-wsrep threads (to be written + to the dump file). + */ + ev= (thd->wsrep_applier) ? wsrep_get_apply_format(thd) : + (new Format_description_log_event(4)); + if (writer.write(ev) || my_b_write(&cache, (uchar*)rbr_buf, buf_len) || flush_io_cache(&cache)) { @@ -489,5 +498,9 @@ cleanup2: cleanup1: mysql_file_close(file, MYF(MY_WME)); + + if (!thd->wsrep_applier) delete ev; + + DBUG_VOID_RETURN; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 68ce59c0665..b0275fc2fd5 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -983,6 +983,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask) { return (thd->variables.wsrep_sync_wait & mask) && thd->variables.wsrep_on && + !(thd->variables.wsrep_dirty_reads && + !is_update_query(thd->lex->sql_command)) && !thd->in_active_multi_stmt_transaction() && thd->wsrep_conflict_state != REPLAYING && thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED; diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index d35514344eb..03cd8674242 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -525,13 +525,11 @@ static void* sst_joiner_thread (void* a) } else { // Scan state ID first followed by wsrep_gtid_domain_id. - char uuid[512]; unsigned long int domain_id; - size_t len= pos - out + 1; - if (len > sizeof(uuid)) goto err; // safety check - memcpy(uuid, out, len); // including '\0' - err= sst_scan_uuid_seqno (uuid, &ret_uuid, &ret_seqno); + // Null-terminate the state-id. + out[pos - out]= 0; + err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno); if (err) { |