From 0897669cba1b314c36f41a8a31ee73b6d0d11115 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 9 Feb 2010 12:53:13 +0400 Subject: BUG#49902 - SELECT returns incorrect results Queries optimized with GROUP_MIN_MAX didn't cleanup KEYREAD optimization properly. As a result subsequent queries may return incomplete rows (fields are initialized to default values). mysql-test/r/group_min_max.result: A test case for BUG#49902. mysql-test/t/group_min_max.test: A test case for BUG#49902. sql/opt_range.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/opt_sum.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/sql_select.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/sql_update.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/table.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/table.h: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). --- sql/sql_update.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 433e2619aca..32add8679ef 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -397,10 +397,7 @@ int mysql_update(THD *thd, matching rows before updating the table! */ if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) - { - table->key_read=1; table->mark_columns_used_by_index(used_index); - } else { table->use_all_columns(); @@ -844,11 +841,7 @@ int mysql_update(THD *thd, err: delete select; free_underlaid_joins(thd, select_lex); - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); thd->abort_on_warning= 0; DBUG_RETURN(1); } -- cgit v1.2.1 From 630fa243c9a459526e225acc19fee30f4676a505 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Wed, 10 Feb 2010 15:37:34 +0100 Subject: Bug#49534: multitable IGNORE update with sql_safe_updates error causes debug assertion The IGNORE option of the multiple-table UPDATE command was not intended to suppress errors caused by the sql_safe_updates mode. This flag will raise an error if the execution of UPDATE does not use a key for row retrieval, and should continue do so regardless of the IGNORE option. However the implementation of IGNORE does not support exceptions to the rule; it always converts errors to warnings and cannot be extended. The Internal_error_handler interface offers the infrastructure to handle individual errors, making sure that the error raised by sql_safe_updates is not silenced. Fixed by implementing an Internal_error_handler and using it for UPDATE IGNORE commands. --- sql/sql_update.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 10 deletions(-) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 32add8679ef..84610630d62 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1188,6 +1188,56 @@ reopen_tables: } +/** + Implementation of the safe update options during UPDATE IGNORE. This syntax + causes an UPDATE statement to ignore all errors. In safe update mode, + however, we must never ignore the ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE. There + is a special hook in my_message_sql that will otherwise delete all errors + when the IGNORE option is specified. + + In the future, all IGNORE handling should be used with this class and all + traces of the hack outlined below should be removed. + + - The parser detects IGNORE option and sets thd->lex->ignore= 1 + + - In JOIN::optimize, if this is set, then + thd->lex->current_select->no_error gets set. + + - In my_message_sql(), if the flag above is set then any error is + unconditionally converted to a warning. + + We are moving in the direction of using Internal_error_handler subclasses + to do all such error tweaking, please continue this effort if new bugs + appear. + */ +class Safe_dml_handler : public Internal_error_handler { + +private: + bool m_handled_error; + +public: + explicit Safe_dml_handler() : m_handled_error(FALSE) {} + + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) + { + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR && + sql_errno == ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE) + + { + thd->main_da.set_error_status(thd, sql_errno, message); + m_handled_error= TRUE; + return TRUE; + } + return FALSE; + } + + bool handled_error() { return m_handled_error; } + +}; + /* Setup multi-update handling and call SELECT to do the join */ @@ -1216,18 +1266,35 @@ bool mysql_multi_update(THD *thd, MODE_STRICT_ALL_TABLES)); List total_list; + + Safe_dml_handler handler; + bool using_handler= thd->options & OPTION_SAFE_UPDATES; + if (using_handler) + thd->push_internal_handler(&handler); + res= mysql_select(thd, &select_lex->ref_pointer_array, - table_list, select_lex->with_wild, - total_list, - conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, - (ORDER *)NULL, - options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, - result, unit, select_lex); - DBUG_PRINT("info",("res: %d report_error: %d", res, - (int) thd->is_error())); + table_list, select_lex->with_wild, + total_list, + conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, + (ORDER *)NULL, + options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | + OPTION_SETUP_TABLES_DONE, + result, unit, select_lex); + + if (using_handler) + { + Internal_error_handler *top_handler= thd->pop_internal_handler(); + DBUG_ASSERT(&handler == top_handler); + } + + DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); res|= thd->is_error(); - if (unlikely(res)) + /* + Todo: remove below code and make Safe_dml_handler do error processing + instead. That way we can return the actual error instead of + ER_UNKNOWN_ERROR. + */ + if (unlikely(res) && (!using_handler || !handler.handled_error())) { /* If we had a another error reported earlier then this will be ignored */ result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); -- cgit v1.2.1 From 57a40848848274a83313f0d57bb184307e0ff87b Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Mon, 22 Feb 2010 14:23:47 +0100 Subject: Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 This is the final patch in the context of this bug. cmd-line-utils/readline/rlmbutil.h: Changed in a previous patch, reverted by a backport. cmd-line-utils/readline/text.c: Static var initialization. extra/yassl/include/yassl_error.hpp: SetErrorString handles errors outside of the YasslError enum. extra/yassl/src/ssl.cpp: SetErrorString handles errors outside of the YasslError enum. extra/yassl/src/yassl_error.cpp: SetErrorString handles errors outside of the YasslError enum. --- sql/sql_update.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 84610630d62..63af275cef3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1283,7 +1283,8 @@ bool mysql_multi_update(THD *thd, if (using_handler) { - Internal_error_handler *top_handler= thd->pop_internal_handler(); + Internal_error_handler *top_handler; + top_handler= thd->pop_internal_handler(); DBUG_ASSERT(&handler == top_handler); } -- cgit v1.2.1 From 4d0e9957acdddf7a07e095ef2e8f53a2cb99b24b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 28 Apr 2010 15:55:54 +0300 Subject: Bug #47453: InnoDB incorrectly changes TIMESTAMP columns when JOINed during an UPDATE Extended the fix for bug 29310 to multi-table update: When a table is being updated it has two set of fields - fields required for checks of conditions and fields to be updated. A storage engine is allowed not to retrieve columns marked for update. Due to this fact records can't be compared to see whether the data has been changed or not. This makes the server always update records independently of data change. Now when an auto-updatable timestamp field is present and server sees that a table handle isn't going to retrieve write-only fields then all of such fields are marked as to be read to force the handler to retrieve them. --- sql/sql_update.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 63af275cef3..d8141deba63 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1379,6 +1379,16 @@ int multi_update::prepare(List ¬_used_values, { table->read_set= &table->def_read_set; bitmap_union(table->read_set, &table->tmp_set); + /* + If a timestamp field settable on UPDATE is present then to avoid wrong + update force the table handler to retrieve write-only fields to be able + to compare records and detect data change. + */ + if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ && + table->timestamp_field && + (table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE || + table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH)) + bitmap_union(table->read_set, table->write_set); } } -- cgit v1.2.1 From 6659ad49fef7adf8fdf4db78403bbb45accc169b Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 13 May 2010 14:00:53 +0300 Subject: Fixes after last merge of MySQL 5.1 - INSERT with RAND() doesn't require row based logging again - Some bugs fixed in opt_range() where we table->key_read was wrongly used .bzrignore: Ignore new xtstat binary mysql-test/r/index_merge_myisam.result: Update results (old result was wrong) mysql-test/suite/binlog/r/binlog_stm_binlog.result: Added drop table first mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result: Added test for when RAND() requires row based logging mysql-test/suite/binlog/t/binlog_stm_binlog.test: Added drop table first mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test: Added test for when RAND() requires row based logging scripts/make_binary_distribution.sh: Removed type from last commit sql/item_create.cc: Don't require row based logging when using RAND() with INSERT sql/opt_range.cc: Revert wrong patch from Oracle: - As QUICK_RANGE_SELECT uses it's own 'file' handler to the tables, one can't use 'table->key_read' as a flag to detect if index only read (keyread) is used or not - Don't set keyread if keyread is already enabled - Don't disable key read, if we didn't enable it ourselves - Simplify code (and ensure that we do proper cleanup of index only read) sql/opt_range.h: Added flags to detect if the range optimizer enabled index only read (key read) or not sql/opt_sum.cc: Use our more optimized macros sql/sql_lex.h: Added 'readable' function to check if we are in a sub query function or not (not normal query or sub query in FROM clause) sql/sql_select.cc: Use our more optimized keyread macros Added ASSERTS early Simplify code on eliminate_item_equal() Fixed that substitute_for_best_equal_field() doesn't core dump in case of out of memory conditions. Removed not needed test for 'field->maybe_null()' Replaced master_unit()->item with is_subquery_function() (More readable) sql/sql_update.cc: Use our more optimized keyread macros sql/table.cc: Use our more optimized keyread macros sql/table.h: Use separate functions to enable/disable Index only reads - Safer, more readable, better logging and faster. --- sql/sql_update.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 1d1f9dedf22..d90480732cd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -841,7 +841,7 @@ int mysql_update(THD *thd, err: delete select; free_underlaid_joins(thd, select_lex); - table->set_keyread(FALSE); + table->disable_keyread(); thd->abort_on_warning= 0; DBUG_RETURN(1); } -- cgit v1.2.1 From d120c5b562629dda782e3c9a66cfeaa48cbb01d1 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 25 May 2010 23:14:18 -0700 Subject: Changed the fixes for the following bugs: Bug #39022: completed Bug #39653: reverted as invalid Bug #45640: ameliorated, simplified, optimized Bug #48483: completed Bug #49324: improved Bug #51242/52336: reverted, applied a real fix. --- sql/sql_update.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sql/sql_update.cc') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d90480732cd..c71060d4066 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -469,9 +469,10 @@ int mysql_update(THD *thd, thd_proc_info(thd, "Searching rows for update"); ha_rows tmp_limit= limit; - while (!(error=info.read_record(&info)) && !thd->killed) + while (!(error=info.read_record(&info)) && + !thd->killed && !thd->is_error()) { - if (!(select && select->skip_record())) + if (!select || select->skip_record(thd) > 0) { if (table->file->was_semi_consistent_read()) continue; /* repeat the read of the same row if it still exists */ @@ -577,7 +578,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { - if (!(select && select->skip_record())) + if (!select || select->skip_record(thd) > 0) { if (table->file->was_semi_consistent_read()) continue; /* repeat the read of the same row if it still exists */ -- cgit v1.2.1