From 0248fb2e8a3c6a02f443140cfcf68a0190354e23 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Thu, 18 Aug 2016 09:56:48 +0530 Subject: Bug #23135667: CRASH AFTER DEEPLY NESTED BUILD_EQUAL_ITEMS_FOR_COND Problem: When build_equal_items_for_cond gets called for a big query recursively, the specified thread_stack_size exceeds. But optimizer does not handle this condition. As a result, server exits. Solution: Check if we exceed specified stack size and if yes exit gracefully by throwing an error. --- sql/sql_select.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fb705e9ba6a..80d4b87e916 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8154,6 +8154,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, COND_EQUAL cond_equal; cond_equal.upper_levels= inherited; + if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL)) + return cond; // Fatal error flag is set! + if (cond->type() == Item::COND_ITEM) { List eq_list; -- cgit v1.2.1 From 8dc642112c83c73969f37dbb12b9fe8f546fd42a Mon Sep 17 00:00:00 2001 From: Sivert Sorumgard Date: Mon, 22 Aug 2016 14:30:02 +0200 Subject: Bug#24388753: PRIVILEGE ESCALATION USING MYSQLD_SAFE [This is the 5.5/5.6 version of the bugfix]. The problem was that it was possible to write log files ending in .ini/.cnf that later could be parsed as an options file. This made it possible for users to specify startup options without the permissions to do so. This patch fixes the problem by disallowing general query log and slow query log to be written to files ending in .ini and .cnf. --- sql/log.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- sql/log.h | 10 +++++++ sql/mysqld.cc | 18 +++++++++++- sql/sys_vars.cc | 25 ++++++++++------ 4 files changed, 131 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 50d7762af6d..493aae8f2ff 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2293,6 +2293,77 @@ bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name, } +bool is_valid_log_name(const char *name, size_t len) +{ + if (len > 3) + { + const char *tail= name + len - 4; + if (my_strcasecmp(system_charset_info, tail, ".ini") == 0 || + my_strcasecmp(system_charset_info, tail, ".cnf") == 0) + { + return false; + } + } + return true; +} + + +/** + Get the real log file name, and possibly reopen file. + + Use realpath() to get the path with symbolic links + expanded. Then, close the file, and reopen the real path using the + O_NOFOLLOW flag. This will reject following symbolic links. + + @param file File descriptor. + @param log_file_key Key for P_S instrumentation. + @param open_flags Flags to use for opening the file. + @param opened_file_name Name of the open fd. + + @retval file descriptor to open file with 'real_file_name', or '-1' + in case of errors. +*/ + +#ifndef _WIN32 +static File mysql_file_real_name_reopen(File file, +#ifdef HAVE_PSI_INTERFACE + PSI_file_key log_file_key, +#endif + int open_flags, + const char *opened_file_name) +{ + DBUG_ASSERT(file); + DBUG_ASSERT(opened_file_name); + + /* Buffer for realpath must have capacity for PATH_MAX. */ + char real_file_name[PATH_MAX]; + + /* Get realpath, validate, open realpath with O_NOFOLLOW. */ + if (realpath(opened_file_name, real_file_name) == NULL) + { + (void) mysql_file_close(file, MYF(0)); + return -1; + } + + if (mysql_file_close(file, MYF(0))) + return -1; + + if (strlen(real_file_name) > FN_REFLEN) + return -1; + + if (!is_valid_log_name(real_file_name, strlen(real_file_name))) + { + sql_print_error("Invalid log file name after expanding symlinks: '%s'", + real_file_name); + return -1; + } + + return mysql_file_open(log_file_key, real_file_name, + open_flags | O_NOFOLLOW, + MYF(MY_WME | ME_WAITTANG)); +} +#endif // _WIN32 + /* Open a (new) log file. @@ -2358,8 +2429,22 @@ bool MYSQL_LOG::open( if ((file= mysql_file_open(log_file_key, log_file_name, open_flags, - MYF(MY_WME | ME_WAITTANG))) < 0 || - init_io_cache(&log_file, file, IO_SIZE, io_cache_type, + MYF(MY_WME | ME_WAITTANG))) < 0) + goto err; + +#ifndef _WIN32 + /* Reopen and validate path. */ + if ((log_type_arg == LOG_UNKNOWN || log_type_arg == LOG_NORMAL) && + (file= mysql_file_real_name_reopen(file, +#ifdef HAVE_PSI_INTERFACE + log_file_key, +#endif + open_flags, + log_file_name)) < 0) + goto err; +#endif // _WIN32 + + if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type, mysql_file_tell(file, MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP | ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0)))) diff --git a/sql/log.h b/sql/log.h index b5e751386a6..d3ecba41964 100644 --- a/sql/log.h +++ b/sql/log.h @@ -717,6 +717,16 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, char *make_log_name(char *buff, const char *name, const char* log_ext); +/** + Check given log name against certain blacklisted names/extensions. + + @param name Log name to check + @param len Length of log name + + @returns true if name is valid, false otherwise. +*/ +bool is_valid_log_name(const char *name, size_t len); + extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; extern LOGGER logger; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a2532ceddd3..e979ea1b731 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify @@ -3512,6 +3512,22 @@ static int init_common_variables() "--log-slow-queries option, log tables are used. " "To enable logging to files use the --log-output=file option."); + if (opt_logname && + !is_valid_log_name(opt_logname, strlen(opt_logname))) + { + sql_print_error("Invalid value for --general_log_file: %s", + opt_logname); + return 1; + } + + if (opt_slow_logname && + !is_valid_log_name(opt_slow_logname, strlen(opt_slow_logname))) + { + sql_print_error("Invalid value for --slow_query_log_file: %s", + opt_slow_logname); + return 1; + } + #define FIX_LOG_VAR(VAR, ALT) \ if (!VAR || !*VAR) \ { \ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b0fa7f9a341..d08cb4f8ca8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2810,6 +2810,14 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) if (!var->save_result.string_value.str) return true; + if (!is_valid_log_name(var->save_result.string_value.str, + var->save_result.string_value.length)) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), + self->name.str, var->save_result.string_value.str); + return true; + } + if (var->save_result.string_value.length > FN_REFLEN) { // path is too long my_error(ER_PATH_LENGTH, MYF(0), self->name.str); @@ -2856,7 +2864,7 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return false; } static bool fix_log(char** logname, const char* default_logname, - const char*ext, bool enabled, void (*reopen)(char*)) + const char*ext, bool enabled, bool (*reopen)(char*)) { if (!*logname) // SET ... = DEFAULT { @@ -2868,16 +2876,17 @@ static bool fix_log(char** logname, const char* default_logname, } logger.lock_exclusive(); mysql_mutex_unlock(&LOCK_global_system_variables); + bool error= false; if (enabled) - reopen(*logname); + error= reopen(*logname); logger.unlock(); mysql_mutex_lock(&LOCK_global_system_variables); - return false; + return error; } -static void reopen_general_log(char* name) +static bool reopen_general_log(char* name) { logger.get_log_file_handler()->close(0); - logger.get_log_file_handler()->open_query_log(name); + return logger.get_log_file_handler()->open_query_log(name); } static bool fix_general_log_file(sys_var *self, THD *thd, enum_var_type type) { @@ -2890,10 +2899,10 @@ static Sys_var_charptr Sys_general_log_path( IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_log_path), ON_UPDATE(fix_general_log_file)); -static void reopen_slow_log(char* name) +static bool reopen_slow_log(char* name) { logger.get_slow_log_file_handler()->close(0); - logger.get_slow_log_file_handler()->open_slow_log(name); + return logger.get_slow_log_file_handler()->open_slow_log(name); } static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type) { -- cgit v1.2.1 From 55a2babcefc9a9f46534f8e6e4b5ca12d94c1105 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 19 Aug 2016 12:06:16 +0200 Subject: Bug#24400628: DEBUG ASSETION KICKS IN WHEN LONG SUBPARTITION NAME IS USED IN CREATE TABLE The problem was that using a very long subpartition name could lead to the server exiting abnormally. This patch fixes the problem by reporting ER_TOO_LONG_IDENT if a name with more than 64 characters are used as partition and subpartition name. --- sql/sql_yacc.yy | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b8ddc8bd49f..2ca36e23652 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4655,6 +4655,12 @@ part_name: { partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; + if (check_string_char_length(&$1, "", NAME_CHAR_LEN, + system_charset_info, true)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + MYSQL_YYABORT; + } p_elem->partition_name= $1.str; } ; @@ -4949,7 +4955,15 @@ sub_part_definition: sub_name: ident_or_text - { Lex->part_info->curr_part_elem->partition_name= $1.str; } + { + if (check_string_char_length(&$1, "", NAME_CHAR_LEN, + system_charset_info, true)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + MYSQL_YYABORT; + } + Lex->part_info->curr_part_elem->partition_name= $1.str; + } ; opt_part_options: -- cgit v1.2.1 From 97fad8518bdce19938fdf55cbb5858e31e9ac464 Mon Sep 17 00:00:00 2001 From: Kailasnath Nagarkar Date: Fri, 26 Aug 2016 11:11:27 +0530 Subject: Bug #23303485 : HANDLE_FATAL_SIGNAL (SIG=11) IN SUBSELECT_UNION_ENGINE::NO_ROWS This patch is specific for mysql-5.5 ISSUE: When max_join_size is used and union query results in evaluation of tuples greater than max_join_size, the join object is not created, and is set to NULL. However, this join object is further dereferenced by union logic to determine if query resulted in any number of rows being returned. Since, the object is NULL, it results in program terminating abnormally. SOLUTION: Added check to verify if join object is created. If join object is created, it will be used to determine if query resulted in any number of rows. Else, when join object is not created, we return 'false' indicating that there were no rows for the query. --- sql/item_subselect.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 43af0b5a3f6..21c897da2be 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1789,8 +1789,12 @@ bool subselect_union_engine::is_executed() const bool subselect_union_engine::no_rows() { + bool rows_present= false; + /* Check if we got any rows when reading UNION result from temp. table: */ - return test(!unit->fake_select_lex->join->send_records); + if (unit->fake_select_lex->join) + rows_present= test(!unit->fake_select_lex->join->send_records); + return rows_present; } void subselect_uniquesubquery_engine::cleanup() -- cgit v1.2.1 From aeab9d6b417871a2893df710c690be0de53e0c7a Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 29 Aug 2016 11:41:50 +0530 Subject: Bug#23303391: HANDLE_FATAL_SIGNAL (SIG=11) IN ALLOC_QUERY USING CHARACTER-SET-SERVER=UTF16 This is a backport of Bug#15985752 to mysql-5.5 --- sql/mysqld.cc | 21 ++++++++++++++++++--- sql/sql_acl.cc | 10 ++++++++-- sql/sql_connect.cc | 10 +++++++++- 3 files changed, 35 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e979ea1b731..d8edbe4b637 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3482,9 +3482,24 @@ static int init_common_variables() /* Set collactions that depends on the default collation */ global_system_variables.collation_server= default_charset_info; global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; + + if (is_supported_parser_charset(default_charset_info)) + { + global_system_variables.collation_connection= default_charset_info; + global_system_variables.character_set_results= default_charset_info; + global_system_variables.character_set_client= default_charset_info; + } + else + { + sql_print_information("'%s' can not be used as client character set. " + "'%s' will be used as default client character set.", + default_charset_info->csname, + my_charset_latin1.csname); + global_system_variables.collation_connection= &my_charset_latin1; + global_system_variables.character_set_results= &my_charset_latin1; + global_system_variables.character_set_client= &my_charset_latin1; + } + if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, MY_CS_PRIMARY, MYF(MY_WME)))) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5ff6f38d18d..99394878a55 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8789,7 +8789,10 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, { mpvio->client_capabilities= uint4korr(end); mpvio->max_client_packet_length= 0xfffff; - charset_code= default_charset_info->number; + charset_code= global_system_variables.character_set_client->number; + sql_print_warning("Client failed to provide its character set. " + "'%s' will be used as client character set.", + global_system_variables.character_set_client->csname); if (mpvio->charset_adapter->init_client_charset(charset_code)) return packet_error; goto skip_to_ssl; @@ -8826,7 +8829,10 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, Old clients didn't have their own charset. Instead the assumption was that they used what ever the server used. */ - charset_code= default_charset_info->number; + charset_code= global_system_variables.character_set_client->number; + sql_print_warning("Client failed to provide its character set. " + "'%s' will be used as client character set.", + global_system_variables.character_set_client->csname); } DBUG_EXECUTE_IF("host_error_charset", { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index ed0b20a0e34..f1ee34f3d09 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -431,6 +431,14 @@ bool thd_init_client_charset(THD *thd, uint cs_number) global_system_variables.character_set_client->name, cs->name)) { + if (!is_supported_parser_charset( + global_system_variables.character_set_client)) + { + /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */ + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + global_system_variables.character_set_client->csname); + return true; + } thd->variables.character_set_client= global_system_variables.character_set_client; thd->variables.collation_connection= -- cgit v1.2.1 From 91ddaff991d745d6b2308342a2555d302a13a481 Mon Sep 17 00:00:00 2001 From: Kailasnath Nagarkar Date: Fri, 2 Sep 2016 15:13:52 +0530 Subject: Bug #24489302 : ZEROFILL CAUSE MEMORY-CORRUPTION AND CRASH ISSUE: Heap corruption occurs and hence mysql server terminates abnormally in String variable destructor when ZEROFILL is used for a column. Though the abnormal termination is observed in the String destructor, heap corruption occurs at earlier stage when function Field_num::prepend_zeros() is called. This function, prepends zeros to the actual data and works on entire field length. Since the allocated memory could be less than the field length, heap corruption occurs. Later, when String destructor tries to free heap, the server terminates abnormally since the heap is corrupt. SOLUTION: In Field_num::prepend_zeros() function, if allocated memory is less than the field length, re-allocate memory enough to hold field length size data. --- sql/field.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 3ca072e7771..15571afefb8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1130,12 +1130,15 @@ void Field_num::prepend_zeros(String *value) int diff; if ((diff= (int) (field_length - value->length())) > 0) { - bmove_upp((uchar*) value->ptr()+field_length, - (uchar*) value->ptr()+value->length(), - value->length()); - bfill((uchar*) value->ptr(),diff,'0'); - value->length(field_length); - (void) value->c_ptr_quick(); // Avoid warnings in purify + const bool error= value->realloc(field_length); + if (!error) + { + bmove_upp((uchar*) value->ptr()+field_length, + (uchar*) value->ptr()+value->length(), + value->length()); + bfill((uchar*) value->ptr(),diff,'0'); + value->length(field_length); + } } } -- cgit v1.2.1 From ac143744a90d1069f0b4f8a47516cdcca915fbfa Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Wed, 28 Sep 2016 15:52:05 +0530 Subject: Bug#24707666: DEFAULT SETTING FOR SECURE-FILE-PRIV SHOULD BE RESTRICTED IN ALL GA RELEASES Back port of WL#6782 to 5.5 and 5.6. This also includes back port of Bug#20771331, Bug#20741572 and Bug#20770671. Bug#24695274 and Bug#24679907 are also handled along with this. --- sql/mysqld.cc | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++----- sql/sql_class.cc | 2 + sql/sql_class.h | 1 + sql/sys_vars.cc | 8 +- 4 files changed, 234 insertions(+), 21 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d8edbe4b637..c969fd8a62a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -570,6 +570,7 @@ uint mysql_real_data_home_len, mysql_data_home_len= 1; uint reg_ext_length; const key_map key_map_empty(0); key_map key_map_full(0); // Will be initialized later +char secure_file_real_path[FN_REFLEN]; DATE_TIME_FORMAT global_date_format, global_datetime_format, global_time_format; Time_zone *default_tz; @@ -7613,9 +7614,9 @@ bool is_secure_file_path(char *path) char buff1[FN_REFLEN], buff2[FN_REFLEN]; size_t opt_secure_file_priv_len; /* - All paths are secure if opt_secure_file_path is 0 + All paths are secure if opt_secure_file_priv is 0 */ - if (!opt_secure_file_priv) + if (!opt_secure_file_priv[0]) return TRUE; opt_secure_file_priv_len= strlen(opt_secure_file_priv); @@ -7623,6 +7624,9 @@ bool is_secure_file_path(char *path) if (strlen(path) >= FN_REFLEN) return FALSE; + if (!my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + return FALSE; + if (my_realpath(buff1, path, 0)) { /* @@ -7655,9 +7659,184 @@ bool is_secure_file_path(char *path) } +/** + check_secure_file_priv_path : Checks path specified through + --secure-file-priv and raises warning in following cases: + 1. If path is empty string or NULL and mysqld is not running + with --bootstrap mode. + 2. If path can access data directory + 3. If path points to a directory which is accessible by + all OS users (non-Windows build only) + + It throws error in following cases: + + 1. If path normalization fails + 2. If it can not get stats of the directory + + @params NONE + + Assumptions : + 1. Data directory path has been normalized + 2. opt_secure_file_priv has been normalized unless it is set + to "NULL". + + @returns Status of validation + @retval true : Validation is successful with/without warnings + @retval false : Validation failed. Error is raised. +*/ + +bool check_secure_file_priv_path() +{ + char datadir_buffer[FN_REFLEN+1]={0}; + char plugindir_buffer[FN_REFLEN+1]={0}; + char whichdir[20]= {0}; + size_t opt_plugindir_len= 0; + size_t opt_datadir_len= 0; + size_t opt_secure_file_priv_len= 0; + bool warn= false; + bool case_insensitive_fs; +#ifndef _WIN32 + MY_STAT dir_stat; +#endif + + if (!opt_secure_file_priv[0]) + { + if (opt_bootstrap) + { + /* + Do not impose --secure-file-priv restriction + in --bootstrap mode + */ + sql_print_information("Ignoring --secure-file-priv value as server is " + "running with --bootstrap."); + } + else + { + sql_print_warning("Insecure configuration for --secure-file-priv: " + "Current value does not restrict location of generated " + "files. Consider setting it to a valid, " + "non-empty path."); + } + return true; + } + + /* + Setting --secure-file-priv to NULL would disable + reading/writing from/to file + */ + if(!my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + { + sql_print_information("--secure-file-priv is set to NULL. " + "Operations related to importing and exporting " + "data are disabled"); + return true; + } + + /* + Check if --secure-file-priv can access data directory + */ + opt_secure_file_priv_len= strlen(opt_secure_file_priv); + + /* + Adds dir seperator at the end. + This is required in subsequent comparison + */ + convert_dirname(datadir_buffer, mysql_unpacked_real_data_home, NullS); + opt_datadir_len= strlen(datadir_buffer); + + case_insensitive_fs= + (test_if_case_insensitive(datadir_buffer) == 1); + + if (!case_insensitive_fs) + { + if (!strncmp(datadir_buffer, opt_secure_file_priv, + opt_datadir_len < opt_secure_file_priv_len ? + opt_datadir_len : opt_secure_file_priv_len)) + { + warn= true; + strcpy(whichdir, "Data directory"); + } + } + else + { + if (!files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) datadir_buffer, + opt_datadir_len, + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + { + warn= true; + strcpy(whichdir, "Data directory"); + } + } + + /* + Don't bother comparing --secure-file-priv with --plugin-dir + if we already have a match against --datadir or + --plugin-dir is not pointing to a valid directory. + */ + if (!warn && !my_realpath(plugindir_buffer, opt_plugin_dir, 0)) + { + convert_dirname(plugindir_buffer, plugindir_buffer, NullS); + opt_plugindir_len= strlen(plugindir_buffer); + + if (!case_insensitive_fs) + { + if (!strncmp(plugindir_buffer, opt_secure_file_priv, + opt_plugindir_len < opt_secure_file_priv_len ? + opt_plugindir_len : opt_secure_file_priv_len)) + { + warn= true; + strcpy(whichdir, "Plugin directory"); + } + } + else + { + if (!files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) plugindir_buffer, + opt_plugindir_len, + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + { + warn= true; + strcpy(whichdir, "Plugin directory"); + } + } + } + + + if (warn) + sql_print_warning("Insecure configuration for --secure-file-priv: " + "%s is accessible through " + "--secure-file-priv. Consider choosing a different " + "directory.", whichdir); + +#ifndef _WIN32 + /* + Check for --secure-file-priv directory's permission + */ + if (!(my_stat(opt_secure_file_priv, &dir_stat, MYF(0)))) + { + sql_print_error("Failed to get stat for directory pointed out " + "by --secure-file-priv"); + return false; + } + + if (dir_stat.st_mode & S_IRWXO) + sql_print_warning("Insecure configuration for --secure-file-priv: " + "Location is accessible to all OS users. " + "Consider choosing a different directory."); +#endif + return true; +} + + static int fix_paths(void) { char buff[FN_REFLEN],*pos; + bool secure_file_priv_nonempty= false; convert_dirname(mysql_home,mysql_home,NullS); /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */ my_realpath(mysql_home,mysql_home,MYF(0)); @@ -7715,29 +7894,56 @@ static int fix_paths(void) Convert the secure-file-priv option to system format, allowing a quick strcmp to check if read or write is in an allowed dir */ - if (opt_secure_file_priv) + if (opt_bootstrap) + opt_secure_file_priv= EMPTY_STR.str; + secure_file_priv_nonempty= opt_secure_file_priv[0] ? true : false; + + if (secure_file_priv_nonempty && strlen(opt_secure_file_priv) > FN_REFLEN) { - if (*opt_secure_file_priv == 0) - { - my_free(opt_secure_file_priv); - opt_secure_file_priv= 0; - } - else + sql_print_warning("Value for --secure-file-priv is longer than maximum " + "limit of %d", FN_REFLEN-1); + return 1; + } + + memset(buff, 0, sizeof(buff)); + if (secure_file_priv_nonempty && + my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + { + int retval= my_realpath(buff, opt_secure_file_priv, MYF(MY_WME)); + if (!retval) { - if (strlen(opt_secure_file_priv) >= FN_REFLEN) - opt_secure_file_priv[FN_REFLEN-1]= '\0'; - if (my_realpath(buff, opt_secure_file_priv, 0)) + convert_dirname(secure_file_real_path, buff, NullS); +#ifdef WIN32 + MY_DIR *dir= my_dir(secure_file_real_path, MYF(MY_DONT_SORT+MY_WME)); + if (!dir) { - sql_print_warning("Failed to normalize the argument for --secure-file-priv."); - return 1; + retval= 1; } - char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); - convert_dirname(secure_file_real_path, buff, NullS); - my_free(opt_secure_file_priv); - opt_secure_file_priv= secure_file_real_path; + else + { + my_dirend(dir); + } +#endif + } + + if (retval) + { + char err_buffer[FN_REFLEN]; + my_snprintf(err_buffer, FN_REFLEN-1, + "Failed to access directory for --secure-file-priv." + " Please make sure that directory exists and is " + "accessible by MySQL Server. Supplied value : %s", + opt_secure_file_priv); + err_buffer[FN_REFLEN-1]='\0'; + sql_print_error("%s", err_buffer); + return 1; } + opt_secure_file_priv= secure_file_real_path; } - + + if (!check_secure_file_priv_path()) + return 1; + return 0; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0696021cfc0..d9fda85d8f6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -68,6 +68,8 @@ char internal_table_name[2]= "*"; char empty_c_string[1]= {0}; /* used for not defined db */ +LEX_STRING EMPTY_STR= { (char *) "", 0 }; + const char * const THD::DEFAULT_WHERE= "field list"; diff --git a/sql/sql_class.h b/sql/sql_class.h index dcc7458ee50..aa6745e4564 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -105,6 +105,7 @@ enum enum_filetype { FILETYPE_CSV, FILETYPE_XML }; extern char internal_table_name[2]; extern char empty_c_string[1]; +extern LEX_STRING EMPTY_STR; extern MYSQL_PLUGIN_IMPORT const char **errmesg; extern bool volatile shutdown_in_progress; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index d08cb4f8ca8..6fd728d638d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1941,8 +1941,12 @@ static Sys_var_charptr Sys_secure_file_priv( "secure_file_priv", "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files " "within specified directory", - PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv), - CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(0)); + READ_ONLY GLOBAL_VAR(opt_secure_file_priv), +#ifndef EMBEDDED_LIBRARY + CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(DEFAULT_SECURE_FILE_PRIV_DIR)); +#else + CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR)); +#endif static bool fix_server_id(sys_var *self, THD *thd, enum_var_type type) { -- cgit v1.2.1 From 149212772804e93983f80b63099ba9e1241ddf4f Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Thu, 13 Oct 2016 14:48:45 +0530 Subject: BUG#23499695: MYSQL SERVER NORMAL SHUTDOWN WITH TIME STAMP 700101 ANALYSIS: ========= To set the time 'start_time' of query in THD, current time is obtained by calling 'gettimeofday()'. On Solaris platform, due to some system level issues, time obtained is invalid i.e. its either greater than 2038 (max signed value to hold microseconds since 1970) or 1970 (0 microseconds since 1970). In these cases, validation checks infer that the 'start_time' is invalid and mysql server initiates the shutdown process. But the reason for shutdown is not logged. FIX: ==== We are now logging appropriate message when shutdown is triggered in the above mentioned scenarios. Now, even if the initial validation checks infer that the 'start_time' is invalid, server shutdown is not initiated immediately. Before initiating the server shutdown, the process of setting 'start_time' and validating it is reiterated (for max 5 times). If correct time is obtained in these 5 iterations then server continues to run. --- sql/sql_parse.cc | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fd3623c6148..ac3901997f3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -889,17 +889,47 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - if (!thd->is_valid_time()) + if (thd->is_valid_time() == false) { /* - If the time has got past 2038 we need to shut this server down - We do this by making sure every command is a shutdown and we - have enough privileges to shut the server down - - TODO: remove this when we have full 64 bit my_time_t support + If the time has gone past 2038 we need to shutdown the server. But + there is possibility of getting invalid time value on some platforms. + For example, gettimeofday() might return incorrect value on solaris + platform. Hence validating the current time with 5 iterations before + initiating the normal server shutdown process because of time getting + past 2038. */ - thd->security_ctx->master_access|= SHUTDOWN_ACL; - command= COM_SHUTDOWN; + const int max_tries= 5; + sql_print_warning("Current time has got past year 2038. Validating current " + "time with %d iterations before initiating the normal " + "server shutdown process.", max_tries); + + int tries= 0; + while (++tries <= max_tries) + { + thd->set_time(); + if (thd->is_valid_time() == true) + { + sql_print_warning("Iteration %d: Obtained valid current time from " + "system", tries); + break; + } + sql_print_warning("Iteration %d: Current time obtained from system is " + "greater than 2038", tries); + } + if (tries > max_tries) + { + /* + If the time has got past 2038 we need to shut this server down. + We do this by making sure every command is a shutdown and we + have enough privileges to shut the server down + + TODO: remove this when we have full 64 bit my_time_t support + */ + sql_print_error("This MySQL server doesn't support dates later than 2038"); + thd->security_ctx->master_access|= SHUTDOWN_ACL; + command= COM_SHUTDOWN; + } } thd->set_query_id(next_query_id()); inc_thread_running(); -- cgit v1.2.1 From c3cf7f47f0f4a1ec314001aaf0c3d9c1c1f62097 Mon Sep 17 00:00:00 2001 From: Thayumanavar S Date: Fri, 28 Oct 2016 14:45:03 +0200 Subject: BUG#24487120 - SLAVE'S SLAVE_SQL_RUNNING IS STOPPED DURING LOAD DATA AT MASTER. Revert "BUG#23080148 - BACKPORT BUG 14653594 AND BUG 20683959 TO" This reverts commit 1d31f5b3090d129382b50b95512f2f79305715a1. The commit causes replication incompatibility between minor revisions and based on discussion with Srinivasarao, the patch is reverted. --- sql/sql_load.cc | 77 +++++++++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 49 deletions(-) (limited to 'sql') diff --git a/sql/sql_load.cc b/sql/sql_load.cc index a46967a24a8..c084e5e3839 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1363,8 +1363,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, set_if_bigger(length,line_start.length()); stack=stack_pos=(int*) sql_alloc(sizeof(int)*length); - if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME)))) - error= true; /* purecov: inspected */ + if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0)))) + error=1; /* purecov: inspected */ else { end_of_buff=buffer+buff_length; @@ -1556,50 +1556,37 @@ int READ_INFO::read_field() } } #ifdef USE_MB - uint ml= my_mbcharlen(read_charset, chr); - if (ml == 0) - { - *to= '\0'; - my_error(ER_INVALID_CHARACTER_STRING, MYF(0), - read_charset->csname, buffer); - error= true; - return 1; - } + if (my_mbcharlen(read_charset, chr) > 1 && + to + my_mbcharlen(read_charset, chr) <= end_of_buff) + { + uchar* p= to; + int ml, i; + *to++ = chr; - if (ml > 1 && - to + ml <= end_of_buff) - { - uchar* p= to; - *to++ = chr; + ml= my_mbcharlen(read_charset, chr); - for (uint i= 1; i < ml; i++) + for (i= 1; i < ml; i++) + { + chr= GET; + if (chr == my_b_EOF) { - chr= GET; - if (chr == my_b_EOF) - { - /* - Need to back up the bytes already ready from illformed - multi-byte char - */ - to-= i; - goto found_eof; - } - *to++ = chr; + /* + Need to back up the bytes already ready from illformed + multi-byte char + */ + to-= i; + goto found_eof; } - if (my_ismbchar(read_charset, + *to++ = chr; + } + if (my_ismbchar(read_charset, (const char *)p, (const char *)to)) - continue; - for (uint i= 0; i < ml; i++) - PUSH(*--to); - chr= GET; - } - else if (ml > 1) - { - // Buffer is too small, exit while loop, and reallocate. - PUSH(chr); - break; - } + continue; + for (i= 0; i < ml; i++) + PUSH(*--to); + chr= GET; + } #endif *to++ = (uchar) chr; } @@ -1843,15 +1830,7 @@ int READ_INFO::read_value(int delim, String *val) for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) { #ifdef USE_MB - uint ml= my_mbcharlen(read_charset, chr); - if (ml == 0) - { - chr= my_b_EOF; - val->length(0); - return chr; - } - - if (ml > 1) + if (my_mbcharlen(read_charset, chr) > 1) { DBUG_PRINT("read_xml",("multi byte")); int i, ml= my_mbcharlen(read_charset, chr); -- cgit v1.2.1 From 42732cc195fd237c9b17490e96f1bb29db433b0b Mon Sep 17 00:00:00 2001 From: Dyre Tjeldvoll Date: Thu, 24 Nov 2016 09:57:54 +0100 Subject: Bug#25092566: CREATE TABLE WITH DATA DIRECTORY CLAUSE DOES NOT REQUIRE SPECIAL PRIVILEGES Require FILE privilege when creating tables using external data directory or index directory. --- sql/partition_info.cc | 26 +++++++++++++++++++++++++- sql/partition_info.h | 13 ++++++++++++- sql/sql_parse.cc | 19 ++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/partition_info.cc b/sql/partition_info.cc index a0d09557b81..cd17e3366cf 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2550,6 +2550,30 @@ void partition_info::print_debug(const char *str, uint *value) DBUG_PRINT("info", ("parser: %s", str)); DBUG_VOID_RETURN; } + +bool has_external_data_or_index_dir(partition_info &pi) +{ + List_iterator part_it(pi.partitions); + for (partition_element *part= part_it++; part; part= part_it++) + { + if (part->data_file_name != NULL || part->index_file_name != NULL) + { + return true; + } + List_iterator subpart_it(part->subpartitions); + for (const partition_element *subpart= subpart_it++; + subpart; + subpart= subpart_it++) + { + if (subpart->data_file_name != NULL || subpart->index_file_name != NULL) + { + return true; + } + } + } + return false; +} + #else /* WITH_PARTITION_STORAGE_ENGINE */ /* For builds without partitioning we need to define these functions diff --git a/sql/partition_info.h b/sql/partition_info.h index 7bfbf8a1b1a..7ff6abeebd2 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -1,7 +1,7 @@ #ifndef PARTITION_INFO_INCLUDED #define PARTITION_INFO_INCLUDED -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -349,4 +349,15 @@ void init_all_partitions_iterator(partition_info *part_info, part_iter->get_next= get_next_partition_id_range; } +/** + Predicate which returns true if any partition or subpartition uses + an external data directory or external index directory. + + @param pi partitioning information + @retval true if any partition or subpartition has an external + data directory or external index directory. + @retval false otherwise + */ +bool has_external_data_or_index_dir(partition_info &pi); + #endif /* PARTITION_INFO_INCLUDED */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ac3901997f3..18cb758c9b5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -35,6 +35,9 @@ #include "sql_insert.h" // mysql_insert #include "sql_update.h" // mysql_update, mysql_multi_update #include "sql_partition.h" // struct partition_info +#ifdef WITH_PARTITION_STORAGE_ENGINE +#include "partition_info.h" // has_external_data_or_index_dir +#endif /* WITH_PARTITION_STORAGE_ENGINE */ #include "sql_db.h" // mysql_change_db, mysql_create_db, // mysql_rm_db, mysql_upgrade_db, // mysql_alter_db, @@ -2413,7 +2416,6 @@ case SQLCOM_PREPARE: copy. */ Alter_info alter_info(lex->alter_info, thd->mem_root); - if (thd->is_fatal_error) { /* If out of memory when creating a copy of alter_info. */ @@ -2421,6 +2423,15 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + if (((lex->create_info.used_fields & HA_CREATE_USED_DATADIR) != 0 || + (lex->create_info.used_fields & HA_CREATE_USED_INDEXDIR) != 0) && + check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE)) + { + res= 1; + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "FILE"); + goto end_with_restore_list; + } + if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; @@ -2458,6 +2469,12 @@ case SQLCOM_PREPARE: #ifdef WITH_PARTITION_STORAGE_ENGINE { partition_info *part_info= thd->lex->part_info; + if (part_info != NULL && has_external_data_or_index_dir(*part_info) && + check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE)) + { + res= -1; + goto end_with_restore_list; + } if (part_info && !(part_info= thd->lex->part_info->get_clone(true))) { res= -1; -- cgit v1.2.1 From 52ea5ad865b4f6b4b37176296a3be0a716c5109a Mon Sep 17 00:00:00 2001 From: SachinSetiya Date: Thu, 1 Dec 2016 11:24:04 +0530 Subject: MDEV-11016 wsrep_node_is_ready() check is too strict Problem:- The condition that checks for node readiness is too strict as it does not allow SELECTs even if these selects do not access any tables. For example,if we run SELECT 1; OR SELECT @@max_allowed_packet; Solution:- We need not to report this error when all_tables(lex->query_tables) is NULL: --- sql/sql_parse.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ed1b7a5323..11613fac026 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2635,11 +2635,15 @@ mysql_execute_command(THD *thd) /* Bail out if DB snapshot has not been installed. We however, allow SET and SHOW queries. + SHOW and SELECT queries (only if wsrep_dirty_reads is set or when it + does not access ant table) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && + !(lex->sql_command == SQLCOM_SELECT && + !all_table) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, -- cgit v1.2.1 From 55b4579633ec81481823b3dfaa45674db6416a50 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 5 Dec 2016 16:28:29 -0500 Subject: Fix build failure. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 11613fac026..53350751d79 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2643,7 +2643,7 @@ mysql_execute_command(THD *thd) !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && !(lex->sql_command == SQLCOM_SELECT && - !all_table) && + !all_tables) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, -- cgit v1.2.1 From ffdd1e9d888edc4e147c3b316a87468b000f8dd4 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Wed, 14 Dec 2016 13:57:05 +0530 Subject: Revert "MDEV-11016 wsrep_node_is_ready() check is too strict" This reverts commit 52ea5ad865b4f6b4b37176296a3be0a716c5109a. # Conflicts: # mysql-test/suite/galera/r/galera_var_dirty_reads.result # mysql-test/suite/galera/t/galera_var_dirty_reads.test # sql/sql_parse.cc --- sql/sql_parse.cc | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 53350751d79..4ed1b7a5323 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2635,15 +2635,11 @@ mysql_execute_command(THD *thd) /* Bail out if DB snapshot has not been installed. We however, allow SET and SHOW queries. - SHOW and SELECT queries (only if wsrep_dirty_reads is set or when it - does not access ant table) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && - !(lex->sql_command == SQLCOM_SELECT && - !all_tables) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, -- cgit v1.2.1 From 4c1e181ac5eac55c67705ffe29b48a5d832211be Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Wed, 14 Dec 2016 15:22:04 +0530 Subject: MDEV-11479 Improved wsrep_dirty_reads Tasks:- Changes in wsrep_dirty_reads variable 1.) Global + Session scope (Current: session-only) 2.) Can be set using command line. 3.) Allow all commands that do not change data (besides SELECT) 4.) Allow prepared Statements that do not change data 5.) Works with wsrep_sync_wait enabled --- sql/sql_parse.cc | 9 ++++++--- sql/sys_vars.cc | 5 +++-- sql/wsrep_mysqld.cc | 4 ++++ sql/wsrep_mysqld.h | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ed1b7a5323..d92ef810498 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2633,13 +2633,16 @@ mysql_execute_command(THD *thd) } /* - Bail out if DB snapshot has not been installed. We however, - allow SET and SHOW queries. + 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 (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && - lex->sql_command == SQLCOM_SELECT) && + !is_update_query(lex->sql_command)) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index af440d7ac44..93a863d6b88 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4811,8 +4811,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); #endif /* WITH_WSREP */ diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 13b72b65afe..353911dcfde 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -71,6 +71,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave // restart will be needed my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks +// Allow reads even if the node is not in the primary component. +bool wsrep_dirty_reads = false; /* Set during the creation of first wsrep applier and rollback threads. @@ -816,6 +818,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_mysqld.h b/sql/wsrep_mysqld.h index 57382d27e98..5ec183f7186 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -88,6 +88,7 @@ extern ulong wsrep_retry_autocommit; extern my_bool wsrep_auto_increment_control; extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_incremental_data_collection; +extern bool wsrep_dirty_reads; extern const char* wsrep_start_position; extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; -- cgit v1.2.1 From e86580c3dda707788fb0ca35244cf602d7e8d50d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 15 Dec 2016 18:20:58 +0100 Subject: MDEV-11552 Queries executed by event scheduler are written to slow log incorrectly or not written at all because thd->update_server_status() is used to measure the query time for the slow log (not only to set protocol level flags), it needs to be called also when the server isn't going to send anything to the client. --- sql/sp_head.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 019e9d9a478..9bfa60a07d3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3146,18 +3146,18 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) thd->query_length()) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); + bool log_slow= !res && thd->enable_slow_log; - if (thd->stmt_da->is_eof()) - { - /* Finalize server status flags after executing a statement. */ + /* Finalize server status flags after executing a statement. */ + if (log_slow || thd->stmt_da->is_eof()) thd->update_server_status(); + if (thd->stmt_da->is_eof()) thd->protocol->end_statement(); - } query_cache_end_of_result(thd); - if (!res && unlikely(thd->enable_slow_log)) + if (log_slow) log_slow_statement(thd); } else -- cgit v1.2.1 From b2b210b891697f999a9f85037462d54f78707e3e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Dec 2016 17:42:21 +0100 Subject: MDEV-11543 Buildbot tests fail with warnings on server shutdown after rpl.rpl_row_mysqlbinlog double the timeout for threads to die on shutdown --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8eb92cafc03..ea4fa823d29 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1462,7 +1462,7 @@ static void close_connections(void) end_slave(); /* Give threads time to die. */ - for (int i= 0; thread_count && i < 100; i++) + for (int i= 0; thread_count && i < 200; i++) my_sleep(20000); /* -- cgit v1.2.1 From c4d9dc705b781bb155aab8f04cece2b87116d3c1 Mon Sep 17 00:00:00 2001 From: iangilfillan Date: Fri, 16 Dec 2016 14:44:08 +0200 Subject: Typo, update limit in comment --- sql/item_subselect.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6427b0ecae4..dda9986f60f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4352,9 +4352,9 @@ bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) result= result_sink; /* - If the subquery has blobs, or the total key lenght is bigger than + If the subquery has blobs, or the total key length is bigger than some length, or the total number of key parts is more than the - allowed maximum (currently MAX_REF_PARTS == 16), then the created + allowed maximum (currently MAX_REF_PARTS == 32), then the created index cannot be used for lookups and we can't use hash semi join. If this is the case, delete the temporary table since it will not be used, and tell the caller we failed to initialize the -- cgit v1.2.1 From 2f6fede8d5f7e98319b4b7b557bd565fdb42fac3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 19 Dec 2016 14:28:08 +0400 Subject: MDEV-10524 Assertion `arg1_int >= 0' failed in Item_func_additive_op::result_precision() This change is a backport from 10.0 to 5.5 for: 1. The full patch for: MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() 9adb6e991ec87b65d04929f115d9d0c899e4ab19 2. A small fragment of: MDEV-5298 Illegal mix of collations on timestamp 03f6778d61a74bdd7d09103a16473a2a5624cf66 which overrides Item_temporal_hybrid_func::cmp_type(), and adds a new line into cache_temporal_4265.result. --- sql/item_func.h | 1 + sql/item_strfunc.cc | 2 +- sql/item_strfunc.h | 1 - sql/item_timefunc.cc | 29 ++++++++++++++++++++---- sql/item_timefunc.h | 62 ++++++++++++++++++++++++++++++++++++++++++---------- sql/sql_const.h | 2 +- sql/sql_time.cc | 17 ++++++++++++++ sql/sql_time.h | 2 ++ 8 files changed, 97 insertions(+), 19 deletions(-) (limited to 'sql') diff --git a/sql/item_func.h b/sql/item_func.h index 667be3c0438..0da38e22c7f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -39,6 +39,7 @@ protected: 0 means get this number from first argument */ uint allowed_arg_cols; + String *val_str_from_val_str_ascii(String *str, String *str2); void count_only_length(Item **item, uint nitems); void count_real_length(Item **item, uint nitems); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 94370d45cef..ec9580bfabd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -70,7 +70,7 @@ size_t username_char_length= 16; Normally conversion does not happen, and val_str_ascii() is immediately returned instead. */ -String *Item_str_func::val_str_from_val_str_ascii(String *str, String *str2) +String *Item_func::val_str_from_val_str_ascii(String *str, String *str2) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 7606c281548..00ae60a7fb1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -62,7 +62,6 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref); - String *val_str_from_val_str_ascii(String *str, String *str2); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 28e93683422..420fb29f518 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1455,25 +1455,29 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) void Item_temporal_func::fix_length_and_dec() { + uint char_length= mysql_temporal_int_part_length(field_type()); /* We set maybe_null to 1 as default as any bad argument with date or time can get us to return NULL. */ maybe_null= 1; - max_length= mysql_temporal_int_part_length(field_type()); + if (decimals) { if (decimals == NOT_FIXED_DEC) - max_length+= TIME_SECOND_PART_DIGITS + 1; + char_length+= TIME_SECOND_PART_DIGITS + 1; else { set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - max_length+= decimals + 1; + char_length+= decimals + 1; } } sql_mode= current_thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); - collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + collation.set(field_type() == MYSQL_TYPE_STRING ? + default_charset() : &my_charset_numeric, + DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + fix_char_length(char_length); } String *Item_temporal_func::val_str(String *str) @@ -1483,6 +1487,23 @@ String *Item_temporal_func::val_str(String *str) } +String *Item_temporal_hybrid_func::val_str_ascii(String *str) +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + + if (get_date(<ime, 0) || + (null_value= my_TIME_to_str(<ime, str, decimals))) + return (String *) 0; + + /* Check that the returned timestamp type matches to the function type */ + DBUG_ASSERT(cached_field_type == MYSQL_TYPE_STRING || + ltime.time_type == MYSQL_TIMESTAMP_NONE || + mysql_type_to_time_type(cached_field_type) == ltime.time_type); + return str; +} + + bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { longlong value=args[0]->val_int(); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 3a03ee4b27a..0062d500835 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -506,6 +506,50 @@ public: }; +/** + Abstract class for functions returning TIME, DATE, DATETIME or string values, + whose data type depends on parameters and is set at fix_fields time. +*/ +class Item_temporal_hybrid_func: public Item_temporal_func +{ +protected: + enum_field_types cached_field_type; // TIME, DATE, DATETIME or STRING + String ascii_buf; // Conversion buffer +public: + Item_temporal_hybrid_func(Item *a,Item *b) + :Item_temporal_func(a,b) {} + enum_field_types field_type() const { return cached_field_type; } + Item_result cmp_type() const + { + return cached_field_type == MYSQL_TYPE_STRING ? + STRING_RESULT : TIME_RESULT; + } + const CHARSET_INFO *charset_for_protocol() const + { + /* + Can return TIME, DATE, DATETIME or VARCHAR depending on arguments. + Send using "binary" when TIME, DATE or DATETIME, + or using collation.collation when VARCHAR + (which is fixed from @@collation_connection in fix_length_and_dec). + */ + DBUG_ASSERT(fixed == 1); + return cached_field_type == MYSQL_TYPE_STRING ? + collation.collation : &my_charset_bin; + } + /** + Return string value in ASCII character set. + */ + String *val_str_ascii(String *str); + /** + Return string value in @@character_set_connection. + */ + String *val_str(String *str) + { + return val_str_from_val_str_ascii(str, &ascii_buf); + } +}; + + class Item_datefunc :public Item_temporal_func { public: @@ -763,17 +807,15 @@ public: }; -class Item_date_add_interval :public Item_temporal_func +class Item_date_add_interval :public Item_temporal_hybrid_func { - enum_field_types cached_field_type; public: const interval_type int_type; // keep it public const bool date_sub_interval; // keep it public Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg) - :Item_temporal_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} + :Item_temporal_hybrid_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} const char *func_name() const { return "date_add_interval"; } void fix_length_and_dec(); - enum_field_types field_type() const { return cached_field_type; } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); @@ -911,16 +953,14 @@ public: }; -class Item_func_add_time :public Item_temporal_func +class Item_func_add_time :public Item_temporal_hybrid_func { const bool is_date; int sign; - enum_field_types cached_field_type; public: Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) - :Item_temporal_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } - enum_field_types field_type() const { return cached_field_type; } + :Item_temporal_hybrid_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } void fix_length_and_dec(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); void print(String *str, enum_query_type query_type); @@ -1019,9 +1059,8 @@ public: }; -class Item_func_str_to_date :public Item_temporal_func +class Item_func_str_to_date :public Item_temporal_hybrid_func { - enum_field_types cached_field_type; timestamp_type cached_timestamp_type; bool const_item; String subject_converter; @@ -1029,12 +1068,11 @@ class Item_func_str_to_date :public Item_temporal_func CHARSET_INFO *internal_charset; public: Item_func_str_to_date(Item *a, Item *b) - :Item_temporal_func(a, b), const_item(false), + :Item_temporal_hybrid_func(a, b), const_item(false), internal_charset(NULL) {} bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *func_name() const { return "str_to_date"; } - enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); }; diff --git a/sql/sql_const.h b/sql/sql_const.h index 9d227601a20..3c127a03826 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -54,7 +54,7 @@ #define MIN_TIME_WIDTH 10 /* -HHH:MM:SS */ #define MAX_TIME_WIDTH 16 /* -DDDDDD HH:MM:SS */ #define MAX_TIME_FULL_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ -#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */ +#define MAX_DATETIME_FULL_WIDTH 26 /* YYYY-MM-DD HH:MM:SS.###### */ #define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */ #define MAX_DATETIME_PRECISION 6 diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c5c65391758..d912a7b78d6 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -838,6 +838,23 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, } } + +/** + Convert TIME/DATE/DATETIME value to String. + @param l_time DATE value + @param OUT str String to convert to + @param dec Number of fractional digits. +*/ +bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec) +{ + if (str->alloc(MAX_DATE_STRING_REP_LENGTH)) + return true; + str->set_charset(&my_charset_numeric); + str->length(my_TIME_to_str(ltime, const_cast(str->ptr()), dec)); + return false; +} + + void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, const ErrConv *sval, diff --git a/sql/sql_time.h b/sql/sql_time.h index ad752121044..9becdcd4200 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -74,6 +74,8 @@ extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format); const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, timestamp_type type); +bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec); + /* MYSQL_TIME operations */ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval); -- cgit v1.2.1 From 19896d4b3ab459d135aee6ee67cb92bce92f9b87 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 19 Dec 2016 16:09:20 +0400 Subject: MDEV-10274 Bundling insert with create statement for table with unsigned Decimal primary key issues warning 1194. Flags are important for key_length calculations, so them should be set before it, not after. --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7d2e67b5cfd..9bcb4c3f8cc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3167,7 +3167,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->pack_length= dup_field->pack_length; sql_field->key_length= dup_field->key_length; sql_field->decimals= dup_field->decimals; - sql_field->create_length_to_internal_length(); sql_field->unireg_check= dup_field->unireg_check; /* We're making one field from two, the result field will have @@ -3177,6 +3176,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields--; sql_field->flags= dup_field->flags; + sql_field->create_length_to_internal_length(); sql_field->interval= dup_field->interval; sql_field->vcol_info= dup_field->vcol_info; sql_field->stored_in_db= dup_field->stored_in_db; -- cgit v1.2.1 From 268bb69beaec027b9f713d13316aa78c5c292817 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 16 Dec 2016 17:08:31 +0300 Subject: MDEV-7691: Assertion `outer_context || !*from_field || *from_field == not_found_field' ... The bug occurred when a subquery - has a reference to outside, to grand-parent query or further up - is converted to a semi-join (i.e. merged into its parent). Then the reference to outside had form Item_ref(Item_field(...)). - Conversion to semi-join would call item->fix_after_pullout() for the outside reference. - Item_ref::fix_after_pullout would call Item_field->fix_after_pullout - The Item_field would construct a new Name_resolution_context object This process ignored the fact that the Item_field does not belong to any of the subselects being flattened. The result was crash in the next call to Item_field::fix_fields(), where we would try to use an invalid Name_resolution_context object. Fixed by not creating Name_resolution_context object if the Item_field's context does not belong to the subselect(s) that were flattened. --- sql/item.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 53666aaf83d..fc9eb31bf5b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2777,6 +2777,44 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) depended_from= NULL; if (context) { + bool need_change= false; + /* + Suppose there are nested selects: + + select_id=1 + select_id=2 + select_id=3 <----+ + select_id=4 -+ + select_id=5 --+ + + Suppose, pullout operation has moved anything that had select_id=4 or 5 + in to select_id=3. + + If this Item_field had a name resolution context pointing into select_lex + with id=4 or id=5, it needs a new name resolution context. + + However, it could also be that this object is a part of outer reference: + Item_ref(Item_field(field in select with select_id=1))). + - The Item_ref object has a context with select_id=5, and so needs a new + name resolution context. + - The Item_field object has a context with select_id=1, and doesn't need + a new name resolution context. + + So, the following loop walks from Item_field's current context upwards. + If we find that the select we've been pulled out to is up there, we + create the new name resolution context. Otherwise, we don't. + */ + for (Name_resolution_context *ct= context; ct; ct= ct->outer_context) + { + if (new_parent == ct->select_lex) + { + need_change= true; + break; + } + } + if (!need_change) + return; + Name_resolution_context *ctx= new Name_resolution_context(); if (context->select_lex == new_parent) { -- cgit v1.2.1 From f23b41b9b8a30e0e54a1ec7a8923057b0e57e0f5 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 16 Dec 2016 17:16:02 +0300 Subject: MDEV-10148: Database crashes in the query to the View Fix st_select_lex::is_merged_child_of to work across merged views or derived tables. --- sql/sql_lex.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f2e7b4f7c3a..fa866bc7008 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4247,6 +4247,12 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) { continue; } + + if (sl->master_unit()->derived && + sl->master_unit()->derived->is_merged_derived()) + { + continue; + } all_merged= FALSE; break; } -- cgit v1.2.1 From aaff3d6c35f51dde60907f3c0fc4b2a40bc63c38 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 20 Dec 2016 10:25:25 +0100 Subject: MDEV-10172: UNION query returns incorrect rows outside conditional evaluation count duplicate of UNION SELECT separately to awoid influence on lokal LIMIT clause. --- sql/sql_select.cc | 13 +++++++++---- sql/sql_select.h | 5 +++-- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8c994964d59..839665f3a9f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2871,7 +2871,7 @@ JOIN::exec() *curr_fields_list), Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); error= do_select(curr_join, curr_fields_list, NULL, procedure); - thd->limit_found_rows= curr_join->send_records; + thd->limit_found_rows= curr_join->send_records - curr_join->duplicate_rows; /* Accumulate the counts from all join iterations of all join parts. */ thd->examined_row_count+= curr_join->examined_rows; @@ -16578,7 +16578,7 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) join->join_tab[join->top_join_tab_count - 1].next_select= end_select; join_tab=join->join_tab+join->const_tables; } - join->send_records=0; + join->duplicate_rows= join->send_records=0; if (join->table_count == join->const_tables) { /* @@ -18089,7 +18089,12 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int error; /* result < 0 if row was not accepted and should not be counted */ if ((error= join->result->send_data(*join->fields))) - DBUG_RETURN(error < 0 ? NESTED_LOOP_OK : NESTED_LOOP_ERROR); + { + if (error > 0) + DBUG_RETURN(NESTED_LOOP_ERROR); + // error < 0 => duplicate row + join->duplicate_rows++; + } } if (++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) @@ -18205,7 +18210,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (error < 0) { /* Duplicate row, don't count */ - join->send_records--; + join->duplicate_rows++; error= 0; } } diff --git a/sql/sql_select.h b/sql/sql_select.h index 4650bc24c68..0623672840e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1018,7 +1018,8 @@ public: table_map outer_join; /* Bitmap of tables used in the select list items */ table_map select_list_used_tables; - ha_rows send_records,found_records,examined_rows,row_limit, select_limit; + ha_rows send_records, found_records, examined_rows, + row_limit, select_limit, duplicate_rows; /** Used to fetch no more than given amount of rows per one fetch operation of server side cursor. @@ -1272,7 +1273,7 @@ public: sort_and_group= 0; first_record= 0; do_send_rows= 1; - send_records= 0; + duplicate_rows= send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; examined_rows= 0; -- cgit v1.2.1 From e025ebcdb538ee6d191d22aee0587f5534080a4b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 20 Dec 2016 12:45:48 +0000 Subject: Fix pointer formatting in crash handler output. Do not use 0x%p to output thd address, use %p --- sql/signal_handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index b0c67fbfe32..81792cc30ac 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -143,7 +143,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) if (opt_stack_trace) { - my_safe_printf_stderr("Thread pointer: 0x%p\n", thd); + my_safe_printf_stderr("Thread pointer: %p\n", thd); my_safe_printf_stderr("%s", "Attempting backtrace. You can use the following " "information to find out\n" -- cgit v1.2.1 From cbd7548aff7536940cf6c619c4de4f51c1f9e0bb Mon Sep 17 00:00:00 2001 From: Ronak Jain Date: Thu, 8 Dec 2016 23:27:04 +0530 Subject: MDEV-11353: fixes Identical logical conditions --- sql/handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 5fc75602039..bc71aa57fb7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3924,7 +3924,7 @@ void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info, stat_info->update_time= stats.update_time; stat_info->check_time= stats.check_time; stat_info->check_sum= 0; - if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_OLD_CHECKSUM)) + if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM)) stat_info->check_sum= checksum(); return; } -- cgit v1.2.1 From 5e051bfa15d201228b103d7f536436a61cde8707 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 21 Dec 2016 15:39:45 +0400 Subject: MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) The patch b96c196f1cd5d77e524cbf952539bdd33c65ffc1 added a new call for safe_charset_converter() without a corresponding fix_fields(). In case of a sub-query the created Item remained in non-fixed state. The problem did not show up with literal derived expressions, only subselects were affected. This patch adds a corresponding fix_fields() to the previously added safe_charset_converter(). --- sql/item.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index fc9eb31bf5b..1df91dc2534 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1164,7 +1164,8 @@ Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs) if (conv == example) return this; Item_cache *cache; - if (!conv || !(cache= new Item_cache_str(conv))) + if (!conv || conv->fix_fields(current_thd, (Item **) NULL) || + !(cache= new Item_cache_str(conv))) return NULL; // Safe conversion is not possible, or OEM cache->setup(conv); cache->fixed= false; // Make Item::fix_fields() happy -- cgit v1.2.1 From 706fb790bcf9105a73f34002fe28c75032267c4b Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 22 Dec 2016 15:51:37 +0530 Subject: MDEV-10927: Crash When Using sort_union Optimization In file sql/filesort.cc,when merge_buffers() is called then - queue_remove(&queue,0) is called - For the function queue_remove there is assertion states that the element to be removed should have index >=1 - this is causing the assertion to fail. Fixed by removing the top element. --- sql/filesort.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/filesort.cc b/sql/filesort.cc index 5bb5c64409a..38404b01cf7 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1411,7 +1411,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, if (!(error= (int) read_to_buffer(from_file, buffpek, rec_length))) { - queue_remove(&queue,0); + (void) queue_remove_top(&queue); reuse_freed_buff(&queue, buffpek, rec_length); } else if (error == -1) -- cgit v1.2.1 From c8e49f2f57b7e8c9dcf3cdb108dc15e6b63b4dc4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 20 Dec 2016 15:17:59 +0100 Subject: move check_user/set_user from mysqld.cc to mysys --- sql/mysqld.cc | 83 ++++++++--------------------------------------------------- 1 file changed, 11 insertions(+), 72 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ea4fa823d29..11e9176861d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -121,10 +121,7 @@ extern "C" { // Because of SCO 3.2V4.2 #include #endif #ifdef HAVE_PWD_H -#include // For getpwent -#endif -#ifdef HAVE_GRP_H -#include +#include // For struct passwd #endif #include @@ -455,9 +452,7 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; -#ifdef HAVE_INITGROUPS volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ -#endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_extra_port; uint mysqld_port_timeout; @@ -2001,59 +1996,18 @@ static void set_ports() static struct passwd *check_user(const char *user) { -#if !defined(__WIN__) - struct passwd *tmp_user_info; - uid_t user_id= geteuid(); + myf flags= 0; + if (global_system_variables.log_warnings) + flags|= MY_WME; + if (!opt_bootstrap && !opt_help) + flags|= MY_FAE; - // Don't bother if we aren't superuser - if (user_id) - { - if (user) - { - /* Don't give a warning, if real user is same as given with --user */ - /* purecov: begin tested */ - tmp_user_info= getpwnam(user); - if ((!tmp_user_info || user_id != tmp_user_info->pw_uid) && - global_system_variables.log_warnings) - sql_print_warning( - "One can only use the --user switch if running as root\n"); - /* purecov: end */ - } - return NULL; - } - if (!user) - { - if (!opt_bootstrap && !opt_help) - { - sql_print_error("Fatal error: Please consult the Knowledge Base " - "to find out how to run mysqld as root!\n"); - unireg_abort(1); - } - return NULL; - } - /* purecov: begin tested */ - if (!strcmp(user,"root")) - return NULL; // Avoid problem with dynamic libraries + struct passwd *tmp_user_info= my_check_user(user, MYF(flags)); - if (!(tmp_user_info= getpwnam(user))) - { - // Allow a numeric uid to be used - const char *pos; - for (pos= user; my_isdigit(mysqld_charset,*pos); pos++) ; - if (*pos) // Not numeric id - goto err; - if (!(tmp_user_info= getpwuid(atoi(user)))) - goto err; - } + if (!tmp_user_info && my_errno==EINVAL && (flags & MY_FAE)) + unireg_abort(1); return tmp_user_info; - /* purecov: end */ - -err: - sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); - unireg_abort(1); -#endif - return NULL; } static inline void allow_coredumps() @@ -2070,10 +2024,6 @@ static inline void allow_coredumps() static void set_user(const char *user, struct passwd *user_info_arg) { - /* purecov: begin tested */ -#if !defined(__WIN__) - DBUG_ASSERT(user_info_arg != 0); -#ifdef HAVE_INITGROUPS /* We can get a SIGSEGV when calling initgroups() on some systems when NSS is configured to use LDAP and the server is statically linked. We set @@ -2081,22 +2031,11 @@ static void set_user(const char *user, struct passwd *user_info_arg) output a specific message to help the user resolve this problem. */ calling_initgroups= 1; - initgroups((char*) user, user_info_arg->pw_gid); + int res= my_set_user(user, user_info_arg, MYF(MY_WME)); calling_initgroups= 0; -#endif - if (setgid(user_info_arg->pw_gid) == -1) - { - sql_perror("setgid"); - unireg_abort(1); - } - if (setuid(user_info_arg->pw_uid) == -1) - { - sql_perror("setuid"); + if (res) unireg_abort(1); - } allow_coredumps(); -#endif - /* purecov: end */ } -- cgit v1.2.1 From e7d7910b7a926ccc6f5b8d73d55ac511f1c03c3d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2016 11:13:07 +0100 Subject: add an assert and use is_supported_parser_charset() instead of direct check --- sql/sql_connect.cc | 16 +++++++--------- sql/sys_vars.cc | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 61f8b4081eb..e2e56c48b3b 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2007, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. + Copyright (c) 2008, 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 @@ -821,6 +821,7 @@ void update_global_user_stats(THD *thd, bool create_user, time_t now) bool thd_init_client_charset(THD *thd, uint cs_number) { + SV *gv=&global_system_variables; CHARSET_INFO *cs; /* Use server character set and collation if @@ -831,16 +832,13 @@ bool thd_init_client_charset(THD *thd, uint cs_number) */ if (!opt_character_set_client_handshake || !(cs= get_charset(cs_number, MYF(0))) || - !my_strcasecmp(&my_charset_latin1, - global_system_variables.character_set_client->name, + !my_strcasecmp(&my_charset_latin1, gv->character_set_client->name, cs->name)) { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.character_set_results= - global_system_variables.character_set_results; + DBUG_ASSERT(is_supported_parser_charset(gv->character_set_client)); + thd->variables.character_set_client= gv->character_set_client; + thd->variables.collation_connection= gv->collation_connection; + thd->variables.character_set_results= gv->character_set_results; } else { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7b898906184..35997525456 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -31,6 +31,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_class.h" // set_var.h: THD +#include "sql_parse.h" #include "sys_vars.h" #include "events.h" @@ -445,7 +446,7 @@ static bool check_cs_client(sys_var *self, THD *thd, set_var *var) return true; // Currently, UCS-2 cannot be used as a client character set - if (((CHARSET_INFO *)(var->save_result.ptr))->mbminlen > 1) + if (!is_supported_parser_charset((CHARSET_INFO *)(var->save_result.ptr))) return true; return false; -- cgit v1.2.1 From ec6d8dadc01269451332e5b24b12a5350a2a4896 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2016 13:02:32 +0100 Subject: reduce code duplication a little --- sql/event_db_repository.cc | 15 +++++++-------- sql/sp_head.cc | 6 +----- sql/sql_parse.cc | 23 ++++++++++++++--------- sql/sql_parse.h | 1 + sql/sql_table.cc | 6 +----- sql/sql_udf.cc | 6 +----- sql/sql_yacc.yy | 12 ++---------- 7 files changed, 27 insertions(+), 42 deletions(-) (limited to 'sql') diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 37dff0da714..673250ffd22 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -17,6 +17,7 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_base.h" // close_thread_tables +#include "sql_parse.h" #include "event_db_repository.h" #include "key.h" // key_copy #include "sql_db.h" // get_default_db_collation @@ -702,19 +703,17 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, restore_record(table, s->default_values); // Get default values for fields - if (system_charset_info->cset-> - numchars(system_charset_info, parse_data->dbname.str, - parse_data->dbname.str + parse_data->dbname.length) > - table->field[ET_FIELD_DB]->char_length()) + if (check_string_char_length(&parse_data->dbname, 0, + table->field[ET_FIELD_DB]->char_length(), + system_charset_info, 1)) { my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str); goto end; } - if (system_charset_info->cset-> - numchars(system_charset_info, parse_data->name.str, - parse_data->name.str + parse_data->name.length) > - table->field[ET_FIELD_NAME]->char_length()) + if (check_string_char_length(&parse_data->name, 0, + table->field[ET_FIELD_NAME]->char_length(), + system_charset_info, 1)) { my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str); goto end; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9bfa60a07d3..69364eaa43f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -488,12 +488,8 @@ check_routine_name(LEX_STRING *ident) my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; } - if (check_string_char_length(ident, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str); + if (check_ident_length(ident)) return TRUE; - } return FALSE; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a3114aba7d3..f000fe1a37d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4329,11 +4329,8 @@ create_sp_error: } case SQLCOM_SHOW_CREATE_TRIGGER: { - if (lex->spname->m_name.length > NAME_LEN) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); + if (check_ident_length(&lex->spname->m_name)) goto error; - } if (show_create_trigger(thd, lex->spname)) goto error; /* Error has been already logged. */ @@ -6019,12 +6016,9 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, LEX *lex= thd->lex; DBUG_ENTER("add_field_to_list"); - if (check_string_char_length(field_name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */ + if (check_ident_length(field_name)) DBUG_RETURN(1); /* purecov: inspected */ - } + if (type_modifier & PRI_KEY_FLAG) { Key *key; @@ -7688,6 +7682,17 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, } +bool check_ident_length(LEX_STRING *ident) +{ + if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str); + return 1; + } + return 0; +} + + /* Check if path does not contain mysql data home directory diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 4c3070d197d..66a8f6efc7d 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -75,6 +75,7 @@ bool check_string_byte_length(LEX_STRING *str, const char *err_msg, bool check_string_char_length(LEX_STRING *str, const char *err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error); +bool check_ident_length(LEX_STRING *ident); CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl); bool check_host_name(LEX_STRING *str); bool check_identifier_name(LEX_STRING *str, uint max_char_length, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9bcb4c3f8cc..2cec480d23b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3312,12 +3312,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp); DBUG_RETURN(TRUE); } - if (check_string_char_length(&key->name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str); + if (check_ident_length(&key->name)) DBUG_RETURN(TRUE); - } key_iterator2.rewind (); if (key->type != Key::FOREIGN_KEY) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 626e5569ccc..d18498de784 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -455,12 +455,8 @@ int mysql_create_function(THD *thd,udf_func *udf) my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0)); DBUG_RETURN(1); } - if (check_string_char_length(&udf->name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str); + if (check_ident_length(&udf->name)) DBUG_RETURN(1); - } /* Turn off row binlogging of this statement and use statement-based diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7d981e03aea..35c7203ca0d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4670,12 +4670,8 @@ part_name: { partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; - if (check_string_char_length(&$1, "", NAME_CHAR_LEN, - system_charset_info, true)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + if (check_ident_length(&$1)) MYSQL_YYABORT; - } p_elem->partition_name= $1.str; } ; @@ -4971,12 +4967,8 @@ sub_part_definition: sub_name: ident_or_text { - if (check_string_char_length(&$1, "", NAME_CHAR_LEN, - system_charset_info, true)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + if (check_ident_length(&$1)) MYSQL_YYABORT; - } Lex->part_info->curr_part_elem->partition_name= $1.str; } ; -- cgit v1.2.1 From 11544334a277508fb984c0a5bba8faa6b97a2762 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 27 Dec 2016 14:13:32 +0530 Subject: MDEV-11636 Extra persistent columns on slave always gets NULL in RBR Problem:- In replication if slave has extra persistent column then these column are not computed while applying write-set from master. Solution:- While applying row events from server, we will generate values for extra persistent columns. --- sql/rpl_record.cc | 31 +++++++++++++++++++++++++++++++ sql/rpl_record.h | 1 + 2 files changed, 32 insertions(+) (limited to 'sql') diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index df8036c40d8..21b8a8028a6 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -407,6 +407,12 @@ unpack_row(rpl_group_info *rgi, } } + /* + Add Extra slave persistent columns + */ + if ((error= fill_extra_persistent_columns(table, cols->n_bits))) + DBUG_RETURN(error); + /* We should now have read all the null bytes, otherwise something is really wrong. @@ -479,5 +485,30 @@ int prepare_record(TABLE *const table, const uint skip, const bool check) DBUG_RETURN(0); } +/** + Fills @c table->record[0] with computed values of extra persistent column which are present on slave but not on master. + @param table Table whose record[0] buffer is prepared. + @param master_cols No of columns on master + @returns 0 on success + */ +int fill_extra_persistent_columns(TABLE *table, int master_cols) +{ + int error= 0; + Field **vfield_ptr, *vfield; + if (!table->vfield) + return 0; + for (vfield_ptr= table->vfield; *vfield_ptr; ++vfield_ptr) + { + vfield= *vfield_ptr; + if (vfield->field_index >= master_cols && vfield->stored_in_db) + { + /*Set bitmap for writing*/ + bitmap_set_bit(table->vcol_set, vfield->field_index); + error= vfield->vcol_info->expr_item->save_in_field(vfield,0); + bitmap_clear_bit(table->vcol_set, vfield->field_index); + } + } + return error; +} #endif // HAVE_REPLICATION diff --git a/sql/rpl_record.h b/sql/rpl_record.h index c10eb8225b0..be69716d9d5 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -38,6 +38,7 @@ int unpack_row(rpl_group_info *rgi, // Fill table's record[0] with default values. int prepare_record(TABLE *const table, const uint skip, const bool check); +int fill_extra_persistent_columns(TABLE *table, int master_cols); #endif #endif -- cgit v1.2.1 From ae1b3d1991b679bb38095711de27934d7683deda Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 5 Jan 2017 13:54:31 -0800 Subject: Fixed bug mdev-10705. The fix for bug mdev-5104 did not take into account that for any call of setup_order the size of ref_array must be big enough. This patch fixes this problem. --- sql/sql_select.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c406fab5a3a..2c65c59ad7e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -714,10 +714,15 @@ JOIN::prepare(Item ***rref_pointer_array, if (mixed_implicit_grouping && tbl->table) tbl->table->maybe_null= 1; } + + uint real_og_num= og_num; + if (skip_order_by && + select_lex != select_lex->master_unit()->global_parameters) + real_og_num+= select_lex->order_list.elements; if ((wild_num && setup_wild(thd, tables_list, fields_list, &all_fields, wild_num)) || - select_lex->setup_ref_array(thd, og_num) || + select_lex->setup_ref_array(thd, real_og_num) || setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ, &all_fields, 1) || setup_without_group(thd, (*rref_pointer_array), tables_list, -- cgit v1.2.1 From ab93a4d4df7206833fa4a8eb0aa47b8ba185da60 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Wed, 11 Jan 2017 09:05:36 -0500 Subject: MDEV-11685: sql_mode can't be set with non-ascii connection charset The supplied sql_mode(s) should be converted to ASCII first, before comparing it with the sql_mode set. --- sql/sys_vars.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 3cbd24f1c89..dbe27ab107e 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -1141,7 +1141,7 @@ public: if (var->value->result_type() == STRING_RESULT) { - if (!(res=var->value->val_str(&str))) + if (!(res=var->value->val_str_ascii(&str))) return true; else { -- cgit v1.2.1 From 0d1d0d77f2a72d9cb6de0489dceb37644caf9037 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 11 Jan 2017 19:12:21 +0100 Subject: MDEV-11706 Assertion `is_stat_field || !table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || (table->vcol_set && bitmap_is_set(table->vcol_set, field_index)))' failed in Field_time::store_TIME_with_warning vcols and triggers. Revert 094f4cf77890c5a747a57cf2bed149b0b6933507, backport the correct fix (Table_triggers_list::mark_fields_used() not marking vcols) from 10.2. --- sql/sql_base.cc | 16 ++++------------ sql/sql_delete.cc | 5 +---- sql/sql_trigger.cc | 3 +++ sql/sql_update.cc | 13 +++---------- sql/table.cc | 13 +++++-------- sql/table.h | 3 +-- 6 files changed, 17 insertions(+), 36 deletions(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d281758fc18..7f84f35c825 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9033,9 +9033,7 @@ fill_record(THD * thd, List &fields, List &values, /* Update virtual fields*/ thd->abort_on_warning= FALSE; if (vcol_table && vcol_table->vfield && - update_virtual_fields(thd, vcol_table, - vcol_table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE)) + update_virtual_fields(thd, vcol_table, VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= save_abort_on_warning; thd->no_errors= save_no_errors; @@ -9099,9 +9097,7 @@ fill_record_n_invoke_before_triggers(THD *thd, List &fields, if (item_field && item_field->field && (table= item_field->field->table) && table->vfield) - result= update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE); + result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE); } } return result; @@ -9186,9 +9182,7 @@ fill_record(THD *thd, Field **ptr, List &values, bool ignore_errors, /* Update virtual fields*/ thd->abort_on_warning= FALSE; if (table->vfield && - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE)) + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= abort_on_warning_saved; DBUG_RETURN(thd->is_error()); @@ -9241,9 +9235,7 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, { TABLE *table= (*ptr)->table; if (table->vfield) - result= update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE); + result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE); } return result; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5b233cde7c7..8aca415a9d0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -328,9 +328,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ! thd->is_error()) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) @@ -1073,4 +1071,3 @@ bool multi_delete::send_eof() } return 0; } - diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index b6915b708fa..4d7338b2e1d 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2246,6 +2246,9 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); if (trg_field->get_settable_routine_parameter()) bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); + if (trigger_table->field[trg_field->field_idx]->vcol_info) + trigger_table->mark_virtual_col(trigger_table-> + field[trg_field->field_idx]); } } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f134e0ba266..060952a589d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -569,9 +569,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || (error= select->skip_record(thd)) > 0) { @@ -695,9 +693,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || select->skip_record(thd) > 0) { @@ -2235,10 +2231,7 @@ int multi_update::do_updates() { int error; if (table->vfield && - update_virtual_fields(thd, table, - (table->triggers ? - VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE))) + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE)) goto err2; if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) diff --git a/sql/table.cc b/sql/table.cc index db18214165e..1330560b6b6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6557,11 +6557,9 @@ bool is_simple_order(ORDER *order) @details The function computes the values of the virtual columns of the table and stores them in the table record buffer. - If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are - computed. Otherwise, only fields from vcol_set are computed: all of them, - if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with - the stored_in_db flag set to false, if vcol_update_mode is equal to - VCOL_UPDATE_FOR_READ. + Only fields from vcol_set are computed: all of them, if vcol_update_mode is + set to VCOL_UPDATE_FOR_WRITE, and, only those with the stored_in_db flag + set to false, if vcol_update_mode is equal to VCOL_UPDATE_FOR_READ. @retval 0 Success @@ -6583,9 +6581,8 @@ int update_virtual_fields(THD *thd, TABLE *table, { vfield= (*vfield_ptr); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); - if ((bitmap_is_set(table->vcol_set, vfield->field_index) && - (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) || - vcol_update_mode == VCOL_UPDATE_ALL) + if (bitmap_is_set(table->vcol_set, vfield->field_index) && + (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) { /* Compute the actual value of the virtual fields */ error= vfield->vcol_info->expr_item->save_in_field(vfield, 0); diff --git a/sql/table.h b/sql/table.h index 17fdd4aba15..dde01a85d77 100644 --- a/sql/table.h +++ b/sql/table.h @@ -302,8 +302,7 @@ enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; enum enum_vcol_update_mode { VCOL_UPDATE_FOR_READ= 0, - VCOL_UPDATE_FOR_WRITE, - VCOL_UPDATE_ALL + VCOL_UPDATE_FOR_WRITE }; typedef struct st_filesort_info -- cgit v1.2.1 From ebb8c9fb26f86cff8c0d81bd2415f415cef952bb Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 12 Jan 2017 15:16:45 +0400 Subject: MDEV-11030 Assertion `precision > 0' failed in decimal_bin_size Fixing Item::decimal_precision() to return at least one digit. This fixes the problem reported in MDEV. Also, fixing Item_func_signed::fix_length_and_dec() to reserve space for at least one digit (plus one character for an optional sign). This is needed to have CONVERT(expr,SIGNED) and CONVERT(expr,UNSIGNED) create correct string fields when they appear in string context, e.g.: CREATE TABLE t1 AS SELECT CONCAT(CONVERT('',SIGNED)); --- sql/item.cc | 9 ++++++++- sql/item_func.h | 11 +++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 08599f1d486..015f5591c5d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -533,7 +533,14 @@ uint Item::decimal_precision() const unsigned_flag); return MY_MIN(prec, DECIMAL_MAX_PRECISION); } - return MY_MIN(max_char_length(), DECIMAL_MAX_PRECISION); + uint res= max_char_length(); + /* + Return at least one decimal digit, even if Item::max_char_length() + returned 0. This is important to avoid attempts to create fields of types + INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL: + CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a; + */ + return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1; } diff --git a/sql/item_func.h b/sql/item_func.h index 4a55bd68453..56d7c190181 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -626,8 +626,15 @@ public: longlong val_int_from_str(int *error); void fix_length_and_dec() { - fix_char_length(MY_MIN(args[0]->max_char_length(), - MY_INT64_NUM_DECIMAL_DIGITS)); + uint32 char_length= MY_MIN(args[0]->max_char_length(), + MY_INT64_NUM_DECIMAL_DIGITS); + /* + args[0]->max_char_length() can return 0. + Reserve max_length to fit at least one character for one digit, + plus one character for the sign (if signed). + */ + set_if_bigger(char_length, 1 + (unsigned_flag ? 0 : 1)); + fix_char_length(char_length); } virtual void print(String *str, enum_query_type query_type); uint decimal_precision() const { return args[0]->decimal_precision(); } -- cgit v1.2.1 From 20ca1bcf4bd81ed43683676276b5f27dc8da8e91 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2017 13:54:21 +0100 Subject: MDEV-11527 Virtual columns do not get along well with NO_ZERO_DATE don't check defaults for vcols --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2cec480d23b..43e146f1f1d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3826,7 +3826,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check); if (thd->variables.sql_mode & MODE_NO_ZERO_DATE && - !sql_field->def && + !sql_field->def && !sql_field->vcol_info && sql_field->sql_type == MYSQL_TYPE_TIMESTAMP && (sql_field->flags & NOT_NULL_FLAG) && (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD)) -- cgit v1.2.1 From 67e2028161d1f653a852f1a4679ff5e523296218 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 14:56:01 +0100 Subject: MDEV-9690 concurrent queries with virtual columns crash in temporal code Item_func_le included Arg_comparator. Arg_comparator remembered the current_thd during fix_fields and used that value during execution to allocate Item_cache in get_datetime_value(). But for vcols fix_fields and val_int can happen in different threads. Same bug for Item_func_in using in_datetime or cmp_item_datetime, both also remembered current_thd at fix_fields() to use it later for get_datetime_value(). As a fix, these objects no longer remember the current_thd, and get_datetime_value() uses current_thd at run time. This should not increase the number of current_thd calls much, as Item_cache is created only once anyway. --- sql/item_cmpfunc.cc | 22 ++++++++++++---------- sql/item_cmpfunc.h | 12 ++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3bd0b5b3fa2..46566206094 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -777,7 +777,7 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type) { - thd= current_thd; + THD *thd= current_thd; owner= owner_arg; set_null= set_null && owner_arg; a= a1; @@ -846,7 +846,6 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value, void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1) { - thd= current_thd; owner= owner_arg; a= a1; b= b1; @@ -919,6 +918,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (cache_arg && item->const_item() && !(item->type() == Item::CACHE_ITEM && item->cmp_type() == TIME_RESULT)) { + if (!thd) + thd= current_thd; + Query_arena backup; Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_temporal *cache= new Item_cache_temporal(f_type); @@ -959,12 +961,12 @@ int Arg_comparator::compare_datetime() owner->null_value= 1; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null); + a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null); if (a_is_null) return -1; /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null); + b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null); if (b_is_null) return -1; @@ -982,10 +984,10 @@ int Arg_comparator::compare_e_datetime() longlong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null); + a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null); /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null); + b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null); return a_is_null || b_is_null ? a_is_null == b_is_null : a_value == b_value; } @@ -3600,7 +3602,7 @@ void in_datetime::set(uint pos,Item *item) bool is_null; struct packed_longlong *buff= &((packed_longlong*) base)[pos]; - buff->val= get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null); + buff->val= get_datetime_value(0, &tmp_item, 0, warn_item, &is_null); buff->unsigned_flag= 1L; } @@ -3608,7 +3610,7 @@ uchar *in_datetime::get_value(Item *item) { bool is_null; Item **tmp_item= lval_cache ? &lval_cache : &item; - tmp.val= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null); + tmp.val= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null); if (item->null_value) return 0; tmp.unsigned_flag= 1L; @@ -3852,7 +3854,7 @@ void cmp_item_datetime::store_value(Item *item) { bool is_null; Item **tmp_item= lval_cache ? &lval_cache : &item; - value= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null); + value= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null); } @@ -3861,7 +3863,7 @@ int cmp_item_datetime::cmp(Item *arg) bool is_null; Item **tmp_item= &arg; return value != - get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null); + get_datetime_value(0, &tmp_item, 0, warn_item, &is_null); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 0194f9cd0e0..a8befa47b95 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -44,7 +44,6 @@ class Arg_comparator: public Sql_alloc Arg_comparator *comparators; // used only for compare_row() double precision; /* Fields used in DATE/DATETIME comparison. */ - THD *thd; Item *a_cache, *b_cache; // Cached values of a and b items // when one of arguments is NULL. public: @@ -52,10 +51,10 @@ public: /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): set_null(TRUE), comparators(0), thd(0), + Arg_comparator(): set_null(TRUE), comparators(0), a_cache(0), b_cache(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE), - comparators(0), thd(0), a_cache(0), b_cache(0) {}; + comparators(0), a_cache(0), b_cache(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); inline int set_compare_func(Item_result_field *owner_arg) @@ -944,15 +943,13 @@ public: class in_datetime :public in_longlong { public: - THD *thd; /* An item used to issue warnings. */ Item *warn_item; /* Cache for the left item. */ Item *lval_cache; in_datetime(Item *warn_item_arg, uint elements) - :in_longlong(elements), thd(current_thd), warn_item(warn_item_arg), - lval_cache(0) {}; + :in_longlong(elements), warn_item(warn_item_arg), lval_cache(0) {}; void set(uint pos,Item *item); uchar *get_value(Item *item); Item* create_item() @@ -1112,14 +1109,13 @@ class cmp_item_datetime :public cmp_item { longlong value; public: - THD *thd; /* Item used for issuing warnings. */ Item *warn_item; /* Cache for the left item. */ Item *lval_cache; cmp_item_datetime(Item *warn_item_arg) - :thd(current_thd), warn_item(warn_item_arg), lval_cache(0) {} + : warn_item(warn_item_arg), lval_cache(0) {} void store_value(Item *item); int cmp(Item *arg); int compare(cmp_item *ci); -- cgit v1.2.1 From 798fcb541698cbf51f1ee33f44b023c11dc2b784 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 20:55:33 +0100 Subject: bugfix: cmp_item_row::alloc_comparators() allocated on the wrong arena it used current_thd->alloc() and allocated on the thd's execution arena, not on table->expr_arena. Remove THD::arena_for_cached_items that is temporarily set in update_virtual_fields(), and replaces THD arena in get_datetime_value(). Instead set THD arena to table->expr_arena for the whole duration of update_virtual_fields() --- sql/item_cmpfunc.cc | 5 ----- sql/sql_class.cc | 1 - sql/sql_class.h | 19 ------------------- sql/table.cc | 6 ++++-- 4 files changed, 4 insertions(+), 27 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 46566206094..ebe088e5092 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -921,12 +921,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (!thd) thd= current_thd; - Query_arena backup; - Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_temporal *cache= new Item_cache_temporal(f_type); - if (save_arena) - thd->set_query_arena(save_arena); - cache->store_packed(value, item); *cache_arg= cache; *item_arg= cache_arg; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 62339b2690a..93af4d3bb4d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -957,7 +957,6 @@ THD::THD() m_internal_handler= NULL; m_binlog_invoker= FALSE; - arena_for_cached_items= 0; memset(&invoker_user, 0, sizeof(invoker_user)); memset(&invoker_host, 0, sizeof(invoker_host)); prepare_derived_at_open= FALSE; diff --git a/sql/sql_class.h b/sql/sql_class.h index 27bc40e3761..5dd7cd18a5d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3102,26 +3102,7 @@ public: } } -private: - /* - This reference points to the table arena when the expression - for a virtual column is being evaluated - */ - Query_arena *arena_for_cached_items; - public: - void reset_arena_for_cached_items(Query_arena *new_arena) - { - arena_for_cached_items= new_arena; - } - Query_arena *switch_to_arena_for_cached_items(Query_arena *backup) - { - if (!arena_for_cached_items) - return 0; - set_n_backup_active_arena(arena_for_cached_items, backup); - return backup; - } - void clear_wakeup_ready() { wakeup_ready= false; } /* Sleep waiting for others to wake us up with signal_wakeup_ready(). diff --git a/sql/table.cc b/sql/table.cc index 1330560b6b6..9d52d5f87a2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6575,7 +6575,9 @@ int update_virtual_fields(THD *thd, TABLE *table, int error __attribute__ ((unused))= 0; DBUG_ASSERT(table && table->vfield); - thd->reset_arena_for_cached_items(table->expr_arena); + Query_arena backup_arena; + thd->set_n_backup_active_arena(table->expr_arena, &backup_arena); + /* Iterate over virtual fields in the table */ for (vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++) { @@ -6593,7 +6595,7 @@ int update_virtual_fields(THD *thd, TABLE *table, DBUG_PRINT("info", ("field '%s' - skipped", vfield->field_name)); } } - thd->reset_arena_for_cached_items(0); + thd->restore_active_arena(table->expr_arena, &backup_arena); DBUG_RETURN(0); } -- cgit v1.2.1 From b948b5f7c64c6430d98dc31b7e9f71d990b40ec1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 21:23:00 +0100 Subject: bugfix: Item_func_min_max stored thd internally It was used for get_datetime_value() and for thd->is_error(). But in fact, get_datetime_value() never used thd argument, because the cache ptr argument was NULL. And thd->is_error() check was not needed at that place at all. --- sql/item_func.cc | 7 ++----- sql/item_func.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 89d3cd9e32a..cfccd66ea8a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2856,7 +2856,6 @@ void Item_func_min_max::fix_length_and_dec() decimals=0; max_length=0; maybe_null=0; - thd= current_thd; cmp_type=args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) @@ -2929,13 +2928,11 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { Item **arg= args + i; bool is_null; - longlong res= get_datetime_value(thd, &arg, 0, compare_as_dates, &is_null); + longlong res= get_datetime_value(0, &arg, 0, compare_as_dates, &is_null); /* Check if we need to stop (because of error or KILL) and stop the loop */ - if (thd->is_error() || args[i]->null_value) - { + if (args[i]->null_value) return (null_value= 1); - } if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) min_max= res; diff --git a/sql/item_func.h b/sql/item_func.h index 0da38e22c7f..d60801745fe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1068,7 +1068,6 @@ class Item_func_min_max :public Item_func int cmp_sign; /* An item used for issuing warnings while string to DATETIME conversion. */ Item *compare_as_dates; - THD *thd; protected: enum_field_types cached_field_type; public: -- cgit v1.2.1 From 1282eb694c9fb18cac6bace643b4ce275a6a5689 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 11 Dec 2016 17:16:15 +0100 Subject: cleanup: make malloc_size_cb_func always defined --- sql/mysqld.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index adb1b273b80..96baaf25287 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3989,7 +3989,7 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) { THD *thd= current_thd; - if (likely(is_thread_specific)) /* If thread specific memory */ + if (is_thread_specific) /* If thread specific memory */ { /* When thread specfic is set, both mysqld_server_initialized and thd @@ -4006,8 +4006,7 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) else if (likely(thd)) { DBUG_PRINT("info", ("global thd memory_used: %lld size: %lld", - (longlong) thd->status_var.global_memory_used, - size)); + (longlong) thd->status_var.global_memory_used, size)); thd->status_var.global_memory_used+= size; } else -- cgit v1.2.1 From 7e2f9d092dd1fb6b0fa1a8fdd5d1f3af68b56f45 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 12 Dec 2016 01:01:56 +0100 Subject: max_session_mem_used server variable --- sql/mysqld.cc | 9 +++++++++ sql/sql_class.cc | 6 ++++-- sql/sql_class.h | 1 + sql/sys_vars.cc | 7 +++++++ 4 files changed, 21 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 96baaf25287..fcb6697fed6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4001,6 +4001,15 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) (longlong) thd->status_var.local_memory_used, size)); thd->status_var.local_memory_used+= size; + if (thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used && + !thd->killed) + { + char buf[1024]; + thd->killed= KILL_QUERY; + my_snprintf(buf, sizeof(buf), "--max-thread-mem-used=%llu", + thd->variables.max_mem_used); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), buf); + } DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0); } else if (likely(thd)) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4143d2cc419..c9592df1b65 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -906,8 +906,8 @@ THD::THD(bool is_wsrep_applier) #endif { ulong tmp; + bzero(&variables, sizeof(variables)); - mdl_context.init(this); /* We set THR_THD to temporally point to this THD to register all the variables that allocates memory for this THD @@ -916,8 +916,11 @@ THD::THD(bool is_wsrep_applier) set_current_thd(this); status_var.local_memory_used= sizeof(THD); status_var.global_memory_used= 0; + variables.max_mem_used= global_system_variables.max_mem_used; main_da.init(); + mdl_context.init(this); + /* Pass nominal parameters to init_alloc_root only to ensure that the destructor works OK in case of an error. The main_mem_root @@ -964,7 +967,6 @@ THD::THD(bool is_wsrep_applier) connection_name.str= 0; connection_name.length= 0; - bzero(&variables, sizeof(variables)); file_id = 0; query_id= 0; query_name_consts= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index da885c3dbac..3058d81496c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -540,6 +540,7 @@ typedef struct system_variables ulonglong sortbuff_size; ulonglong group_concat_max_len; ulonglong default_regex_flags; + ulonglong max_mem_used; /** Place holders to store Multi-source variables in sys_var.cc during diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bb349e78724..641f8306f98 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -5401,3 +5401,10 @@ static Sys_var_ulong Sys_log_tc_size( DEFAULT(my_getpagesize() * 6), BLOCK_SIZE(my_getpagesize())); #endif + +static Sys_var_ulonglong Sys_max_thread_mem( + "max_session_mem_used", "Amount of memory a single user session " + "is allowed to allocate. This limits the value of the " + "session variable MEM_USED", SESSION_VAR(max_mem_used), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(8192, ULONGLONG_MAX), + DEFAULT(LONGLONG_MAX), BLOCK_SIZE(1)); -- cgit v1.2.1 From 5dfab33c4ec54082daf034da99c4a796410fe4f3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2017 00:33:21 +0100 Subject: MDEV-11551 Server crashes in Field::is_real_null sometimes table->s->stored_fields is less than table->s->null_fields --- sql/sql_trigger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 7a61279fc9c..7bfc1e950b5 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1082,7 +1082,7 @@ bool Table_triggers_list::prepare_record_accessors(TABLE *table) && (table->s->stored_fields != table->s->null_fields)) { - int null_bytes= (table->s->stored_fields - table->s->null_fields + 7)/8; + int null_bytes= (table->s->fields - table->s->null_fields + 7)/8; if (!(extra_null_bitmap= (uchar*)alloc_root(&table->mem_root, null_bytes))) return 1; if (!(record0_field= (Field **)alloc_root(&table->mem_root, -- cgit v1.2.1 From eddbae422bd3430f684d5cd287ca522467040c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 16 Jan 2017 12:49:22 +0200 Subject: MDEV-11712: ArmHF EXPLAIN JSON garbage longlong values printed Make sure printing with snprintf uses the correct typed parameters. --- sql/field.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 58def13f5f3..ea56489543d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10600,7 +10600,7 @@ Create_field::Create_field(THD *thd, Field *old_field, Field *orig_field) if (length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%llu)", length); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), -- cgit v1.2.1 From 6560e9c3a86383cb3af1333987abd39aae6af8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 16 Jan 2017 12:50:12 +0200 Subject: MDEV-11711: ArmHF EXPLAIN JSON garbage longlong values printed Make sure printing with snprintf uses the correct typed parameters. --- sql/my_json_writer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc index d36fdd1192a..135ce353552 100644 --- a/sql/my_json_writer.cc +++ b/sql/my_json_writer.cc @@ -125,7 +125,7 @@ void Json_writer::start_element() void Json_writer::add_ll(longlong val) { char buf[64]; - my_snprintf(buf, sizeof(buf), "%ld", val); + my_snprintf(buf, sizeof(buf), "%lld", val); add_unquoted_str(buf); } @@ -135,16 +135,16 @@ void Json_writer::add_size(longlong val) { char buf[64]; if (val < 1024) - my_snprintf(buf, sizeof(buf), "%ld", val); + my_snprintf(buf, sizeof(buf), "%lld", val); else if (val < 1024*1024*16) { /* Values less than 16MB are specified in KB for precision */ - size_t len= my_snprintf(buf, sizeof(buf), "%ld", val/1024); + size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/1024); strcpy(buf + len, "Kb"); } else { - size_t len= my_snprintf(buf, sizeof(buf), "%ld", val/(1024*1024)); + size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/(1024*1024)); strcpy(buf + len, "Mb"); } add_str(buf); -- cgit v1.2.1 From 1e192e901ccf34454967cc3f62a71432c50f2c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 17 Jan 2017 02:35:16 +0200 Subject: Post merge review fixes * Remove duplicate lines from tests * Use thd instead of current_thd * Remove extra wsrep_binlog_format_names * Correctly merge union patch from 5.5 wrt duplicate rows. * Correctly merge SELinux changes into 10.1 --- sql/item.cc | 2 +- sql/mysqld.cc | 4 ---- sql/sql_select.cc | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 2e7bc8e20c0..643e5c85df5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1133,7 +1133,7 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) if (conv == example) return this; Item_cache *cache; - if (!conv || conv->fix_fields(current_thd, (Item **) NULL) || + if (!conv || conv->fix_fields(thd, (Item **) NULL) || !(cache= new (thd->mem_root) Item_cache_str(thd, conv))) return NULL; // Safe conversion is not possible, or OEM cache->setup(thd, conv); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b0bb0e5cd22..5ff56daf7c2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -480,10 +480,6 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; -#ifdef WITH_WSREP -const char *wsrep_binlog_format_names[]= - {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; -#endif /* WITH_WSREP */ volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_extra_port; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f299e863bf2..1bd101bbe6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17972,7 +17972,7 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) error= NESTED_LOOP_OK; /* select_limit used */ } - join->thd->limit_found_rows= join->send_records; + join->thd->limit_found_rows= join->send_records - join->duplicate_rows; if (error == NESTED_LOOP_NO_MORE_ROWS || join->thd->killed == ABORT_QUERY) error= NESTED_LOOP_OK; -- cgit v1.2.1 From 3e589d4b8edf3d435a44cf71419a8355fe284f8e Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 17 Jan 2017 12:24:55 +0100 Subject: MDEV-11811: dual master with parallel replication memory leak in write master Gtid_list_log_event::do_apply_event() did not free_root(thd->mem_root). It can allocate on this in record_gtid(), and in some scenarios there is nothing else that does free_root(), leading to temporary memory leak until stop of SQL thread. One scenario is in circular replication with only one master active. The active master receives only its own events on the slave, all of which are ignored. But whenever the SQL thread catches up with the IO thread, a Gtid_list_log_event is applied, leading to the leak. --- sql/log_event.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index d311297f8a8..14f6bb20b47 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6915,6 +6915,7 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi) rli->abort_slave= true; rli->stop_for_until= true; } + free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC)); return ret; } -- cgit v1.2.1 From 30a9ac4250e1b19754dd0ae43705108cc9de2ab0 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 17 Jan 2017 15:32:41 +0400 Subject: MDEV-10956 Strict Password Validation Breaks Replication. strict_password_validation variable now has no effect in the slave thread. --- sql/sql_acl.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2accb3abc91..912930d60f3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -895,7 +895,7 @@ static my_bool do_validate(THD *, plugin_ref plugin, void *arg) } -static bool validate_password(LEX_USER *user) +static bool validate_password(LEX_USER *user, THD *thd) { if (user->pwtext.length || !user->pwhash.length) { @@ -911,7 +911,8 @@ static bool validate_password(LEX_USER *user) } else { - if (strict_password_validation && has_validation_plugins()) + if (!thd->slave_thread && + strict_password_validation && has_validation_plugins()) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation"); return true; @@ -2750,7 +2751,7 @@ bool check_change_password(THD *thd, LEX_USER *user) LEX_USER *real_user= get_current_user(thd, user); if (fix_and_copy_user(real_user, user, thd) || - validate_password(real_user)) + validate_password(real_user, thd)) return true; *user= *real_user; @@ -3465,7 +3466,7 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo, } if (!old_row_exists || combo.pwtext.length || combo.pwhash.length) - if (!handle_as_role && validate_password(&combo)) + if (!handle_as_role && validate_password(&combo, thd)) goto end; /* Update table columns with new privileges */ -- cgit v1.2.1 From ef8003eb9a23007ac5d606530dcdcc3ea2f0c039 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2017 18:23:02 +0100 Subject: MDEV-11698 Old Bug possibly not fixed; BEFORE INSERT Trigger on NOT NULL check_that_all_fields_are_given_values() relied on write_set, but was run too early, before triggers updated write_set. also, when triggers are present, fields might get values conditionally, so we need to check that all fields are given values for every row. --- sql/sql_insert.cc | 118 ++++++++++++++++++++++++++++------------------------- sql/sql_insert.h | 3 +- sql/sql_prepare.cc | 2 +- 3 files changed, 64 insertions(+), 59 deletions(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ac7fd93f0c0..f4e0a6a00eb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -304,6 +304,32 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(0); } +static bool has_no_default_value(THD *thd, Field *field, TABLE_LIST *table_list) +{ + if ((field->flags & NO_DEFAULT_VALUE_FLAG) && field->real_type() != MYSQL_TYPE_ENUM) + { + bool view= false; + if (table_list) + { + table_list= table_list->top_table(); + view= table_list->view != NULL; + } + if (view) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER_THD(thd, ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, table_list->view_name.str); + } + else + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_FIELD, + ER_THD(thd, ER_NO_DEFAULT_FOR_FIELD), field->field_name); + } + return true; + } + return false; +} + /** Check if update fields are correct. @@ -733,13 +759,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (mysql_prepare_insert(thd, table_list, table, fields, values, update_fields, update_values, duplic, &unused_conds, - FALSE, - (fields.elements || !value_count || - table_list->view != 0), - !ignore && thd->is_strict_mode())) + FALSE)) goto abort; - /* mysql_prepare_insert set table_list->table if it was not set */ + /* mysql_prepare_insert sets table_list->table if it was not set */ table= table_list->table; context= &thd->lex->select_lex.context; @@ -866,6 +889,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->prepare_triggers_for_insert_stmt_or_event(); table->mark_columns_needed_for_insert(); + if (fields.elements || !value_count || table_list->view != 0) + { + if (check_that_all_fields_are_given_values(thd, table, table_list)) + { + error= 1; + goto values_loop_end; + } + } if (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)) @@ -965,6 +996,23 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error= 1; break; } + /* + with triggers a field can get a value *conditionally*, so we have to repeat + has_no_default_value() check for every row + */ + if (table->triggers && + table->triggers->has_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE)) + { + for (Field **f=table->field ; *f ; f++) + { + if (!((*f)->flags & HAS_EXPLICIT_VALUE) && has_no_default_value(thd, *f, table_list)) + { + error= 1; + goto values_loop_end; + } + (*f)->flags &= ~HAS_EXPLICIT_VALUE; + } + } if ((res= table_list->view_check_option(thd, (values_list.elements == 1 ? @@ -1374,10 +1422,6 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement - check_fields TRUE if need to check that all INSERT fields are - given values. - abort_on_warning whether to report if some INSERT field is not - assigned as an error (TRUE) or as a warning (FALSE). TODO (in far future) In cases of: @@ -1397,9 +1441,8 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, - enum_duplicates duplic, - COND **where, bool select_insert, - bool check_fields, bool abort_on_warning) + enum_duplicates duplic, COND **where, + bool select_insert) { SELECT_LEX *select_lex= &thd->lex->select_lex; Name_resolution_context *context= &select_lex->context; @@ -1470,17 +1513,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, check_insert_fields(thd, context->table_list, fields, *values, !insert_into_view, 0, &map)); - if (!res && check_fields) - { - bool saved_abort_on_warning= thd->abort_on_warning; - thd->abort_on_warning= abort_on_warning; - res= check_that_all_fields_are_given_values(thd, - table ? table : - context->table_list->table, - context->table_list); - thd->abort_on_warning= saved_abort_on_warning; - } - if (!res) res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); @@ -1923,8 +1955,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, - TABLE_LIST *table_list) + +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list) { int err= 0; MY_BITMAP *write_set= entry->write_set; @@ -1932,32 +1964,8 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, for (Field **field=entry->field ; *field ; field++) { if (!bitmap_is_set(write_set, (*field)->field_index) && - ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && - ((*field)->real_type() != MYSQL_TYPE_ENUM)) - { - bool view= FALSE; - if (table_list) - { - table_list= table_list->top_table(); - view= MY_TEST(table_list->view); - } - if (view) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_VIEW_FIELD, - ER_THD(thd, ER_NO_DEFAULT_FOR_VIEW_FIELD), - table_list->view_db.str, - table_list->view_name.str); - } - else - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER_THD(thd, ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); - } - err= 1; - } + has_no_default_value(thd, *field, table_list)) + err=1; } return thd->abort_on_warning ? err : 0; } @@ -3390,9 +3398,8 @@ bool mysql_insert_select_prepare(THD *thd) if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, - lex->update_list, lex->value_list, - lex->duplicates, - &select_lex->where, TRUE, FALSE, FALSE)) + lex->update_list, lex->value_list, lex->duplicates, + &select_lex->where, TRUE)) DBUG_RETURN(TRUE); DBUG_ASSERT(select_lex->leaf_tables.elements != 0); @@ -3479,8 +3486,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) { bool saved_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); - res= check_that_all_fields_are_given_values(thd, table_list->table, - table_list); + res= check_that_all_fields_are_given_values(thd, table_list->table, table_list); thd->abort_on_warning= saved_abort_on_warning; } diff --git a/sql/sql_insert.h b/sql/sql_insert.h index cbfc1ea9dcd..aea0dac6b0d 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -27,8 +27,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, enum_duplicates duplic, - COND **where, bool select_insert, - bool check_fields, bool abort_on_warning); + COND **where, bool select_insert); bool mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d381825851d..d3a5d0aeef6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1299,7 +1299,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, if (mysql_prepare_insert(thd, table_list, table_list->table, fields, values, update_fields, update_values, - duplic, &unused_conds, FALSE, FALSE, FALSE)) + duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; -- cgit v1.2.1 From f797ea7124e906fd3abf311d66101a21dce2d27d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2017 18:47:53 +0100 Subject: MDEV-11601 Out-of-bounds string access in create_schema_table() in Item_partition_func_safe_string(THD *thd, const char *name_arg, uint length, CHARSET_INFO *cs= NULL), the 'name_arg' is the value of the string constant and 'length' is the length of this constant, so length == strlen(name_arg). --- sql/item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 07b8a865652..b09e9297826 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3206,7 +3206,7 @@ class Item_blob :public Item_partition_func_safe_string { public: Item_blob(THD *thd, const char *name_arg, uint length): - Item_partition_func_safe_string(thd, name_arg, length, &my_charset_bin) + Item_partition_func_safe_string(thd, name_arg, strlen(name_arg), &my_charset_bin) { max_length= length; } enum Type type() const { return TYPE_HOLDER; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } -- cgit v1.2.1