From a80bd0b5d7267d420aa876ed7d7edaed2c7e898d Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 23 Jul 2009 19:01:24 +0200 Subject: Bug #46212 safe_process: FATAL ERROR, Unknown option: --nocore Also fixed mysqld.cc to avoid popup-boxes --- sql/mysqld.cc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 080f78993a1..fa8b4a971d7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2103,15 +2103,14 @@ static void init_signals(void) win_install_sigabrt_handler(); if(opt_console) SetConsoleCtrlHandler(console_event_handler,TRUE); - else - { + /* Avoid MessageBox()es*/ - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); /* Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (), @@ -2120,8 +2119,8 @@ static void init_signals(void) exception filter is not guaranteed to work in all situation (like heap corruption or stack overflow) */ - SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - } + SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS + | SEM_NOOPENFILEERRORBOX); SetUnhandledExceptionFilter(my_unhandler_exception_filter); } -- cgit v1.2.1 From f42fab1b76e8435b5de753a35e047b369e07b60a Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 7 Aug 2009 15:08:32 +0200 Subject: Bug#32430: 'show innodb status' causes errors Invalid (old?) table or database name in logs Post push patch. Bug was that a non partitioned table file was not converted to system_charset, (due to table_name_len was not set). Also missing DBUG_RETURN. And Innodb adds quotes after calling the function, so I added one more mode where explain_filename does not add quotes. But it still appends the [sub]partition name as a comment. Also caught a minor quoting bug, the character '`' was not quoted in the identifier. (so 'a`b' was quoted as `a`b` and not `a``b`, this is mulitbyte characters aware.) sql/mysql_priv.h: Bug#32430: 'show innodb status' causes errors Invalid (old?) table or database name in logs Added an unquoted mode sql/share/errmsg.txt: Bug#32430: 'show innodb status' causes errors Invalid (old?) table or database name in logs Removed the quoting of identifier, only leaving the translated word. sql/sql_table.cc: Bug#32430: 'show innodb status' causes errors Invalid (old?) table or database name in logs Fixed quoting of '`' Added DBUG_RETURN. Corrected table_name_len. Added unquoted mode. --- sql/mysql_priv.h | 3 ++- sql/share/errmsg.txt | 16 +++++------ sql/sql_table.cc | 76 +++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 24 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 03c366a45bf..609254448e3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2261,7 +2261,8 @@ enum enum_explain_filename_mode { EXPLAIN_ALL_VERBOSE= 0, EXPLAIN_PARTITIONS_VERBOSE, - EXPLAIN_PARTITIONS_AS_COMMENT + EXPLAIN_PARTITIONS_AS_COMMENT, + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING }; uint explain_filename(const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5531ee71620..3aba434b284 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6184,17 +6184,17 @@ ER_FUNC_INEXISTENT_NAME_COLLISION 42000 # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. ER_DATABASE_NAME - eng "Database `%s`" - swe "Databas `%s`" + eng "Database" + swe "Databas" ER_TABLE_NAME - eng "Table `%s`" - swe "Tabell `%s`" + eng "Table" + swe "Tabell" ER_PARTITION_NAME - eng "Partition `%s`" - swe "Partition `%s`" + eng "Partition" + swe "Partition" ER_SUBPARTITION_NAME - eng "Subpartition `%s`" - swe "Subpartition `%s`" + eng "Subpartition" + swe "Subpartition" ER_TEMPORARY_NAME eng "Temporary" swe "Temporär" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0066c66eb59..7e4318b7d16 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -72,7 +72,7 @@ static void wait_for_kill_signal(THD *thd) @brief Helper function for explain_filename */ static char* add_identifier(char *to_p, const char * end_p, - const char* name, uint name_len, int errcode) + const char* name, uint name_len, bool add_quotes) { uint res; uint errors; @@ -92,18 +92,44 @@ static char* add_identifier(char *to_p, const char * end_p, res= strconvert(&my_charset_filename, conv_name, system_charset_info, conv_string, FN_REFLEN, &errors); if (!res || errors) + { + DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors)); conv_name= name; + } else { DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string)); conv_name= conv_string; } - if (errcode) - to_p+= my_snprintf(to_p, end_p - to_p, ER(errcode), conv_name); + if (add_quotes && (end_p - to_p > 2)) + { + *(to_p++)= '`'; + while (*conv_name && (end_p - to_p - 1) > 0) + { + uint length= my_mbcharlen(system_charset_info, *conv_name); + if (!length) + length= 1; + if (length == 1 && *conv_name == '`') + { + if ((end_p - to_p) < 3) + break; + *(to_p++)= '`'; + *(to_p++)= *(conv_name++); + } + else if (length < (end_p - to_p)) + { + to_p= strnmov(to_p, conv_name, length); + conv_name+= length; + } + else + break; /* string already filled */ + } + to_p= strnmov(to_p, "`", end_p - to_p); + } else - to_p+= my_snprintf(to_p, end_p - to_p, "`%s`", conv_name); - return to_p; + to_p= strnmov(to_p, conv_name, end_p - to_p); + DBUG_RETURN(to_p); } @@ -135,6 +161,8 @@ static char* add_identifier(char *to_p, const char * end_p, [,[ Temporary| Renamed] Partition `p` [, Subpartition `sp`]] *| (| is really a /, and it is all in one line) + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING -> + same as above but no quotes are added. @retval Length of returned string */ @@ -245,28 +273,39 @@ uint explain_filename(const char *from, part_name_len-= 5; } } + else + table_name_len= strlen(table_name); if (db_name) { if (explain_mode == EXPLAIN_ALL_VERBOSE) { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, - ER_DATABASE_NAME); + to_p= strnmov(to_p, ER(ER_DATABASE_NAME), end_p - to_p); + *(to_p++)= ' '; + to_p= add_identifier(to_p, end_p, db_name, db_name_len, 1); to_p= strnmov(to_p, ", ", end_p - to_p); } else { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, 0); + to_p= add_identifier(to_p, end_p, db_name, db_name_len, + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); to_p= strnmov(to_p, ".", end_p - to_p); } } if (explain_mode == EXPLAIN_ALL_VERBOSE) - to_p= add_identifier(to_p, end_p, table_name, table_name_len, - ER_TABLE_NAME); + { + to_p= strnmov(to_p, ER(ER_TABLE_NAME), end_p - to_p); + *(to_p++)= ' '; + to_p= add_identifier(to_p, end_p, table_name, table_name_len, 1); + } else - to_p= add_identifier(to_p, end_p, table_name, table_name_len, 0); + to_p= add_identifier(to_p, end_p, table_name, table_name_len, + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); if (part_name) { - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || + explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) to_p= strnmov(to_p, " /* ", end_p - to_p); else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE) to_p= strnmov(to_p, " ", end_p - to_p); @@ -280,15 +319,22 @@ uint explain_filename(const char *from, to_p= strnmov(to_p, ER(ER_RENAMED_NAME), end_p - to_p); to_p= strnmov(to_p, " ", end_p - to_p); } + to_p= strnmov(to_p, ER(ER_PARTITION_NAME), end_p - to_p); + *(to_p++)= ' '; to_p= add_identifier(to_p, end_p, part_name, part_name_len, - ER_PARTITION_NAME); + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); if (subpart_name) { to_p= strnmov(to_p, ", ", end_p - to_p); + to_p= strnmov(to_p, ER(ER_SUBPARTITION_NAME), end_p - to_p); + *(to_p++)= ' '; to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len, - ER_SUBPARTITION_NAME); + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); } - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || + explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) to_p= strnmov(to_p, " */", end_p - to_p); } DBUG_PRINT("exit", ("to '%s'", to)); -- cgit v1.2.1 From 152943f39f487795f3d1d6910d1ee9f736feae44 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 19 Aug 2009 17:53:43 +0300 Subject: Bug #46807: subselect test fails on PB-2 with a crash The check for stack overflow was independent of the size of the structure stored in the heap. Fixed by adding sizeof(PARAM) to the requested free heap size. --- sql/opt_range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 32f9b0df4c0..d007009d62c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2063,7 +2063,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, KEY *key_info; PARAM param; - if (check_stack_overrun(thd, 2*STACK_MIN_SIZE, buff)) + if (check_stack_overrun(thd, 2*STACK_MIN_SIZE + sizeof(PARAM), buff)) DBUG_RETURN(0); // Fatal error flag is set /* set up parameter that is passed to all functions */ -- cgit v1.2.1 From 7492d622e44d7d3fd424bd24fd53131fe06d1c22 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 24 Aug 2009 15:28:03 +0300 Subject: Bug #37044: Read overflow in opt_range.cc found during "make test" The code was using a special global buffer for the value of IS NULL ranges. This was not always long enough to be copied by a regular memcpy. As a result read buffer overflows may occur. Fixed by setting the null byte to 1 and setting the rest of the field disk image to NULL with a bzero (instead of relying on the buffer and memcpy()). --- sql/opt_range.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d007009d62c..778fc418392 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8308,11 +8308,21 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, return FALSE; uint field_length= cur_part->store_length; - if ((cur_range->maybe_null && + if (cur_range->maybe_null && cur_range->min_value[0] && cur_range->max_value[0]) - || - (memcmp(cur_range->min_value, cur_range->max_value, field_length) == 0)) - { /* cur_range specifies 'IS NULL' or an equality condition. */ + { + /* + cur_range specifies 'IS NULL'. In this case the argument points to a "null value" (is_null_string) + that may not always be long enough for a direct memcpy to a field. + */ + DBUG_ASSERT (field_length > 0); + *key_ptr= 1; + bzero(key_ptr+1,field_length-1); + key_ptr+= field_length; + *key_infix_len+= field_length; + } + else if (memcmp(cur_range->min_value, cur_range->max_value, field_length) == 0) + { /* cur_range specifies an equality condition. */ memcpy(key_ptr, cur_range->min_value, field_length); key_ptr+= field_length; *key_infix_len+= field_length; -- cgit v1.2.1 From 4655118bea2bcb14a06f01046fb06052fd37214c Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 26 Aug 2009 12:51:23 +0200 Subject: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) There were a problem since pruning uses the field for comparison (while evaluate_join_record uses longlong), resulting in pruning failures when comparing DATE to DATETIME. Fix was to always comparing DATE vs DATETIME as DATETIME, by adding ' 00:00:00' to the DATE string. And adding optimization for comparing with 23:59:59, so that DATETIME_col > '2001-02-03 23:59:59' -> TO_DAYS(DATETIME_col) > TO_DAYS('2001-02-03 23:59:59') instead of '>='. mysql-test/r/partition_pruning.result: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Updated result-file mysql-test/t/partition_pruning.test: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Added testcases. sql-common/my_time.c: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) removed duplicate assignment. sql/item.cc: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Changed field_is_equal_to_item into field_cmp_to_item, to better handling DATE vs DATETIME comparision. sql/item.h: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Updated comment sql/item_timefunc.cc: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Added optimization (pruning) of DATETIME where time-part is 23:59:59 sql/opt_range.cc: Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) Using the new stored_field_cmp_to_item for better pruning. --- sql/item.cc | 50 +++++++++++++++++++++++++++++++++++++++----------- sql/item.h | 6 +++--- sql/item_timefunc.cc | 10 +++++++--- sql/opt_range.cc | 15 ++++++++++----- 4 files changed, 59 insertions(+), 22 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 2640b74851b..79ae4b20f30 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6846,14 +6846,21 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Return true if the value stored in the field is equal to the const - item. + Compare the value stored in field, with the original item. - We need to use this on the range optimizer because in some cases - we can't store the value in the field without some precision/character loss. + @param field field which the item is converted and stored in + @param item original item + + @return Return an integer greater than, equal to, or less than 0 if + the value stored in the field is greater than, equal to, + or less than the original item + + @note We only use this on the range optimizer/partition pruning, + because in some cases we can't store the value in the field + without some precision/character loss. */ -bool field_is_equal_to_item(Field *field,Item *item) +int stored_field_cmp_to_item(Field *field, Item *item) { Item_result res_type=item_cmp_type(field->result_type(), @@ -6864,28 +6871,49 @@ bool field_is_equal_to_item(Field *field,Item *item) char field_buff[MAX_FIELD_WIDTH]; String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); + enum_field_types field_type; item_result=item->val_str(&item_tmp); if (item->null_value) - return 1; // This must be true + return 0; field->val_str(&field_tmp); - return !stringcmp(&field_tmp,item_result); + + /* + If comparing DATE with DATETIME, append the time-part to the DATE. + So that the strings are equally formatted. + A DATE converted to string is 10 characters, and a DATETIME converted + to string is 19 characters. + */ + field_type= field->type(); + if (field_type == MYSQL_TYPE_DATE && + item_result->length() == 19) + field_tmp.append(" 00:00:00"); + else if (field_type == MYSQL_TYPE_DATETIME && + item_result->length() == 10) + item_result->append(" 00:00:00"); + + return stringcmp(&field_tmp,item_result); } if (res_type == INT_RESULT) - return 1; // Both where of type int + return 0; // Both are of type int if (res_type == DECIMAL_RESULT) { my_decimal item_buf, *item_val, field_buf, *field_val; item_val= item->val_decimal(&item_buf); if (item->null_value) - return 1; // This must be true + return 0; field_val= field->val_decimal(&field_buf); - return !my_decimal_cmp(item_val, field_val); + return my_decimal_cmp(item_val, field_val); } double result= item->val_real(); if (item->null_value) + return 0; + double field_result= field->val_real(); + if (field_result < result) + return -1; + else if (field_result > result) return 1; - return result == field->val_real(); + return 0; } Item_cache* Item_cache::get_cache(const Item *item) diff --git a/sql/item.h b/sql/item.h index 3dfcd7c2612..8b37bd3c26d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -576,8 +576,8 @@ public: left_endp FALSE <=> The interval is "x < const" or "x <= const" TRUE <=> The interval is "x > const" or "x >= const" - incl_endp IN TRUE <=> the comparison is '<' or '>' - FALSE <=> the comparison is '<=' or '>=' + incl_endp IN FALSE <=> the comparison is '<' or '>' + TRUE <=> the comparison is '<=' or '>=' OUT The same but for the "F(x) $CMP$ F(const)" comparison DESCRIPTION @@ -3117,4 +3117,4 @@ void mark_select_range_as_dependent(THD *thd, extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); -extern bool field_is_equal_to_item(Field *field,Item *item); +extern int stored_field_cmp_to_item(Field *field, Item *item); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d79b0b02998..eebede32f8d 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -991,15 +991,19 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) point to day bound ("strictly less" comparison stays intact): col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15') + col > '2007-09-15 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15') which is different from the general case ("strictly less" changes to "less or equal"): col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15') */ - if (!left_endp && !(ltime.hour || ltime.minute || ltime.second || - ltime.second_part)) - ; /* do nothing */ + if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second || + ltime.second_part)) || + (left_endp && ltime.hour == 23 && ltime.minute == 59 && + ltime.second == 59)) + /* do nothing */ + ; else *incl_endp= TRUE; return res; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e3aef02637f..96631a741da 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5855,7 +5855,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, but we'll need to convert '>' to '>=' and '<' to '<='. This will be done together with other types at the end of this function - (grep for field_is_equal_to_item) + (grep for stored_field_cmp_to_item) */ } else @@ -5930,7 +5930,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (field_is_equal_to_item(field,value)) + if (stored_field_cmp_to_item(field,value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5944,11 +5944,16 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, break; case Item_func::GT_FUNC: /* Don't use open ranges for partial key_segments */ - if (field_is_equal_to_item(field,value) && - !(key_part->flag & HA_PART_KEY_SEG)) + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(field, value) <= 0)) tree->min_flag=NEAR_MIN; - /* fall through */ + tree->max_flag= NO_MAX_RANGE; + break; case Item_func::GE_FUNC: + /* Don't use open ranges for partial key_segments */ + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(field,value) < 0)) + tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; case Item_func::SP_EQUALS_FUNC: -- cgit v1.2.1 From 67214ef4334deccdd1f1d89c49c4edecd9075962 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 26 Aug 2009 12:59:49 +0200 Subject: Bug#20577: Partitions: use of to_days() function leads to selection failures Problem was that the partition containing NULL values was pruned away, since '2001-01-01' < '2001-02-00' but TO_DAYS('2001-02-00') is NULL. Added the NULL partition for RANGE/LIST partitioning on TO_DAYS() function to be scanned too. Also fixed a bug that added ALLOW_INVALID_DATES to sql_mode (SELECT * FROM t WHERE date_col < '1999-99-99' on a RANGE/LIST partitioned table would add it). mysql-test/include/partition_date_range.inc: Bug#20577: Partitions: use of to_days() function leads to selection failures Added include file to decrease test code duplication mysql-test/r/partition_pruning.result: Bug#20577: Partitions: use of to_days() function leads to selection failures Added test results mysql-test/r/partition_range.result: Bug#20577: Partitions: use of to_days() function leads to selection failures Updated test result. This fix adds the partition containing NULL values to the list of partitions to be scanned. mysql-test/t/partition_pruning.test: Bug#20577: Partitions: use of to_days() function leads to selection failures Added test case sql/item.h: Bug#20577: Partitions: use of to_days() function leads to selection failures Added MONOTONIC_*INCREASE_NOT_NULL values to be used by TO_DAYS. sql/item_timefunc.cc: Bug#20577: Partitions: use of to_days() function leads to selection failures Calculate the number of days as return value even for invalid dates. This is so that pruning can be used even for invalid dates. sql/opt_range.cc: Bug#20577: Partitions: use of to_days() function leads to selection failures Fixed a bug that added ALLOW_INVALID_DATES to sql_mode (SELECT * FROM t WHERE date_col < '1999-99-99' on a RANGE/LIST partitioned table would add it). sql/partition_info.h: Bug#20577: Partitions: use of to_days() function leads to selection failures Resetting ret_null_part when a single partition is to be used, this to avoid adding the NULL partition. sql/sql_partition.cc: Bug#20577: Partitions: use of to_days() function leads to selection failures Always include the NULL partition if RANGE or LIST. Use the returned value for the function for pruning, even if it is marked as NULL, so that even '2000-00-00' can be used for pruning, even if TO_DAYS('2000-00-00') is NULL. Changed == to >= in get_next_partition_id_list to avoid crash if part_iter->part_nums is not correctly setup. --- sql/item.h | 9 +++++++- sql/item_timefunc.cc | 21 ++++++++++++++--- sql/opt_range.cc | 4 ++++ sql/partition_info.h | 1 + sql/sql_partition.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 90 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 3dfcd7c2612..30478ddf13d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -397,13 +397,20 @@ public: from INT_RESULT, may be NULL, or are unsigned. It will be possible to address this issue once the related partitioning bugs (BUG#16002, BUG#15447, BUG#13436) are fixed. + + The NOT_NULL enums are used in TO_DAYS, since TO_DAYS('2001-00-00') returns + NULL which puts those rows into the NULL partition, but + '2000-12-31' < '2001-00-00' < '2001-01-01'. So special handling is needed + for this (see Bug#20577). */ typedef enum monotonicity_info { NON_MONOTONIC, /* none of the below holds */ MONOTONIC_INCREASING, /* F() is unary and (x < y) => (F(x) <= F(y)) */ - MONOTONIC_STRICT_INCREASING /* F() is unary and (x < y) => (F(x) < F(y)) */ + MONOTONIC_INCREASING_NOT_NULL, /* But only for valid/real x and y */ + MONOTONIC_STRICT_INCREASING,/* F() is unary and (x < y) => (F(x) < F(y)) */ + MONOTONIC_STRICT_INCREASING_NOT_NULL /* But only for valid/real x and y */ } enum_monotonicity_info; /*************************************************************************/ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d79b0b02998..eefe47232ae 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -960,9 +960,9 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const if (args[0]->type() == Item::FIELD_ITEM) { if (args[0]->field_type() == MYSQL_TYPE_DATE) - return MONOTONIC_STRICT_INCREASING; + return MONOTONIC_STRICT_INCREASING_NOT_NULL; if (args[0]->field_type() == MYSQL_TYPE_DATETIME) - return MONOTONIC_INCREASING; + return MONOTONIC_INCREASING_NOT_NULL; } return NON_MONOTONIC; } @@ -973,12 +973,27 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; longlong res; - if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + int dummy; /* unused */ + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) { /* got NULL, leave the incl_endp intact */ return LONGLONG_MIN; } res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day); + /* Set to NULL if invalid date, but keep the value */ + null_value= check_date(<ime, + (ltime.year || ltime.month || ltime.day), + (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE), + &dummy); + if (null_value) + { + /* + Even if the evaluation return NULL, the calc_daynr is useful for pruning + */ + if (args[0]->field_type() != MYSQL_TYPE_DATE) + *incl_endp= TRUE; + return res; + } if (args[0]->field_type() == MYSQL_TYPE_DATE) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e3aef02637f..e26d91dcd44 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5826,6 +5826,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, { tree= new (alloc) SEL_ARG(field, 0, 0); tree->type= SEL_ARG::IMPOSSIBLE; + field->table->in_use->variables.sql_mode= orig_sql_mode; goto end; } else @@ -5859,7 +5860,10 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, */ } else + { + field->table->in_use->variables.sql_mode= orig_sql_mode; goto end; + } } } diff --git a/sql/partition_info.h b/sql/partition_info.h index 415f955d5d4..8832b6ee409 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -300,6 +300,7 @@ static inline void init_single_partition_iterator(uint32 part_id, { part_iter->part_nums.start= part_iter->part_nums.cur= part_id; part_iter->part_nums.end= part_id+1; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..ad24af12087 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2766,8 +2766,24 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - DBUG_RETURN(0); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the the first index (lowest value). + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return index with lowest value */ + DBUG_RETURN(0); + } } + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; DBUG_ASSERT(part_info->no_list_values); @@ -2916,11 +2932,29 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - uint32 ret_part_id= 0; - if (!left_endpoint && include_endpoint) - ret_part_id= 1; - DBUG_RETURN(ret_part_id); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the first partition + (may be included if not left endpoint) + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return partition with lowest value */ + if (!left_endpoint && include_endpoint) + DBUG_RETURN(1); + DBUG_RETURN(0); + + } } + + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; if (left_endpoint && !include_endpoint) @@ -6733,6 +6767,19 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, } else assert(0); + + if (part_info->part_type == RANGE_PARTITION || + part_info->has_null_value) + { + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic == MONOTONIC_INCREASING_NOT_NULL || + monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* col is NOT NULL, but F(col) can return NULL, add NULL partition */ + part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; + } + } /* Find minimum: Do special handling if the interval has left bound in form @@ -6959,7 +7006,13 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) { if (part_iter->part_nums.cur >= part_iter->part_nums.end) { + if (part_iter->ret_null_part) + { + part_iter->ret_null_part= FALSE; + return 0; /* NULL always in first range partition */ + } part_iter->part_nums.cur= part_iter->part_nums.start; + part_iter->ret_null_part= part_iter->ret_null_part_orig; return NOT_A_PARTITION_ID; } else @@ -6987,7 +7040,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) { - if (part_iter->part_nums.cur == part_iter->part_nums.end) + if (part_iter->part_nums.cur >= part_iter->part_nums.end) { if (part_iter->ret_null_part) { -- cgit v1.2.1 From 6c2b32515e1856b65feedec2ebe47843f416b2ad Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Thu, 27 Aug 2009 00:13:03 +0100 Subject: BUG#28976 Mixing trans and non-trans tables in one transaction results in incorrect binlog Mixing transactional (T) and non-transactional (N) tables on behalf of a transaction may lead to inconsistencies among masters and slaves in STATEMENT mode. The problem stems from the fact that although modifications done to non-transactional tables on behalf of a transaction become immediately visible to other connections they do not immediately get to the binary log and therefore consistency is broken. Although there may be issues in mixing T and M tables in STATEMENT mode, there are safe combinations that clients find useful. In this bug, we fix the following issue. Mixing N and T tables in multi-level (e.g. a statement that fires a trigger) or multi-table table statements (e.g. update t1, t2...) were not handled correctly. In such cases, it was not possible to distinguish when a T table was updated if the sequence of changes was N and T. In a nutshell, just the flag "modified_non_trans_table" was not enough to reflect that both a N and T tables were changed. To circumvent this issue, we check if an engine is registered in the handler's list and changed something which means that a T table was modified. Check WL 2687 for a full-fledged patch that will make the use of either the MIXED or ROW modes completely safe. mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Truncate statement is wrapped in BEGIN/COMMIT. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Truncate statement is wrapped in BEGIN/COMMIT. --- sql/log.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index bb81d0c723e..282312d28e2 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1264,6 +1264,25 @@ int LOGGER::set_handlers(uint error_log_printer, return 0; } +/** + This function checks if a transactional talbe was updated by the + current statement. + + @param thd The client thread that executed the current statement. + @return + @c true if a transactional table was updated, @false otherwise. +*/ +static bool stmt_has_updated_trans_table(THD *thd) +{ + Ha_trx_info *ha_info; + + for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + { + if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) + return (TRUE); + } + return (FALSE); +} /* Save position of binary log transaction cache. @@ -4060,7 +4079,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); IO_CACHE *trans_log= &trx_data->trans_log; my_off_t trans_log_pos= my_b_tell(trans_log); - if (event_info->get_cache_stmt() || trans_log_pos != 0) + if (event_info->get_cache_stmt() || trans_log_pos != 0 || + stmt_has_updated_trans_table(thd)) { DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu", event_info->get_cache_stmt(), -- cgit v1.2.1 From 367c14b854f4afe6cfd41b9f56bf8fbf3c337b65 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 27 Aug 2009 15:22:19 +0500 Subject: Bug#46184 Crash, SELECT ... FROM derived table procedure analyze The crash happens because select_union object is used as result set for queries which have derived tables. select_union use temporary table as data storage and if fields count exceeds 10(count of values for procedure ANALYSE()) then we get a crash on fill_record() function. mysql-test/r/analyse.result: test result mysql-test/r/subselect.result: result fix mysql-test/t/analyse.test: test case mysql-test/t/subselect.test: test fix sql/sql_yacc.yy: The crash happens because select_union object is used as result set for queries which have derived tables. select_union use temporary table as data storage and if fields count exceeds 10(count of values for procedure ANALYSE()) then we get a crash on fill_record() function. --- sql/sql_yacc.yy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b38b6e96890..09a0a4b2f12 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7334,7 +7334,8 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select) + if (&lex->select_lex != lex->current_select || + lex->select_lex.get_table_list()->derived) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; -- cgit v1.2.1 From a22c29d5e49fddf8cf55f3b1bf51e02b03696b7f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 27 Aug 2009 14:40:42 +0300 Subject: Bug #46749: Segfault in add_key_fields() with outer subquery level field references This error requires a combination of factors : 1. An "impossible where" in the outermost SELECT 2. An aggregate in the outermost SELECT 3. A correlated subquery with a WHERE clause that includes an outer field reference as a top level WHERE sargable predicate When JOIN::optimize detects an "impossible WHERE" it will bail out without doing the rest of the work and initializations. It will not call make_join_statistics() as well. And make_join_statistics fills in various structures for each table referenced. When processing the result of the "impossible WHERE" the query must send a single row of data if there are aggregate functions in it. In this case the server marks all the aggregates as having received no rows and calls the relevant Item::val_xxx() method on the SELECT list. However if this SELECT list happens to contain a correlated subquery this subquery is evaluated in a normal evaluation mode. And if this correlated subquery has a reference to a field from the outermost "impossible where" SELECT the add_key_fields will mistakenly consider the outer field reference as a "local" field reference when looking for sargable predicates. But since the SELECT where the outer field reference refers to is not completely initialized due to the "impossible WHERE" in this level we'll get a NULL pointer reference. Fixed by making a better condition for discovering if a field is "local" to the SELECT level being processed. It's not enough to look for OUTER_REF_TABLE_BIT in this case since for outer references to constant tables the Item_field::used_tables() will return 0 regardless of whether the field reference is from the local SELECT or not. --- sql/sql_select.cc | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0a5706ee989..ff179c432a8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3207,6 +3207,28 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, } } + +/** + Check if an expression is a non-outer field. + + Checks if an expression is a field and belongs to the current select. + + @param field Item expression to check + + @return boolean + @retval TRUE the expression is a local field + @retval FALSE it's something else +*/ + +inline static bool +is_local_field (Item *field) +{ + field= field->real_item(); + return field->type() == Item::FIELD_ITEM && + !((Item_field *)field)->depended_from; +} + + static void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, COND *cond, table_map usable_tables, @@ -3282,13 +3304,12 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, { Item **values; // BETWEEN, IN, NE - if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->key_item()) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { values= cond_func->arguments()+1; if (cond_func->functype() == Item_func::NE_FUNC && - cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + is_local_field (cond_func->arguments()[1])) values--; DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC || cond_func->argument_count() != 2); @@ -3304,9 +3325,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, for (uint i= 1 ; i < cond_func->argument_count() ; i++) { Item_field *field_item; - if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM - && - !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[i])) { field_item= (Item_field *) (cond_func->arguments()[i]->real_item()); add_key_equal_fields(key_fields, *and_level, cond_func, @@ -3322,8 +3341,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC || cond_func->functype() == Item_func::EQUAL_FUNC); - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[0])) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[0])->real_item(), @@ -3331,9 +3349,8 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, cond_func->arguments()+1, 1, usable_tables, sargables); } - if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - cond_func->functype() != Item_func::LIKE_FUNC && - !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[1]) && + cond_func->functype() != Item_func::LIKE_FUNC) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[1])->real_item(), @@ -3345,7 +3362,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } case Item_func::OPTIMIZE_NULL: /* column_name IS [NOT] NULL */ - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->arguments()[0]) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { Item *tmp=new Item_null; -- cgit v1.2.1 From 354f5f7bac16a688f8c851cbf866120871713105 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Thu, 27 Aug 2009 13:46:29 +0100 Subject: BUG#46864 Incorrect update of InnoDB table on slave when using trigger with myisam table Slave does not correctly handle "expected errors" leading to inconsistencies between the mater and slave. Specifically, when a statement changes both transactional and non-transactional tables, the transactional changes are automatically rolled back on the master but the slave ignores the error and does not roll them back thus leading to inconsistencies. To fix the problem, we automatically roll back a statement that fails on the slave but note that the transaction is not rolled back unless a "rollback" command is in the relay log file. mysql-test/extra/rpl_tests/rpl_mixing_engines.test: Enabled item 13.e which was disabled because of the bug fixed by the current and removed item 14 which was introduced by mistake. --- sql/log_event.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 375f9cf1859..0cda724b698 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3202,6 +3202,15 @@ Default database: '%s'. Query: '%s'", DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast(rli)); thd->killed= THD::NOT_KILLED; + /* + When an error is expected and matches the actual error the + slave does not report any error and by consequence changes + on transactional tables are not rolled back in the function + close_thread_tables(). For that reason, we explicitly roll + them back here. + */ + if (expected_error && expected_error == actual_error) + ha_autocommit_or_rollback(thd, TRUE); } /* If we expected a non-zero error code and get nothing and, it is a concurrency -- cgit v1.2.1 From ea06bbd2b0cc4e33b3350ef0bff25b0c1d1c2e95 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Thu, 27 Aug 2009 17:28:09 +0100 Subject: BUG#46861 Auto-closing of temporary tables broken by replicate-rewrite-db When a connection is dropped any remaining temporary table is also automatically dropped and the SQL statement of this operation is written to the binary log in order to drop such tables on the slave and keep the slave in sync. Specifically, the current code base creates the following type of statement: DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `db`.`table`; Unfortunately, appending the database to the table name in this manner circumvents the replicate-rewrite-db option (and any options that check the current database). To solve the issue, we started writing the statement to the binary as follows: use `db`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `table`; --- sql/sql_base.cc | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d969c837891..bc9aa50cb82 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -769,19 +769,23 @@ void close_temporary_tables(THD *thd) { /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); - /* Loop forward through all tables within the sublist of - common pseudo_thread_id to create single DROP query */ + String db; + db.append(table->s->db); + /* Loop forward through all tables that belong to a common database + within the sublist of common pseudo_thread_id to create single + DROP query + */ for (s_query.length(stub_len); table && is_user_table(table) && - tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; + tmpkeyval(thd, table) == thd->variables.pseudo_thread_id && + strlen(table->s->db) == db.length() && + strcmp(table->s->db, db.ptr()) == 0; table= next) { /* - We are going to add 4 ` around the db/table names and possible more - due to special characters in the names + We are going to add ` around the table names and possible more + due to special characters */ - append_identifier(thd, &s_query, table->s->db, strlen(table->s->db)); - s_query.q_append('.'); append_identifier(thd, &s_query, table->s->table_name, strlen(table->s->table_name)); s_query.q_append(','); @@ -794,6 +798,7 @@ void close_temporary_tables(THD *thd) Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE); + qinfo.db= db.ptr(); thd->variables.character_set_client= cs_save; /* Imagine the thread had created a temp table, then was doing a SELECT, and -- cgit v1.2.1 From 169f7da04c4ffc43355d5a632a8013bc4caea39b Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 28 Aug 2009 12:06:59 -0300 Subject: Fix for a few assorted compiler warnings. client/mysql.cc: Remove leading whitespace. Remove extra text after #else directive. client/mysqldump.c: Function does not take a parameter. mysys/array.c: buffer is a uchar pointer. sql/item.cc: Assert if it should not happen. storage/myisam/mi_check.c: Cast to expected type. This is probably a bug, but it is casted in a similar way in another part of the code. storage/ndb/include/mgmapi/ndb_logevent.h: Apply fix from cluster team. tests/mysql_client_test.c: Remove extraneous slash. --- sql/item.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 0ebb1d61a28..c1ba6fe77a3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3305,8 +3305,7 @@ Item_copy *Item_copy::create (Item *item) new Item_copy_uint (item) : new Item_copy_int (item); case DECIMAL_RESULT: return new Item_copy_decimal (item); - - case ROW_RESULT: + default: DBUG_ASSERT (0); } /* should not happen */ -- cgit v1.2.1 From 1ba25ae47caace207cda0be2b7994a1a845e6cce Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Fri, 28 Aug 2009 17:51:31 +0200 Subject: Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 This patch fixes a number of GCC warnings about variables used before initialized. A new macro UNINIT_VAR() is introduced for use in the variable declaration, and LINT_INIT() usage will be gradually deprecated. (A workaround is used for g++, pending a patch for a g++ bug.) GCC warnings for unused results (attribute warn_unused_result) for a number of system calls (present at least in later Ubuntus, where the usual void cast trick doesn't work) are also fixed. client/mysqlmanager-pwgen.c: A fix for warn_unused_result, adding fallback to use of srand()/rand() if /dev/random cannot be used. Also actually adds calls to rand() in the second branch so that it actually creates a random password. --- sql/field.cc | 19 ++++++------------- sql/ha_myisammrg.cc | 2 +- sql/item.cc | 7 ++----- sql/item_cmpfunc.cc | 17 +++++------------ sql/item_create.cc | 6 ++++-- sql/item_func.cc | 12 ++++-------- sql/lock.cc | 3 +-- sql/log.cc | 3 ++- sql/opt_range.cc | 8 ++++---- sql/spatial.cc | 13 +++---------- sql/sql_acl.cc | 10 +++------- sql/sql_base.cc | 6 ++---- sql/sql_parse.cc | 4 ++-- sql/sql_prepare.cc | 3 +-- sql/sql_show.cc | 7 ++----- sql/sql_update.cc | 4 +--- sql/sql_view.cc | 3 +-- 17 files changed, 44 insertions(+), 83 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 2322c5d7b9d..b61e5fd2d79 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1736,16 +1736,16 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) Pointers used when digits move from the left of the '.' to the right of the '.' (explained below) */ - const char *int_digits_tail_from; + const char *UNINIT_VAR(int_digits_tail_from); /* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */ - uint int_digits_added_zeros; + uint UNINIT_VAR(int_digits_added_zeros); /* Pointer used when digits move from the right of the '.' to the left of the '.' */ - const char *frac_digits_head_end; + const char *UNINIT_VAR(frac_digits_head_end); /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */ - uint frac_digits_added_zeros; + uint UNINIT_VAR(frac_digits_added_zeros); char *pos,*tmp_left_pos,*tmp_right_pos; /* Pointers that are used as limits (begin and end of the field buffer) */ char *left_wall,*right_wall; @@ -1756,11 +1756,6 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) */ bool is_cuted_fields_incr=0; - LINT_INIT(int_digits_tail_from); - LINT_INIT(int_digits_added_zeros); - LINT_INIT(frac_digits_head_end); - LINT_INIT(frac_digits_added_zeros); - /* There are three steps in this function : - parse the input string @@ -8854,10 +8849,8 @@ Field *make_field(char *ptr, uint32 field_length, const char *field_name, struct st_table *table) { - uchar *bit_ptr; - uchar bit_offset; - LINT_INIT(bit_ptr); - LINT_INIT(bit_offset); + uchar *UNINIT_VAR(bit_ptr); + uchar UNINIT_VAR(bit_offset); if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { bit_ptr= null_pos; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index fef2e21d271..7983ffbc6c8 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -78,7 +78,7 @@ static void split_file_name(const char *file_name, extern "C" void myrg_print_wrong_table(const char *table_name) { - LEX_STRING db, name; + LEX_STRING db= {NULL, 0}, name; char buf[FN_REFLEN]; split_file_name(table_name, &db, &name); memcpy(buf, db.str, db.length); diff --git a/sql/item.cc b/sql/item.cc index eecb48aa16f..03d752a85d9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1635,7 +1635,7 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, bool agg_item_set_converter(DTCollation &coll, const char *fname, Item **args, uint nargs, uint flags, int item_sep) { - Item **arg, *safe_args[2]; + Item **arg, *safe_args[2]= {NULL, NULL}; /* For better error reporting: save the first and the second argument. @@ -1644,8 +1644,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, doesn't display each argument's characteristics. - if nargs is 1, then this error cannot happen. */ - LINT_INIT(safe_args[0]); - LINT_INIT(safe_args[1]); if (nargs >=2 && nargs <= 3) { safe_args[0]= args[0]; @@ -5122,9 +5120,8 @@ bool Item_null::send(Protocol *protocol, String *packet) bool Item::send(Protocol *protocol, String *buffer) { - bool result; + bool UNINIT_VAR(result); // Will be set if null_value == 0 enum_field_types f_type; - LINT_INIT(result); // Will be set if null_value == 0 switch ((f_type=field_type())) { default: diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c940c4ab3c0..8c655cdc369 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -352,8 +352,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item, /* For comparison purposes allow invalid dates like 2000-01-32 */ ulong orig_sql_mode= thd->variables.sql_mode; enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields; - ulonglong orig_field_val; /* original field value if valid */ - LINT_INIT(orig_field_val); + ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */ thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) | MODE_INVALID_DATES; thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -2453,19 +2452,13 @@ Item_func_nullif::is_null() Item *Item_func_case::find_item(String *str) { - String *first_expr_str, *tmp; - my_decimal *first_expr_dec, first_expr_dec_val; - longlong first_expr_int; - double first_expr_real; + String *UNINIT_VAR(first_expr_str), *tmp; + my_decimal *UNINIT_VAR(first_expr_dec), first_expr_dec_val; + longlong UNINIT_VAR(first_expr_int); + double UNINIT_VAR(first_expr_real); char buff[MAX_FIELD_WIDTH]; String buff_str(buff,sizeof(buff),default_charset()); - /* These will be initialized later */ - LINT_INIT(first_expr_str); - LINT_INIT(first_expr_int); - LINT_INIT(first_expr_real); - LINT_INIT(first_expr_dec); - if (first_expr_num != -1) { switch (cmp_type) diff --git a/sql/item_create.cc b/sql/item_create.cc index c897b7aef79..cbd015f300b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -451,10 +451,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, const char *c_len, const char *c_dec, CHARSET_INFO *cs) { - Item *res; + Item *UNINIT_VAR(res); ulong len; uint dec; - LINT_INIT(res); switch (cast_type) { case ITEM_CAST_BINARY: res= new Item_func_binary(a); break; @@ -542,6 +541,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, res= new Item_char_typecast(a, len, cs ? cs : current_thd->variables.collation_connection); break; + + default: + DBUG_ASSERT(0); } return res; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 6193ab285f2..3c1e2126008 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2275,9 +2275,8 @@ void Item_func_min_max::fix_length_and_dec() uint Item_func_min_max::cmp_datetimes(ulonglong *value) { - longlong min_max; + longlong UNINIT_VAR(min_max); uint min_max_idx= 0; - LINT_INIT(min_max); for (uint i=0; i < arg_count ; i++) { @@ -2345,8 +2344,7 @@ String *Item_func_min_max::val_str(String *str) } case STRING_RESULT: { - String *res; - LINT_INIT(res); + String *UNINIT_VAR(res); for (uint i=0; i < arg_count ; i++) { if (i == 0) @@ -2435,8 +2433,7 @@ longlong Item_func_min_max::val_int() my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) { DBUG_ASSERT(fixed == 1); - my_decimal tmp_buf, *tmp, *res; - LINT_INIT(res); + my_decimal tmp_buf, *tmp, *UNINIT_VAR(res); if (compare_as_dates) { @@ -4974,8 +4971,7 @@ void Item_func_match::init_search(bool no_order) bool Item_func_match::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - Item *item; - LINT_INIT(item); // Safe as arg_count is > 1 + Item *UNINIT_VAR(item); // Safe as arg_count is > 1 maybe_null=1; join_key=0; diff --git a/sql/lock.cc b/sql/lock.cc index 3102497576f..97abd76b7c2 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1216,11 +1216,10 @@ void unlock_global_read_lock(THD *thd) bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit) { - const char *old_message; + const char *UNINIT_VAR(old_message); bool result= 0, need_exit_cond; DBUG_ENTER("wait_if_global_read_lock"); - LINT_INIT(old_message); /* Assert that we do not own LOCK_open. If we would own it, other threads could not close their tables. This would make a pretty diff --git a/sql/log.cc b/sql/log.cc index ec8f5fe820b..c042651216c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2635,9 +2635,10 @@ bool flush_error_log() else result= 1; #else + FILE *reopen; my_rename(log_error_file,err_renamed,MYF(0)); if (freopen(log_error_file,"a+",stdout)) - freopen(log_error_file,"a+",stderr); + reopen= freopen(log_error_file,"a+",stderr); else result= 1; #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 778fc418392..fdf6cc03a44 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3514,11 +3514,10 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, { int idx; SEL_ARG **key,**end, **key_to_read= NULL; - ha_rows best_records; + ha_rows UNINIT_VAR(best_records); /* protected by key_to_read */ TRP_RANGE* read_plan= NULL; bool pk_is_clustered= param->table->file->primary_key_is_clustered(); DBUG_ENTER("get_key_scans_params"); - LINT_INIT(best_records); /* protected by key_to_read */ /* Note that there may be trees that have type SEL_TREE::KEY but contain no key reads at all, e.g. tree for expression "key1 is not null" where key1 @@ -5370,8 +5369,7 @@ static bool eq_tree(SEL_ARG* a,SEL_ARG *b) SEL_ARG * SEL_ARG::insert(SEL_ARG *key) { - SEL_ARG *element,**par,*last_element; - LINT_INIT(par); LINT_INIT(last_element); + SEL_ARG *element,**UNINIT_VAR(par),*UNINIT_VAR(last_element); for (element= this; element != &null_element ; ) { @@ -7918,7 +7916,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) goto next_index; } else + { DBUG_ASSERT(FALSE); + } /* Check (SA2). */ if (min_max_arg_item) diff --git a/sql/spatial.cc b/sql/spatial.cc index 80506f16d0f..6e1da589527 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -935,13 +935,10 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const int Gis_polygon::centroid_xy(double *x, double *y) const { uint32 n_linear_rings; - double res_area; - double res_cx, res_cy; + double UNINIT_VAR(res_area); + double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); const char *data= m_data; bool first_loop= 1; - LINT_INIT(res_area); - LINT_INIT(res_cx); - LINT_INIT(res_cy); if (no_data(data, 4)) return 1; @@ -1634,14 +1631,10 @@ int Gis_multi_polygon::centroid(String *result) const uint32 n_polygons; bool first_loop= 1; Gis_polygon p; - double res_area, res_cx, res_cy; + double UNINIT_VAR(res_area), UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); double cur_area, cur_cx, cur_cy; const char *data= m_data; - LINT_INIT(res_area); - LINT_INIT(res_cx); - LINT_INIT(res_cy); - if (no_data(data, 4)) return 1; n_polygons= uint4korr(data); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ab4e518d5dd..ea17a4227ef 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5067,17 +5067,13 @@ static int handle_grant_struct(uint struct_no, bool drop, uint elements; const char *user; const char *host; - ACL_USER *acl_user; - ACL_DB *acl_db; - GRANT_NAME *grant_name; + ACL_USER *UNINIT_VAR(acl_user); + ACL_DB *UNINIT_VAR(acl_db); + GRANT_NAME *UNINIT_VAR(grant_name); DBUG_ENTER("handle_grant_struct"); DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'", struct_no, user_from->user.str, user_from->host.str)); - LINT_INIT(acl_user); - LINT_INIT(acl_db); - LINT_INIT(grant_name); - safe_mutex_assert_owner(&acl_cache->lock); /* Get the number of elements in the in-memory structure. */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6a99d5d1541..db4ab29d6de 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -706,7 +706,7 @@ void close_temporary_tables(THD *thd) return; } - TABLE *next, + TABLE *UNINIT_VAR(next), *prev_table /* prev link is not maintained in TABLE's double-linked list */; bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */ // Better add "if exists", in case a RESET MASTER has been done @@ -716,7 +716,6 @@ void close_temporary_tables(THD *thd) memcpy(buf, stub, stub_len); String s_query= String(buf, sizeof(buf), system_charset_info); bool found_user_tables= false; - LINT_INIT(next); /* insertion sort of temp tables by pseudo_thread_id to build ordered list @@ -4142,8 +4141,7 @@ find_item_in_list(Item *find, List &items, uint *counter, (and not an item that happens to have a name). */ bool is_ref_by_name= 0; - uint unaliased_counter; - LINT_INIT(unaliased_counter); // Dependent on found_unaliased + uint UNINIT_VAR(unaliased_counter); // Dependent on found_unaliased *resolution= NOT_RESOLVED; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 45f70964f50..65b2a9d60b0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1325,7 +1325,7 @@ pthread_handler_t handle_bootstrap(void *arg) thd->init_for_queries(); while (fgets(buff, thd->net.max_packet, file)) { - char *query; + char *query, *res; ulong length= (ulong) strlen(buff); while (buff[length-1] != '\n' && !feof(file)) { @@ -1340,7 +1340,7 @@ pthread_handler_t handle_bootstrap(void *arg) break; } buff= (char*) thd->net.buff; - fgets(buff + length, thd->net.max_packet - length, file); + res= fgets(buff + length, thd->net.max_packet - length, file); length+= (ulong) strlen(buff + length); } if (thd->is_fatal_error) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d14f14b526e..06f77f9689c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2072,10 +2072,9 @@ void mysql_sql_stmt_prepare(THD *thd) LEX_STRING *name= &lex->prepared_stmt_name; Prepared_statement *stmt; const char *query; - uint query_len; + uint UNINIT_VAR(query_len); DBUG_ENTER("mysql_sql_stmt_prepare"); DBUG_ASSERT(thd->protocol == &thd->protocol_simple); - LINT_INIT(query_len); if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9eac750c22e..13045280c5f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2172,8 +2172,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) ST_SCHEMA_TABLE *schema_table= tables->schema_table; SELECT_LEX sel; INDEX_FIELD_VALUES idx_field_vals; - char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name; - uint len; + char path[FN_REFLEN], *UNINIT_VAR(end), *base_name, *orig_base_name, *file_name; + uint UNINIT_VAR(len); bool with_i_schema; enum enum_schema_tables schema_table_idx; List bases; @@ -2190,9 +2190,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) #endif DBUG_ENTER("get_all_tables"); - LINT_INIT(end); - LINT_INIT(len); - lex->view_prepare_mode= TRUE; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c18c34fc1d1..06d1bcaa8fb 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -125,7 +125,7 @@ int mysql_update(THD *thd, uint want_privilege; #endif uint table_count= 0; - query_id_t query_id=thd->query_id, timestamp_query_id; + query_id_t query_id=thd->query_id, UNINIT_VAR(timestamp_query_id); ha_rows updated, found; key_map old_used_keys; TABLE *table; @@ -137,8 +137,6 @@ int mysql_update(THD *thd, THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_update"); - LINT_INIT(timestamp_query_id); - for ( ; ; ) { if (open_tables(thd, &table_list, &table_count, 0)) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 96077aeeb12..8cf25e9d88c 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -955,7 +955,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, TABLE_LIST *top_view= table->top_table(); int res; bool result, view_is_mergeable; - TABLE_LIST *view_main_select_tables; + TABLE_LIST *UNINIT_VAR(view_main_select_tables); DBUG_ENTER("mysql_make_view"); DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name)); @@ -1218,7 +1218,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE && lex->can_be_merged()); - LINT_INIT(view_main_select_tables); if (view_is_mergeable) { -- cgit v1.2.1 From f32c08bd0ca20d23e95ca46912044d48282cfd6f Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Aug 2009 16:52:22 +0800 Subject: Bug #44331 Restore of database with events produces warning in replication If an EVENT is created without the DEFINER clause set explicitly or with it set to CURRENT_USER, the master and slaves become inconsistent. This issue stems from the fact that in both cases, the DEFINER is set to the CURRENT_USER of the current thread. On the master, the CURRENT_USER is the mysqld's user, while on the slave, the CURRENT_USER is empty for the SQL Thread which is responsible for executing the statement. To fix the problem, we do what follows. If the definer is not set explicitly, a DEFINER clause is added when writing the query into binlog; if 'CURRENT_USER' is used as the DEFINER, it is replaced with the value of the current user before writing to binlog. mysql-test/suite/rpl/r/rpl_create_if_not_exists.result: Updated the result file after fixing bug#44331 mysql-test/suite/rpl/r/rpl_drop_if_exists.result: Updated the result file after fixing bug#44331 mysql-test/suite/rpl/r/rpl_events.result: Test result of Bug#44331 mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: Updated the result file after fixing bug#44331 mysql-test/suite/rpl/t/rpl_events.test: Added test to verify if the definer is consistent between master and slave when the event is created without the DEFINER clause set explicitly or the DEFINER is set to CURRENT_USER sql/events.cc: The "create_query_string" function is added to create a new query string for removing executable comments. sql/sql_yacc.yy: The remember_name token was added for recording the offset of EVENT_SYM. --- sql/events.cc | 38 +++++++++++++++++++++++++++++++++++++- sql/sql_yacc.yy | 7 ++++--- 2 files changed, 41 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/events.cc b/sql/events.cc index 10edfff2402..34da0e185b7 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -341,6 +341,33 @@ common_1_lev_code: } +/** + Create a new query string for removing executable comments + for avoiding leak and keeping consistency of the execution + on master and slave. + + @param[in] thd Thread handler + @param[in] buf Query string + + @return + 0 ok + 1 error +*/ +static int +create_query_string(THD *thd, String *buf) +{ + /* Append the "CREATE" part of the query */ + if (buf->append(STRING_WITH_LEN("CREATE "))) + return 1; + /* Append definer */ + append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + /* Append the left part of thd->query after "DEFINER" part */ + if (buf->append(thd->lex->stmt_definition_begin)) + return 1; + + return 0; +} + /** Create a new event. @@ -439,7 +466,16 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, { /* Binlog the create event. */ DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + String log_query; + if (create_query_string(thd, &log_query)) + { + sql_print_error("Event Error: An error occurred while creating query string, " + "before writing it into binary log."); + DBUG_RETURN(TRUE); + } + /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER + will be written into the binary log as the definer for the SQL thread. */ + write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length()); } } pthread_mutex_unlock(&LOCK_event_metadata); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c7e955d122d..a18f57bf9cf 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1809,15 +1809,16 @@ server_option: ; event_tail: - EVENT_SYM opt_if_not_exists sp_name + remember_name EVENT_SYM opt_if_not_exists sp_name { THD *thd= YYTHD; LEX *lex=Lex; - lex->create_info.options= $2; + lex->stmt_definition_begin= $1; + lex->create_info.options= $3; if (!(lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; - lex->event_parse_data->identifier= $3; + lex->event_parse_data->identifier= $4; lex->event_parse_data->on_completion= Event_parse_data::ON_COMPLETION_DROP; -- cgit v1.2.1 From 6ce48392ea410ecb9937ea07943cc6434a5ac378 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Sun, 30 Aug 2009 11:03:37 +0400 Subject: Bug #46607: Assertion failed: (cond_type == Item::FUNC_ITEM) results in server crash check_group_min_max_predicates() assumed the input condition item to be one of COND_ITEM, SUBSELECT_ITEM, or FUNC_ITEM. Since a condition of the form "field" is also a valid condition equivalent to "field <> 0", using such a condition in a query where the loose index scan was chosen resulted in a debug assertion failure. Fixed by handling conditions of the FIELD_ITEM type in check_group_min_max_predicates(). mysql-test/r/group_min_max.result: Added a test case for bug #46607. mysql-test/t/group_min_max.test: Added a test case for bug #46607. sql/opt_range.cc: Handle conditions of the FUNC_ITEM type in check_group_mix_max_predicates(). --- sql/opt_range.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e3aef02637f..d7438b7b9cc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9628,7 +9628,17 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, */ if (cond_type == Item::SUBSELECT_ITEM) DBUG_RETURN(FALSE); - + + /* + Condition of the form 'field' is equivalent to 'field <> 0' and thus + satisfies the SA3 condition. + */ + if (cond_type == Item::FIELD_ITEM) + { + DBUG_PRINT("info", ("Analyzing: %s", cond->full_name())); + DBUG_RETURN(TRUE); + } + /* We presume that at this point there are no other Items than functions. */ DBUG_ASSERT(cond_type == Item::FUNC_ITEM); -- cgit v1.2.1 From f0720480dc641195999086b5c36d3d6a03b1a935 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 2 Sep 2009 13:22:47 +0300 Subject: Fixed win32 compilation warnings --- 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 9f88fa93c06..4ec104aedc3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -117,7 +117,7 @@ static char* add_identifier(char *to_p, const char * end_p, *(to_p++)= '`'; *(to_p++)= *(conv_name++); } - else if (length < (end_p - to_p)) + else if (((long) length) < (end_p - to_p)) { to_p= strnmov(to_p, conv_name, length); conv_name+= length; -- cgit v1.2.1 From 32c7efa6b420b09e00d42b99f29a790064694d3b Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 2 Sep 2009 16:19:28 +0500 Subject: BUG#46483 - drop table of partitioned table may leave extraneous file Online/fast ALTER TABLE of a partitioned table may leave temporary file in database directory. Fixed by removing unnecessary call to handler::ha_create_handler_files(), which was creating partitioning definition file. mysql-test/r/partition_innodb.result: A test case for BUG#46483. mysql-test/t/partition_innodb.test: A test case for BUG#46483. sql/unireg.cc: Do not call ha_create_handler_files() when we were requested to create only dot-frm file. --- sql/unireg.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/unireg.cc b/sql/unireg.cc index 68a352e4a44..60674b8390b 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -412,10 +412,10 @@ int rea_create_table(THD *thd, const char *path, DBUG_ASSERT(*fn_rext(frm_name)); if (thd->variables.keep_files_on_create) create_info->options|= HA_CREATE_KEEP_FILES; - if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) - goto err_handler; - if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, - create_info,0)) + if (!create_info->frm_only && + (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, + create_info) || + ha_create_table(thd, path, db, table_name, create_info, 0))) goto err_handler; DBUG_RETURN(0); -- cgit v1.2.1 From 7c9e39f5c5a57c1d68c146b3982d643f93750eda Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 2 Sep 2009 15:20:47 +0300 Subject: fixed a valgrind warning in partitioning code --- sql/sql_partition.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d433ba0b0cc..08ff2daacb9 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6909,6 +6909,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, Field *field; uint total_parts; partition_iter_func get_next_func; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; if (is_subpart) { field= part_info->subpart_field_array[0]; -- cgit v1.2.1 From b64e7fb5befaee89f1db90db05e80e4249feba77 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 2 Sep 2009 18:42:08 +0300 Subject: fixed a valgrind warning in partition_pruning --- sql/partition_info.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/partition_info.h b/sql/partition_info.h index 8832b6ee409..9f438e8260b 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -311,5 +311,6 @@ void init_all_partitions_iterator(partition_info *part_info, { part_iter->part_nums.start= part_iter->part_nums.cur= 0; part_iter->part_nums.end= part_info->no_parts; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } -- cgit v1.2.1 From 76b8bd35898ea74734b4c57c10bdb2928dd7dd55 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Thu, 3 Sep 2009 12:08:55 +0200 Subject: Bug#46486 warnings produced when running mysql_install_db During start up some plugins are disabled by default. This caused an additional warning level message to be emitted as a result of a previous bug patch. Since there is risk of unnecessary confusion regarding the operation level of the server the redundant information is removed. --- sql/sql_plugin.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index da168d36429..f00e1f72390 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1565,9 +1565,6 @@ void plugin_shutdown(void) } } - if (count > free_slots) - sql_print_warning("Forcing shutdown of %d plugins", count - free_slots); - plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1)); /* -- cgit v1.2.1 From 2fc9c5d19993f4af526b97153ee7363ac108831b Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 3 Sep 2009 16:02:03 +0530 Subject: Fix for BUG#46591 - .frm file isn't sync'd with sync_frm enabled for CREATE TABLE...LIKE... The mysql server option 'sync_frm' is ignored when table is created with syntax CREATE TABLE .. LIKE.. Fixed by adding the MY_SYNC flag and calling my_sync() from my_copy() when the flag is set. In mysql_create_table(), when the 'sync_frm' is set, MY_SYNC flag is passed to my_copy(). Note: TestCase is not attached and can be tested manually using debugger. client/Makefile.am: BUG#46591 - .frm file isn't sync'd with sync_frm enabled for CREATE TABLE...LIKE... add my_sync to sources as it is used in my_copy() method include/my_sys.h: BUG#46591 - .frm file isn't sync'd with sync_frm enabled for CREATE TABLE...LIKE... MY_SYNC flag is added to call my_sync() method mysys/my_copy.c: BUG#46591 - .frm file isn't sync'd with sync_frm enabled for CREATE TABLE...LIKE... my_sync() is method is called when MY_SYNC is set in my_copy() sql/sql_table.cc: BUG#46591 - .frm file isn't sync'd with sync_frm enabled for CREATE TABLE...LIKE... Fixed mysql_create_like_table() to call my_sync() when opt_sync_frm variable is set --- sql/sql_table.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 84370873054..5a3100685e0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2773,6 +2773,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, int err; bool res= TRUE; db_type not_used; + myf flags= MY_DONT_OVERWRITE_FILE; DBUG_ENTER("mysql_create_like_table"); /* @@ -2859,10 +2860,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000);); + if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + flags|= MY_SYNC; + /* Create a new table by copying from source table + and sync the new table if the flag MY_SYNC is set */ - if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE))) + if (my_copy(src_path, dst_path, flags)) { if (my_errno == ENOENT) my_error(ER_BAD_DB_ERROR,MYF(0),db); -- cgit v1.2.1 From 629557ff13e28e3422dfa1c354c44ef2fd62e4d0 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 3 Sep 2009 18:03:46 +0300 Subject: Bug #46791: Assertion failed:(table->key_read==0),function unknown function,file sql_base.cc When uncacheable queries are written to a temp table the optimizer must preserve the original JOIN structure, because it is re-using the JOIN structure to read from the resulting temporary table. This was done only for uncacheable sub-queries. But top level queries can also benefit from this mechanism, specially if they're using index access and need a reset. Fixed by not limiting the saving of JOIN structure to subqueries exclusively. Added a new test file to extend the existing (large) subquery.test. --- sql/sql_select.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b670e6e3637..9d5e67c9532 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1474,12 +1474,8 @@ JOIN::optimize() } } - /* - If this join belongs to an uncacheable subquery save - the original join - */ - if (select_lex->uncacheable && !is_top_level_join() && - init_save_join_tab()) + /* If this join belongs to an uncacheable query save the original join */ + if (select_lex->uncacheable && init_save_join_tab()) DBUG_RETURN(-1); /* purecov: inspected */ } -- cgit v1.2.1 From 9776b6f9cd4fc4d8c84ae373fd0a44c486c7c2e2 Mon Sep 17 00:00:00 2001 From: V Narayanan Date: Fri, 4 Sep 2009 09:27:11 +0530 Subject: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Inserting a negative value in the autoincrement column of a partitioned innodb table was causing the value of the auto increment counter to wrap around into a very large positive value. The consequences are the same as if a very large positive value was inserted into a column, e.g. reduced autoincrement range, failure to read autoincrement counter. The current patch ensures that before calculating the next auto increment value, the current value is within the positive maximum allowed limit. mysql-test/suite/parts/inc/partition_auto_increment.inc: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Adds tests for performing insert,update and delete on a partition table with negative auto_increment values. mysql-test/suite/parts/r/partition_auto_increment_innodb.result: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Result file for the innodb engine. mysql-test/suite/parts/r/partition_auto_increment_memory.result: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Result file for the memory engine. mysql-test/suite/parts/r/partition_auto_increment_myisam.result: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Result file for the myisam engine. mysql-test/suite/parts/r/partition_auto_increment_ndb.result: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Result file for the ndb engine. mysql-test/suite/parts/t/partition_auto_increment_archive.test: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Adds a variable that allows the Archive engine to skip tests that involve insertion of negative auto increment values. mysql-test/suite/parts/t/partition_auto_increment_blackhole.test: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Adds a variable that allows the Blackhole engine to skip tests that involve insertion of negative auto increment values. sql/ha_partition.cc: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Ensures that the current value is lesser than the upper limit for the type of the field before setting the next auto increment value to be calculated. sql/ha_partition.h: Bug#45823 Assertion failure in file row/row0mysql.c line 1386 Modifies the set_auto_increment_if_higher function, to take into account negative auto increment values when doing a comparison. --- sql/ha_partition.cc | 4 ++-- sql/ha_partition.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..63f8271cca1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3024,7 +3024,7 @@ int ha_partition::write_row(uchar * buf) tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[part_id]->ha_write_row(buf); if (have_auto_increment && !table->s->next_number_keypart) - set_auto_increment_if_higher(table->next_number_field->val_int()); + set_auto_increment_if_higher(table->next_number_field); reenable_binlog(thd); exit: table->timestamp_field_type= orig_timestamp_type; @@ -3128,7 +3128,7 @@ exit: HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; if (!ha_data->auto_inc_initialized) info(HA_STATUS_AUTO); - set_auto_increment_if_higher(table->found_next_number_field->val_int()); + set_auto_increment_if_higher(table->found_next_number_field); } table->timestamp_field_type= orig_timestamp_type; DBUG_RETURN(error); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 8a81a759e2a..d0301e24a93 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -936,9 +936,11 @@ private: auto_increment_lock= FALSE; } } - virtual void set_auto_increment_if_higher(const ulonglong nr) + virtual void set_auto_increment_if_higher(Field *field) { HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; + ulonglong nr= (((Field_num*) field)->unsigned_flag || + field->val_int() > 0) ? field->val_int() : 0; lock_auto_increment(); DBUG_ASSERT(ha_data->auto_inc_initialized == TRUE); /* must check when the mutex is taken */ -- cgit v1.2.1 From 6e27ef435e3863382295f1a1d41424c9b8d4c197 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 4 Sep 2009 12:21:54 +0530 Subject: Fix for BUG#46384 - mysqld segfault when trying to create table with same name as existing view When trying to create a table with the same name as existing view with join, mysql server crashes. The problem is when create table is issued with the same name as view, while verifying with the existing tables, we assume that base table object is created always. In this case, since it is a view over multiple tables, we don't have the mysql derived table object. Fixed the logic which checks if there is an existing table to not to assume that table object is created when the base table is view over multiple tables. mysql-test/r/create.result: BUG#46384 - mysqld segfault when trying to create table with same name as existing view Testcase for the bug mysql-test/t/create.test: BUG#46384 - mysqld segfault when trying to create table with same name as existing view Testcase for the bug sql/sql_insert.cc: BUG#46384 - mysqld segfault when trying to create table with same name as existing view Fixed create_table_from_items() method to properly check, if the base table is a view over multiple tables. --- sql/sql_insert.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d2a0f47f1a9..b0958201795 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3217,7 +3217,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000);); if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) && - create_table->table->db_stat) + (create_table->table && create_table->table->db_stat)) { /* Table already exists and was open at open_and_lock_tables() stage. */ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) -- cgit v1.2.1 From 643fbe4234a06e51746c8912223652a3b41fe133 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 4 Sep 2009 12:20:53 +0500 Subject: Bug#45989 memory leak after explain encounters an error in the query Memory allocated in TMP_TABLE_PARAM::copy_field is not cleaned up. The fix is to clean up TMP_TABLE_PARAM::copy_field array in JOIN::destroy. mysql-test/r/explain.result: test result mysql-test/t/explain.test: test case sql/sql_select.cc: Memory allocated in TMP_TABLE_PARAM::copy_field is not cleaned up. The fix is to clean up TMP_TABLE_PARAM::copy_field array in JOIN::destroy. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ff179c432a8..b670e6e3637 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2176,7 +2176,7 @@ JOIN::destroy() } } tmp_join->tmp_join= 0; - tmp_table_param.copy_field=0; + tmp_table_param.cleanup(); DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; -- cgit v1.2.1 From 2a6ac469fc7cd940d7864babafb72798b7643bf3 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Fri, 4 Sep 2009 13:14:54 +0500 Subject: Fix for bug#46629: Item_in_subselect::val_int(): Assertion `0' on subquery inside a SP Problem: repeated call of a SP containing an incorrect query with a subselect may lead to failed ASSERT(). Fix: set proper sublelect's state in case of error occured during subquery transformation. mysql-test/r/sp.result: Fix for bug#46629: Item_in_subselect::val_int(): Assertion `0' on subquery inside a SP - test result. mysql-test/t/sp.test: Fix for bug#46629: Item_in_subselect::val_int(): Assertion `0' on subquery inside a SP - test case. sql/item_subselect.cc: Fix for bug#46629: Item_in_subselect::val_int(): Assertion `0' on subquery inside a SP - don't set Item_subselect::changed in the Item_subselect::fix_fields() if an error occured during subquery transformation. That prevents us of further processing incorrect subqueries after Item_in_subselect::select_in_like_transformer(). --- sql/item_subselect.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index cdb091fa07e..da651cec70c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -155,13 +155,11 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res)) return TRUE; - res= engine->prepare(); - - // all transformation is done (used by prepared statements) - changed= 1; - - if (!res) + if (!(res= engine->prepare())) { + // all transformation is done (used by prepared statements) + changed= 1; + if (substitution) { int ret= 0; -- cgit v1.2.1 From 0c4c2d7b8db1fead32aa48b12d538b5a8b522c59 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Fri, 4 Sep 2009 12:32:21 +0200 Subject: Bug#46486 warnings produced when running mysql_install_db Incremental patch part 2 Removing dead code and changing a note level message to a warning. sql/sql_plugin.cc: * Remove free_slots. The only purpose for this variable was to trigger a redundant warning message and it failed. * Change the note level message about shutting down plugins which didn't end nicely to a warning level message. (If this shutdown fails and there still are reference counts in the plugin an additional error level message is emitted) --- sql/sql_plugin.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index f00e1f72390..025c8a8248d 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1520,7 +1520,7 @@ error: void plugin_shutdown(void) { - uint i, count= plugin_array.elements, free_slots= 0; + uint i, count= plugin_array.elements; struct st_plugin_int **plugins, *plugin; struct st_plugin_dl **dl; DBUG_ENTER("plugin_shutdown"); @@ -1541,18 +1541,13 @@ void plugin_shutdown(void) while (reap_needed && (count= plugin_array.elements)) { reap_plugins(); - for (i= free_slots= 0; i < count; i++) + for (i= 0; i < count; i++) { plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **); - switch (plugin->state) { - case PLUGIN_IS_READY: + if (plugin->state == PLUGIN_IS_READY) + { plugin->state= PLUGIN_IS_DELETED; reap_needed= true; - break; - case PLUGIN_IS_FREED: - case PLUGIN_IS_UNINITIALIZED: - free_slots++; - break; } } if (!reap_needed) @@ -1586,8 +1581,8 @@ void plugin_shutdown(void) if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED | PLUGIN_IS_DISABLED))) { - sql_print_information("Plugin '%s' will be forced to shutdown", - plugins[i]->name.str); + sql_print_warning("Plugin '%s' will be forced to shutdown", + plugins[i]->name.str); /* We are forcing deinit on plugins so we don't want to do a ref_count check until we have processed all the plugins. -- cgit v1.2.1 From 35d6911b283b3cf7720af9a7edb8c7ed3b3726db Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 4 Sep 2009 15:02:15 +0200 Subject: Bug#35845: unneccesary call to ha_start_bulk_insert for not used partitions (Backport) Problem is that when insert (ha_start_bulk_insert) in i partitioned table, it will call ha_start_bulk_insert for every partition, used or not. Solution is to delay the call to the partitions ha_start_bulk_insert until the first row is to be inserted into that partition sql/ha_partition.cc: Bug#35845: unneccesary call to ha_start_bulk_insert for not used partitions Using a bitmap for keeping record of which partitions for which ha_start_bulk_insert has been called, and check against that if one should call it before continue with the insert/update, or if it has already been called. This way it will only call ha_start_bulk_insert for the used partitions. There is also a little prediction on how many rows that will be inserted into the current partition, it will guess on equal distribution of the records across all partitions, accept for the first used partition, which will guess at 50% of the given estimate, if it is a monotonic partitioning function. sql/ha_partition.h: Bug#35845: unneccesary call to ha_start_bulk_insert for not used partitions Added help variables and function for delaying ha_bulk_insert until it has to be called. Fixed a comment. --- sql/ha_partition.cc | 95 +++++++++++++++++++++++++++++++++++++++++++++-------- sql/ha_partition.h | 10 +++++- 2 files changed, 91 insertions(+), 14 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 63f8271cca1..c849bbd12c5 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -239,6 +239,7 @@ void ha_partition::init_handler_variables() m_curr_key_info[0]= NULL; m_curr_key_info[1]= NULL; is_clone= FALSE, + m_part_func_monotonicity_info= NON_MONOTONIC; auto_increment_lock= FALSE; auto_increment_safe_stmt_log_lock= FALSE; /* @@ -2464,11 +2465,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) } } + /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */ + if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE)) + DBUG_RETURN(1); + bitmap_clear_all(&m_bulk_insert_started); /* Initialize the bitmap we use to determine what partitions are used */ if (!is_clone) { if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE)) + { + bitmap_free(&m_bulk_insert_started); DBUG_RETURN(1); + } bitmap_set_all(&(m_part_info->used_partitions)); } @@ -2552,12 +2560,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) calling open on all individual handlers. */ m_handler_status= handler_opened; + if (m_part_info->part_expr) + m_part_func_monotonicity_info= + m_part_info->part_expr->get_monotonicity_info(); + else if (m_part_info->list_of_part_fields) + m_part_func_monotonicity_info= MONOTONIC_STRICT_INCREASING; info(HA_STATUS_VARIABLE | HA_STATUS_CONST); DBUG_RETURN(0); err_handler: while (file-- != m_file) (*file)->close(); + bitmap_free(&m_bulk_insert_started); if (!is_clone) bitmap_free(&(m_part_info->used_partitions)); @@ -2605,6 +2619,7 @@ int ha_partition::close(void) DBUG_ASSERT(table->s == table_share); delete_queue(&m_queue); + bitmap_free(&m_bulk_insert_started); if (!is_clone) bitmap_free(&(m_part_info->used_partitions)); file= m_file; @@ -3021,6 +3036,8 @@ int ha_partition::write_row(uchar * buf) } m_last_part= part_id; DBUG_PRINT("info", ("Insert in partition %d", part_id)); + start_part_bulk_insert(part_id); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[part_id]->ha_write_row(buf); if (have_auto_increment && !table->s->next_number_keypart) @@ -3083,6 +3100,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) } m_last_part= new_part_id; + start_part_bulk_insert(new_part_id); if (new_part_id == old_part_id) { DBUG_PRINT("info", ("Update in partition %d", new_part_id)); @@ -3247,22 +3265,65 @@ int ha_partition::delete_all_rows() DESCRIPTION rows == 0 means we will probably insert many rows */ - void ha_partition::start_bulk_insert(ha_rows rows) { - handler **file; DBUG_ENTER("ha_partition::start_bulk_insert"); - rows= rows ? rows/m_tot_parts + 1 : 0; - file= m_file; - do - { - (*file)->ha_start_bulk_insert(rows); - } while (*(++file)); + m_bulk_inserted_rows= 0; + bitmap_clear_all(&m_bulk_insert_started); + /* use the last bit for marking if bulk_insert_started was called */ + bitmap_set_bit(&m_bulk_insert_started, m_tot_parts); DBUG_VOID_RETURN; } +/* + Check if start_bulk_insert has been called for this partition, + if not, call it and mark it called +*/ +void ha_partition::start_part_bulk_insert(uint part_id) +{ + if (!bitmap_is_set(&m_bulk_insert_started, part_id) && + bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) + { + m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows()); + bitmap_set_bit(&m_bulk_insert_started, part_id); + } + m_bulk_inserted_rows++; +} + + +/* + Try to predict the number of inserts into this partition. + + If less than 10 rows (including 0 which means Unknown) + just give that as a guess + If monotonic partitioning function was used + guess that 50 % of the inserts goes to the first partition + For all other cases, guess on equal distribution between the partitions +*/ +ha_rows ha_partition::guess_bulk_insert_rows() +{ + DBUG_ENTER("guess_bulk_insert_rows"); + + if (estimation_rows_to_insert < 10) + DBUG_RETURN(estimation_rows_to_insert); + + /* If first insert/partition and monotonic partition function, guess 50%. */ + if (!m_bulk_inserted_rows && + m_part_func_monotonicity_info != NON_MONOTONIC && + m_tot_parts > 1) + DBUG_RETURN(estimation_rows_to_insert / 2); + + /* Else guess on equal distribution (+1 is to avoid returning 0/Unknown) */ + if (m_bulk_inserted_rows < estimation_rows_to_insert) + DBUG_RETURN(((estimation_rows_to_insert - m_bulk_inserted_rows) + / m_tot_parts) + 1); + /* The estimation was wrong, must say 'Unknown' */ + DBUG_RETURN(0); +} + + /* Finish a large batch of insert rows @@ -3272,21 +3333,29 @@ void ha_partition::start_bulk_insert(ha_rows rows) RETURN VALUE >0 Error code 0 Success + + Note: end_bulk_insert can be called without start_bulk_insert + being called, see bug¤44108. + */ int ha_partition::end_bulk_insert() { int error= 0; - handler **file; + uint i; DBUG_ENTER("ha_partition::end_bulk_insert"); - file= m_file; - do + if (!bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) + DBUG_RETURN(error); + + for (i= 0; i < m_tot_parts; i++) { int tmp; - if ((tmp= (*file)->ha_end_bulk_insert())) + if (bitmap_is_set(&m_bulk_insert_started, i) && + (tmp= m_file[i]->ha_end_bulk_insert())) error= tmp; - } while (*(++file)); + } + bitmap_clear_all(&m_bulk_insert_started); DBUG_RETURN(error); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index d0301e24a93..f47dfe8f621 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -176,6 +176,11 @@ private: This to ensure it will work with statement based replication. */ bool auto_increment_safe_stmt_log_lock; + /** For optimizing ha_start_bulk_insert calls */ + MY_BITMAP m_bulk_insert_started; + ha_rows m_bulk_inserted_rows; + /** used for prediction of start_bulk_insert rows */ + enum_monotonicity_info m_part_func_monotonicity_info; public: handler *clone(MEM_ROOT *mem_root); virtual void set_part_info(partition_info *part_info) @@ -353,7 +358,6 @@ public: Bulk inserts are supported if all underlying handlers support it. start_bulk_insert and end_bulk_insert is called before and after a number of calls to write_row. - Not yet though. */ virtual int write_row(uchar * buf); virtual int update_row(const uchar * old_data, uchar * new_data); @@ -361,6 +365,10 @@ public: virtual int delete_all_rows(void); virtual void start_bulk_insert(ha_rows rows); virtual int end_bulk_insert(); +private: + ha_rows guess_bulk_insert_rows(); + void start_part_bulk_insert(uint part_id); +public: virtual bool is_fatal_error(int error, uint flags) { -- cgit v1.2.1 From 505346028f975d26f1353c46bdb3db618b1e306c Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Sun, 6 Sep 2009 00:42:17 +0400 Subject: Bug #46159: simple query that never returns The external 'for' loop in remove_dup_with_compare() handled HA_ERR_RECORD_DELETED by just starting over without advancing to the next record which caused an infinite loop. This condition could be triggered on certain data by a SELECT query containing DISTINCT, GROUP BY and HAVING clauses. Fixed remove_dup_with_compare() so that we always advance to the next record when receiving HA_ERR_RECORD_DELETED from rnd_next(). mysql-test/r/distinct.result: Added a test case for bug #46159. mysql-test/t/distinct.test: Added a test case for bug #46159. sql/sql_select.cc: Fixed remove_dup_with_compare() so that we always advance to the next record when receiving HA_ERR_RECORD_DELETED from rnd_next(). --- sql/sql_select.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5cb0de1ba5c..a02430446d1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13665,7 +13665,10 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (error) { if (error == HA_ERR_RECORD_DELETED) - continue; + { + error= file->rnd_next(record); + continue; + } if (error == HA_ERR_END_OF_FILE) break; goto err; -- cgit v1.2.1 From dd407c5228df80a7ef6086c412940084e7498627 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 7 Sep 2009 10:37:54 +0200 Subject: Fix to ensure that all subpartitions gets deleted before renaming starts, BUG#47029 --- sql/ha_partition.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..2e303744c1a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -705,6 +705,7 @@ int ha_partition::rename_partitions(const char *path) if (m_is_sub_partitioned) { List_iterator sub_it(part_elem->subpartitions); + j= 0; do { sub_elem= sub_it++; -- cgit v1.2.1 From 2cb3a131f47a8bcf0398a28e4a6a16d1c30c9708 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Mon, 7 Sep 2009 11:57:22 +0200 Subject: Bug#46259: 5.0.83 -> 5.1.36, query doesn't work The parser rule for expressions in a udf parameter list contains two hacks: First, the parser input stream is read verbatim, bypassing the lexer. Second, the Item::name field is overwritten. If the argument to a udf was a field, the field's name as seen by name resolution was overwritten this way. If the field name was quoted or escaped, it would appear as e.g. "`field`". Fixed by not overwriting field names. mysql-test/r/udf.result: Bug#46259: Test result. mysql-test/t/udf.test: Bug#46259: Test case. sql/sql_yacc.yy: Bug#46259: Fix. --- sql/sql_yacc.yy | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a18f57bf9cf..db97e77bbd0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7921,7 +7921,13 @@ udf_expr: $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } - else + /* + A field has to have its proper name in order for name + resolution to work, something we are only guaranteed if we + parse it out. If we hijack the input stream with + remember_name we may get quoted or escaped names. + */ + else if ($2->type() != Item::FIELD_ITEM) $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $$= $2; } -- cgit v1.2.1 From 3228a2be669f5d92a607b8212c9c3260a02fd47f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 9 Sep 2009 14:38:50 +0500 Subject: BUG#45638 - Create temporary table with engine innodb fails Create temporary InnoDB table fails on case insensitive filesystems, when lower_case_table_names is 2 (e.g. OS X) and temporary directory path contains upper case letters. The problem was that tmpdir prefix was converted to lower case when table was created, but was passed as is when table was opened. Fixed by leaving tmpdir prefix part intact. mysql-test/r/lowercase_mixed_tmpdir_innodb.result: A test case for BUG#45638. mysql-test/t/lowercase_mixed_tmpdir_innodb-master.opt: A test case for BUG#45638. mysql-test/t/lowercase_mixed_tmpdir_innodb-master.sh: A test case for BUG#45638. mysql-test/t/lowercase_mixed_tmpdir_innodb.test: A test case for BUG#45638. sql/handler.cc: Fixed get_canonical_filename() to not lowercase filesystem path prefix for temporary tables. --- sql/handler.cc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index e5c64452aaf..a4d88e84f4c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1885,12 +1885,42 @@ bool ha_flush_logs(handlerton *db_type) return FALSE; } + +/** + @brief make canonical filename + + @param[in] file table handler + @param[in] path original path + @param[out] tmp_path buffer for canonized path + + @details Lower case db name and table name path parts for + non file based tables when lower_case_table_names + is 2 (store as is, compare in lower case). + Filesystem path prefix (mysql_data_home or tmpdir) + is left intact. + + @note tmp_path may be left intact if no conversion was + performed. + + @retval canonized path + + @todo This may be done more efficiently when table path + gets built. Convert this function to something like + ASSERT_CANONICAL_FILENAME. +*/ const char *get_canonical_filename(handler *file, const char *path, char *tmp_path) { + uint i; if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED)) return path; + for (i= 0; i <= mysql_tmpdir_list.max; i++) + { + if (is_prefix(path, mysql_tmpdir_list.list[i])) + return path; + } + /* Ensure that table handler get path in lower case */ if (tmp_path != path) strmov(tmp_path, path); -- cgit v1.2.1 From 70972926ab8970267fa8e3f06086282c4b9e747d Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Thu, 10 Sep 2009 11:40:57 +0400 Subject: A patch for Bug#45118 (mysqld.exe crashed in debug mode on Windows in dbug.c) -- part 2: a patch for the DBUG subsystem to detect misuse of DBUG_ENTER / DBUG_RETURN macros. 5.1 version. --- sql/mysqld.cc | 4 +-- sql/rpl_filter.cc | 2 ++ sql/set_var.cc | 1 + sql/sql_insert.cc | 85 ++++++++++++++++++++++++++++++------------------------- sql/sql_parse.cc | 49 +++++++++++++++++++------------- 5 files changed, 82 insertions(+), 59 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3e2f8eabd39..3f536f01094 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4789,10 +4789,10 @@ static bool read_init_file(char *file_name) DBUG_ENTER("read_init_file"); DBUG_PRINT("enter",("name: %s",file_name)); if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME)))) - return(1); + DBUG_RETURN(TRUE); bootstrap(file); (void) my_fclose(file,MYF(MY_WME)); - return 0; + DBUG_RETURN(FALSE); } diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index 3004a3905e5..68272c58bb1 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -350,6 +350,7 @@ Rpl_filter::add_do_db(const char* table_spec) DBUG_ENTER("Rpl_filter::add_do_db"); i_string *db = new i_string(table_spec); do_db.push_back(db); + DBUG_VOID_RETURN; } @@ -359,6 +360,7 @@ Rpl_filter::add_ignore_db(const char* table_spec) DBUG_ENTER("Rpl_filter::add_ignore_db"); i_string *db = new i_string(table_spec); ignore_db.push_back(db); + DBUG_VOID_RETURN; } extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool); diff --git a/sql/set_var.cc b/sql/set_var.cc index 0b89333ce03..b64b54fdd29 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1238,6 +1238,7 @@ void fix_slave_exec_mode(enum_var_type type) } if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 0) bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT); + DBUG_VOID_RETURN; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b79b9b1ae9e..3ac40ae825a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2274,44 +2274,9 @@ void kill_delayed_threads(void) } -/* - * Create a new delayed insert thread -*/ - -pthread_handler_t handle_delayed_insert(void *arg) +static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) { - Delayed_insert *di=(Delayed_insert*) arg; - THD *thd= &di->thd; - - pthread_detach_this_thread(); - /* Add thread to THD list so that's it's visible in 'show processlist' */ - pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thd->set_current_time(); - threads.append(thd); - thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; - pthread_mutex_unlock(&LOCK_thread_count); - - /* - Wait until the client runs into pthread_cond_wait(), - where we free it after the table is opened and di linked in the list. - If we did not wait here, the client might detect the opened table - before it is linked to the list. It would release LOCK_delayed_create - and allow another thread to create another handler for the same table, - since it does not find one in the list. - */ - pthread_mutex_lock(&di->mutex); -#if !defined( __WIN__) /* Win32 calls this in pthread_create */ - if (my_thread_init()) - { - /* Can't use my_error since store_globals has not yet been called */ - thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); - goto end; - } -#endif - - DBUG_ENTER("handle_delayed_insert"); + DBUG_ENTER("handle_delayed_insert_impl"); thd->thread_stack= (char*) &thd; if (init_thr_lock() || thd->store_globals()) { @@ -2500,6 +2465,49 @@ err: */ ha_autocommit_or_rollback(thd, 1); + DBUG_VOID_RETURN; +} + + +/* + * Create a new delayed insert thread +*/ + +pthread_handler_t handle_delayed_insert(void *arg) +{ + Delayed_insert *di=(Delayed_insert*) arg; + THD *thd= &di->thd; + + pthread_detach_this_thread(); + /* Add thread to THD list so that's it's visible in 'show processlist' */ + pthread_mutex_lock(&LOCK_thread_count); + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + thd->set_current_time(); + threads.append(thd); + thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; + pthread_mutex_unlock(&LOCK_thread_count); + + /* + Wait until the client runs into pthread_cond_wait(), + where we free it after the table is opened and di linked in the list. + If we did not wait here, the client might detect the opened table + before it is linked to the list. It would release LOCK_delayed_create + and allow another thread to create another handler for the same table, + since it does not find one in the list. + */ + pthread_mutex_lock(&di->mutex); +#if !defined( __WIN__) /* Win32 calls this in pthread_create */ + if (my_thread_init()) + { + /* Can't use my_error since store_globals has not yet been called */ + thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); + goto end; + } +#endif + + handle_delayed_insert_impl(thd, di); + #ifndef __WIN__ end: #endif @@ -2523,7 +2531,8 @@ end: my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); + + return 0; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ca27d476213..a977740ebe2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -408,29 +408,12 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -/** - Execute commands from bootstrap_file. - - Used when creating the initial grant tables. -*/ - -pthread_handler_t handle_bootstrap(void *arg) +static void handle_bootstrap_impl(THD *thd) { - THD *thd=(THD*) arg; FILE *file=bootstrap_file; char *buff; const char* found_semicolon= NULL; - /* The following must be called before DBUG_ENTER */ - thd->thread_stack= (char*) &thd; - if (my_thread_init() || thd->store_globals()) - { -#ifndef EMBEDDED_LIBRARY - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#endif - thd->fatal_error(); - goto end; - } DBUG_ENTER("handle_bootstrap"); #ifndef EMBEDDED_LIBRARY @@ -525,6 +508,33 @@ pthread_handler_t handle_bootstrap(void *arg) #endif } + DBUG_VOID_RETURN; +} + + +/** + Execute commands from bootstrap_file. + + Used when creating the initial grant tables. +*/ + +pthread_handler_t handle_bootstrap(void *arg) +{ + THD *thd=(THD*) arg; + + /* The following must be called before DBUG_ENTER */ + thd->thread_stack= (char*) &thd; + if (my_thread_init() || thd->store_globals()) + { +#ifndef EMBEDDED_LIBRARY + close_connection(thd, ER_OUT_OF_RESOURCES, 1); +#endif + thd->fatal_error(); + goto end; + } + + handle_bootstrap_impl(thd); + end: net_end(&thd->net); thd->cleanup(); @@ -539,7 +549,8 @@ end: my_thread_end(); pthread_exit(0); #endif - DBUG_RETURN(0); + + return 0; } -- cgit v1.2.1 From 104d9ce76a68fd3da2f9217514a4c61454802c1d Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 10 Sep 2009 13:49:49 +0500 Subject: Bug#42364 SHOW ERRORS returns empty resultset after dropping non existent table partial backport of bug43138 fix mysql-test/r/warnings.result: test result mysql-test/t/warnings.test: test case sql/sql_class.cc: partial backport of bug43138 fix sql/sql_class.h: partial backport of bug43138 fix sql/sql_table.cc: partial backport of bug43138 fix --- sql/sql_class.cc | 25 +++++++++++++++++++++++++ sql/sql_class.h | 25 +++++++++++++++++++++++++ sql/sql_table.cc | 8 ++++---- 3 files changed, 54 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3f568566c89..daef5a26742 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -399,6 +399,31 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, return buffer; } + +/** + Implementation of Drop_table_error_handler::handle_error(). + The reason in having this implementation is to silence technical low-level + warnings during DROP TABLE operation. Currently we don't want to expose + the following warnings during DROP TABLE: + - Some of table files are missed or invalid (the table is going to be + deleted anyway, so why bother that something was missed); + - A trigger associated with the table does not have DEFINER (One of the + MySQL specifics now is that triggers are loaded for the table being + dropped. So, we may have a warning that trigger does not have DEFINER + attribute during DROP TABLE operation). + + @return TRUE if the condition is handled. +*/ +bool Drop_table_error_handler::handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + return ((sql_errno == EE_DELETE && my_errno == ENOENT) || + sql_errno == ER_TRG_NO_DEFINER); +} + + /** Clear this diagnostics area. diff --git a/sql/sql_class.h b/sql/sql_class.h index f52d5fae76f..c38eb17f191 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1091,6 +1091,31 @@ public: }; +/** + This class is an internal error handler implementation for + DROP TABLE statements. The thing is that there may be warnings during + execution of these statements, which should not be exposed to the user. + This class is intended to silence such warnings. +*/ + +class Drop_table_error_handler : public Internal_error_handler +{ +public: + Drop_table_error_handler(Internal_error_handler *err_handler) + :m_err_handler(err_handler) + { } + +public: + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + +private: + Internal_error_handler *m_err_handler; +}; + + /** Stores status of the currently executed statement. Cleared at the beginning of the statement, and then diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 89a84ebc1fe..41e76211dd8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1772,6 +1772,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, my_bool drop_temporary) { bool error= FALSE, need_start_waiters= FALSE; + Drop_table_error_handler err_handler(thd->get_internal_handler()); DBUG_ENTER("mysql_rm_table"); /* mark for close and remove all cached entries */ @@ -1792,7 +1793,10 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, LOCK_open during wait_if_global_read_lock(), other threads could not close their tables. This would make a pretty deadlock. */ + thd->push_internal_handler(&err_handler); error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); + thd->pop_internal_handler(); + if (need_start_waiters) start_waiting_global_read_lock(thd); @@ -1894,9 +1898,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, DBUG_RETURN(1); } - /* Don't give warnings for not found errors, as we already generate notes */ - thd->no_warnings_for_error= 1; - for (table= tables; table; table= table->next_local) { char *db=table->db; @@ -2145,7 +2146,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, err_with_placeholders: unlock_table_names(thd, tables, (TABLE_LIST*) 0); pthread_mutex_unlock(&LOCK_open); - thd->no_warnings_for_error= 0; DBUG_RETURN(error); } -- cgit v1.2.1 From e436b8866be640b2160f0b756f85559437cff67d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Sep 2009 18:05:53 +0800 Subject: BUG#45999 Row based replication fails when auto_increment field = 0 In RBR, There is an inconsistency between slaves and master. When INSERT statement which includes an auto_increment field is executed, Store engine of master will check the value of the auto_increment field. It will generate a sequence number and then replace the value, if its value is NULL or empty. if the field's value is 0, the store engine will do like encountering the NULL values unless NO_AUTO_VALUE_ON_ZERO is set into SQL_MODE. In contrast, if the field's value is 0, Store engine of slave always generates a new sequence number whether or not NO_AUTO_VALUE_ON_ZERO is set into SQL_MODE. SQL MODE of slave sql thread is always consistency with master's. Another variable is related to this bug. If generateing a sequence number is decided by the values of table->auto_increment_field_not_null and SQL_MODE(if includes MODE_NO_AUTO_VALUE_ON_ZERO) The table->auto_increment_is_not_null is FALSE, which causes this bug to appear. .. --- sql/log_event.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 0cda724b698..08fe3aba8ed 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8312,6 +8312,16 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability /* Honor next number column if present */ m_table->next_number_field= m_table->found_next_number_field; + /* + * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new + * sequence numbers for auto_increment fields if the values of them are 0. + * If generateing a sequence number is decided by the values of + * table->auto_increment_field_not_null and SQL_MODE(if includes + * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. + * SQL_MODE of slave sql thread is always consistency with master's. + * In RBR, auto_increment fields never are NULL. + */ + m_table->auto_increment_field_not_null= TRUE; return error; } @@ -8321,6 +8331,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * { int local_error= 0; m_table->next_number_field=0; + m_table->auto_increment_field_not_null= FALSE; if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) { -- cgit v1.2.1 From 10406ae65871de074e807e626f9ede686e9321d4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 10 Sep 2009 15:24:07 +0500 Subject: Bug#46815 CONCAT_WS returning wrong data The problem is that argument buffer can be used as result buffer and it leads to argument value change. The fix is to use 'old buffer' as result buffer only if first argument is not constant item. mysql-test/r/func_str.result: test result mysql-test/t/func_str.test: test case sql/item_strfunc.cc: The problem is that argument buffer can be used as result buffer and it leads to argument value change. The fix is to use 'old buffer' as result buffer only if first argument is not constant item. --- sql/item_strfunc.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e3fe67f4324..6f697a1665a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -600,6 +600,7 @@ String *Item_func_concat_ws::val_str(String *str) String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info), *sep_str, *res, *res2,*use_as_buff; uint i; + bool is_const= 0; null_value=0; if (!(sep_str= args[0]->val_str(&tmp_sep_str))) @@ -613,7 +614,11 @@ String *Item_func_concat_ws::val_str(String *str) // If not, return the empty string for (i=1; i < arg_count; i++) if ((res= args[i]->val_str(str))) + { + is_const= args[i]->const_item() || !args[i]->used_tables(); break; + } + if (i == arg_count) return &my_empty_string; @@ -631,7 +636,7 @@ String *Item_func_concat_ws::val_str(String *str) current_thd->variables.max_allowed_packet); goto null; } - if (res->alloced_length() >= + if (!is_const && res->alloced_length() >= res->length() + sep_str->length() + res2->length()) { // Use old buffer res->append(*sep_str); // res->length() > 0 always -- cgit v1.2.1 From b6c16b329a861b4b7da9cda2ede9921af912fd38 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Fri, 11 Sep 2009 22:06:27 +0500 Subject: Fix for bug#47130: misplaced or redundant check for null pointer? Problem: LOGGER::general_log_write() relied on valid "thd" parameter passed but had inconsistent "if (thd)" check. Fix: as we always pass a valid "thd" parameter to the method, redundant check removed. sql/log.cc: Fix for bug#47130: misplaced or redundant check for null pointer? - code clean-up, as we rely on the "thd" parameter in the LOGGER::general_log_write(), redundant "if (thd)" check removed, added assert(thd) instead. --- sql/log.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 1af2f3a4ddc..feaa5499912 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1024,14 +1024,10 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, Log_event_handler **current_handler= general_log_handler_list; char user_host_buff[MAX_USER_HOST_SIZE + 1]; Security_context *sctx= thd->security_ctx; - ulong id; uint user_host_len= 0; time_t current_time; - if (thd) - id= thd->thread_id; /* Normal thread */ - else - id= 0; /* Log from connect handler */ + DBUG_ASSERT(thd); lock_shared(); if (!opt_log) @@ -1050,7 +1046,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, while (*current_handler) error|= (*current_handler++)-> log_general(thd, current_time, user_host_buff, - user_host_len, id, + user_host_len, thd->thread_id, command_name[(uint) command].str, command_name[(uint) command].length, query, query_length, -- cgit v1.2.1 From 2535ede7138cb4d1e8986d18b4154c377ba37f3f Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 17 Sep 2009 16:33:23 +0500 Subject: Bug#42364 SHOW ERRORS returns empty resultset after dropping non existent table additional backport of of bug43138 fix mysql-test/t/myisam-system.test: additional backport of of bug43138 fix sql/sql_db.cc: additional backport of of bug43138 fix --- sql/sql_db.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 3fca5bd7df6..bcc8fcf54fc 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -907,6 +907,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) remove_db_from_cache(db); pthread_mutex_unlock(&LOCK_open); + Drop_table_error_handler err_handler(thd->get_internal_handler()); + thd->push_internal_handler(&err_handler); + error= -1; /* We temporarily disable the binary log while dropping the objects @@ -939,6 +942,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error = 0; reenable_binlog(thd); } + thd->pop_internal_handler(); } if (!silent && deleted>=0) { -- cgit v1.2.1 From ec7c4fb442842b46029f28355ece7d0104ea63ac Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 19 Oct 2009 13:40:08 +0200 Subject: port of fixes for bug-20577 and 46362 for TO_SECONDS --- sql/item_timefunc.cc | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 29fab2a38a2..fd05737728e 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -944,8 +944,29 @@ longlong Item_func_to_days::val_int() longlong Item_func_to_seconds::val_int_endpoint(bool left_endp, bool *incl_endp) { - longlong res= val_int(); - return null_value ? LONGLONG_MIN : res; + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + longlong seconds; + longlong days; + int dummy; /* unused */ + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) + { + /* got NULL, leave the incl_endp intact */ + return LONGLONG_MIN; + } + seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second; + seconds= ltime.neg ? -seconds : seconds; + days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day); + seconds+= days * 24L * 3600L; + /* Set to NULL if invalid date, but keep the value */ + null_value= check_date(<ime, + (ltime.year || ltime.month || ltime.day), + (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE), + &dummy); + /* + Even if the evaluation return NULL, seconds is useful for pruning + */ + return seconds; } longlong Item_func_to_seconds::val_int() @@ -956,10 +977,10 @@ longlong Item_func_to_seconds::val_int() longlong days; if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) return 0; - seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; + seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second; seconds=ltime.neg ? -seconds : seconds; - days= (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); - return (seconds + days * (24L * 3600L)); + days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day); + return seconds + days * 24L * 3600L; } /* @@ -992,10 +1013,9 @@ enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const { if (args[0]->type() == Item::FIELD_ITEM) { - if (args[0]->field_type() == MYSQL_TYPE_DATE) - return MONOTONIC_STRICT_INCREASING; - if (args[0]->field_type() == MYSQL_TYPE_DATETIME) - return MONOTONIC_INCREASING; + if (args[0]->field_type() == MYSQL_TYPE_DATE || + args[0]->field_type() == MYSQL_TYPE_DATETIME) + return MONOTONIC_STRICT_INCREASING_NOT_NULL; } return NON_MONOTONIC; } -- cgit v1.2.1 From 37b6043070ebed97158c4ef9e3c8534a8c23c860 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 20 Oct 2009 14:59:42 +0200 Subject: WL#3352: Extending Partitioning Types and new partition function Moved the new errors back to the end of errmsg.txt Updated two tests with new error message --- sql/share/errmsg.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a379b11c812..87ac1810c8e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5822,8 +5822,6 @@ ER_SAME_NAME_PARTITION eng "Duplicate partition name %-.192s" ger "Doppelter Partitionsname: %-.192s" swe "Duplicerat partitionsnamn %-.192s" -ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" ER_NO_BINLOG_ERROR eng "It is not allowed to shut off binlog on this command" ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten" @@ -6182,14 +6180,6 @@ ER_TOO_LONG_FIELD_COMMENT ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" -ER_PARTITION_COLUMN_LIST_ERROR - eng "Inconsistency in usage of column lists for partitioning" -ER_WRONG_TYPE_COLUMN_VALUE_ERROR - eng "Partition column values of incorrect type" -ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR - eng "Too many fields in '%s'" -ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR - eng "Cannot use MAXVALUE as value in List partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. @@ -6216,3 +6206,13 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" +ER_SAME_NAME_PARTITION_FIELD + eng "Duplicate partition field name %-.192s" +ER_PARTITION_COLUMN_LIST_ERROR + eng "Inconsistency in usage of column lists for partitioning" +ER_WRONG_TYPE_COLUMN_VALUE_ERROR + eng "Partition column values of incorrect type" +ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR + eng "Too many fields in '%-.192s'" +ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR + eng "Cannot use MAXVALUE as value in List partitioning" -- cgit v1.2.1