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_class.cc | 4 ++- sql/sql_class.h | 2 +- sql/sql_update.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7b37a3f6e93..b22aa41b40a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -740,10 +740,12 @@ bool THD::handle_error(uint sql_errno, const char *message, } -void THD::pop_internal_handler() +Internal_error_handler *THD::pop_internal_handler() { DBUG_ASSERT(m_internal_handler != NULL); + Internal_error_handler *popped_handler= m_internal_handler; m_internal_handler= m_internal_handler->m_prev_internal_handler; + return popped_handler; } extern "C" diff --git a/sql/sql_class.h b/sql/sql_class.h index 77b4aa6c1d0..032985dc44e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2313,7 +2313,7 @@ public: /** Remove the error handler last pushed. */ - void pop_internal_handler(); + Internal_error_handler *pop_internal_handler(); /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); 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 f4a16558c81af480d1cd9e09bd3965e598c561ac Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 11 Feb 2010 21:10:13 +0100 Subject: Bug #47905 stored procedures with conditional statements not being logged to slow query log The problem is that the execution time for a multi-statement stored procedure as a whole may not be accurate, and thus not be entered into the slow query log even if the total time exceeds long_query_time. The reason for this is that THD::utime_after_lock used for time calculation may be reset at the start of each new statement, possibly leaving the total SP execution equal to the time spent executing the last statement in the SP. This patch stores the utime on start of SP execution, and restores it on exit of SP execution. A test is added. mysql-test/suite/sys_vars/r/slow_query_log_func.result: New test results for #47905. mysql-test/suite/sys_vars/t/slow_query_log_func.test: New test case for #47905. sql/sp_head.cc: Save and restore the THD::utime_after_lock on entry and exit of execute_procedure(). --- sql/sp_head.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 45cb4eebb09..8a626cabd90 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1848,6 +1848,8 @@ sp_head::execute_procedure(THD *thd, List *args) { bool err_status= FALSE; uint params = m_pcont->context_var_count(); + /* Query start time may be reset in a multi-stmt SP; keep this for later. */ + ulonglong utime_before_sp_exec= thd->utime_after_lock; sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; bool save_enable_slow_log= false; @@ -2040,6 +2042,7 @@ sp_head::execute_procedure(THD *thd, List *args) delete nctx; thd->spcont= save_spcont; + thd->utime_after_lock= utime_before_sp_exec; DBUG_RETURN(err_status); } -- cgit v1.2.1 From ee66332ce43f5aa05b9957ead4bc8dc9b540695e Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 27 Jan 2010 11:10:53 -0200 Subject: Bug#47734: Assertion failed: ! is_set() when locking a view with non-existing definer The problem was that a failure to open a view wasn't being properly handled. When opening a view with unknown definer, the open procedure would be treated as successful and would later crash when attempting to lock the view (which wasn't opened to begin with). The solution is to skip further processing when opening a table if it fails with a fatal error. mysql-test/r/view.result: Add test case result for Bug#47734. mysql-test/t/view.test: Add test case for Bug#47734. sql/sql_base.cc: Skip further processing if opening a table failed due to a fatal error (for the statement). --- sql/sql_base.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a1f34f6a770..06e4b1d3e63 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4591,7 +4591,20 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) safe_to_ignore_table= prelock_handler.safely_trapped_errors(); } else + { tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags); + + /* + Skip further processing if there has been a fatal error while + trying to open a table. For example, this might happen due to + stack shortage, unknown definer in views, etc. + */ + if (!tables->table && thd->is_error()) + { + result= -1; + goto err; + } + } } else DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx", -- cgit v1.2.1 From 63817720b41a9daa5d792d517c58ae29130cc254 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 10 Feb 2010 16:11:08 -0200 Subject: Bug#48449: hang on show create view after upgrading when view contains function of view SHOW CREATE TABLE on a view (v1) that contains a function whose statement uses another view (v2), could trigger a infinite loop if the view referenced within the function causes a warning to be raised while opening the said view (v2). The problem was a infinite loop over the stack of internal error handlers. The problem would be triggered if the stack contained two or more handlers and the first two handlers didn't handle the raised condition. In this case, the loop variable would always point to the second handler in the stack. The solution is to correct the loop variable assignment so that the loop is able to iterate over all handlers in the stack. mysql-test/r/view.result: Add test case result for Bug#48449. mysql-test/std_data/bug48449.frm: Add a incomplete view definition that causes a warning to be issued. mysql-test/t/view.test: Add test case for Bug#48449 sql/sql_class.cc: Iterate over all handlers in the stack. --- sql/sql_class.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b22aa41b40a..673fc9b78e6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -725,15 +725,12 @@ void THD::push_internal_handler(Internal_error_handler *handler) bool THD::handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level) { - if (!m_internal_handler) - return FALSE; - for (Internal_error_handler *error_handler= m_internal_handler; error_handler; - error_handler= m_internal_handler->m_prev_internal_handler) + error_handler= error_handler->m_prev_internal_handler) { if (error_handler->handle_error(sql_errno, message, level, this)) - return TRUE; + return TRUE; } return FALSE; -- cgit v1.2.1 From 32902dad006b68e2bdb855f9c2ea1910a9195c9c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 11 Feb 2010 19:41:53 +0200 Subject: Addendum to bug #46175 : use and check for the correct error values when converting to a enumerated type. --- sql/item.cc | 2 +- sql/sql_select.h | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index c967a1a0feb..df266434f72 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5157,7 +5157,7 @@ int Item::save_in_field(Field *field, bool no_conversions) field->set_notnull(); error=field->store(nr, unsigned_flag); } - return error ? error : (field->table->in_use->is_error() ? 2 : 0); + return error ? error : (field->table->in_use->is_error() ? 1 : 0); } diff --git a/sql/sql_select.h b/sql/sql_select.h index ef43f9b049c..8d3520bf9c8 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -736,10 +736,11 @@ public: we need to check for errors executing it and react accordingly */ if (!res && table->in_use->is_error()) - res= 2; + res= 1; /* STORE_KEY_FATAL */ dbug_tmp_restore_column_map(table->write_set, old_map); null_key= to_field->is_null() || item->null_value; - return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res); + return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL : + (store_key_result) res); } }; @@ -775,10 +776,10 @@ protected: we need to check for errors executing it and react accordingly */ if (!err && to_field->table->in_use->is_error()) - err= 2; + err= 1; /* STORE_KEY_FATAL */ } null_key= to_field->is_null() || item->null_value; - return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); + return ((err < 0 || err > 2) ? STORE_KEY_FATAL : (store_key_result) err); } }; -- cgit v1.2.1 From 46cffd7f5b585527387e2a23d1c3c43d2b14bf2c Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 12 Feb 2010 13:44:20 +0400 Subject: Bug#48294 assertion when creating a view based on some row() construct in select query In case of 'CREATE VIEW' subselect transformation does not happen(see JOIN::prepare). During fix_fields Item_row may call is_null() method for its arugmens which leads to item calculation(wrong subselect in our case as transformation did not happen before). This is_null() call does not make sence for 'CREATE VIEW'. Note: Only Item_row is affected because other items don't call is_null() during fix_fields() for arguments. mysql-test/r/view.result: test case mysql-test/t/view.test: test case sql/item_row.cc: skip is_null() call in case of 'CREATE VIEW' as unnecessary. --- sql/item_row.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_row.cc b/sql/item_row.cc index 28de03bf049..29b37eb2bc0 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -71,7 +71,12 @@ bool Item_row::fix_fields(THD *thd, Item **ref) Item *item= *arg; used_tables_cache |= item->used_tables(); const_item_cache&= item->const_item() && !with_null; - if (const_item_cache) + /* + Some subqueries transformations aren't done in the view_prepare_mode thus + is_null() will fail. So we skip is_null() calculation for CREATE VIEW as + not necessary. + */ + if (const_item_cache && !thd->lex->view_prepare_mode) { if (item->cols() > 1) with_null|= item->null_inside(); -- cgit v1.2.1 From d6ab925c5e10acc72cddbaf910d9aa4bee305c82 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Thu, 28 Jan 2010 12:41:14 -0200 Subject: Bug#50423: Crash on second call of a procedure dropping a trigger The problem was that a DROP TRIGGER statement inside a stored procedure could cause a crash in subsequent invocations. This was due to the addition, on the first execution, of a temporary table reference to the stored procedure query table list. In a subsequent invocation, there would be a attempt to reinitialize the temporary table reference, which by then was already gone. The solution is to backup and reset the query table list each time a trigger needs to be dropped. This ensures that any temp changes to the query table list are discarded. It is safe to do so at this time as drop trigger is restricted from more complicated scenarios (ie, not allowed within stored functions, etc). mysql-test/r/sp-bugs.result: Add test case result for Bug#50423 mysql-test/t/sp-bugs.test: Add test case for Bug#50423 sql/sql_trigger.cc: Backup and reset the query table list. Remove now unnecessary manual reset of the query table list. --- sql/sql_trigger.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ba0515d38ad..aafb25013f6 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -327,6 +327,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) TABLE *table; bool result= TRUE; String stmt_query; + Query_tables_list backup; bool need_start_waiting= FALSE; DBUG_ENTER("mysql_create_or_drop_trigger"); @@ -393,6 +394,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { bool if_exists= thd->lex->drop_if_exists; + /* + Protect the query table list from the temporary and potentially + destructive changes necessary to open the trigger's table. + */ + thd->lex->reset_n_backup_query_tables_list(&backup); + if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables)) goto end; @@ -512,6 +519,10 @@ end: VOID(pthread_mutex_unlock(&LOCK_open)); + /* Restore the query table list. Used only for drop trigger. */ + if (!create) + thd->lex->restore_backup_query_tables_list(&backup); + if (need_start_waiting) start_waiting_global_read_lock(thd); @@ -1625,10 +1636,6 @@ bool add_table_for_trigger(THD *thd, if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name)) DBUG_RETURN(TRUE); - /* We need to reset statement table list to be PS/SP friendly. */ - lex->query_tables= 0; - lex->query_tables_last= &lex->query_tables; - *table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str, tbl_name.str, TL_IGNORE); -- cgit v1.2.1 From 16c8298a85619674f1cce46c081e52f4fbeadb33 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 1 Feb 2010 16:07:00 +0100 Subject: Bug#42438: Crash ha_partition::change_table_ptr There was two problems: The first was the symptom, caused by bad error handling in ha_partition. It did not handle print_error etc. when having no partitions (when used by dummy handler). The second was the real problem that when dropping tables it reused the table type (storage engine) from when the lock was asked for, not the table type that it had when gaining the exclusive name lock. So that it tried to delete tables from wrong storage engines. Solutions for the first problem was to accept some handler calls to the partitioning handler even if it was not setup with any partitions, and also if possible fallback to use the base handler's default functions. Solution for the second problem was to remove the optimization to reuse the definition from the cache, instead always check the frm-file when holding the LOCK_open mutex (updated with a fix for a debug print crash and better comments as required by reviewer, and removed optimization to avoid reading the frm-file). mysql-test/r/partition_debug_sync.result: Bug#42438: Crash ha_partition::change_table_ptr New result file using DEBUG_SYNC for deterministic results. mysql-test/t/partition_debug_sync.test: Bug#42438: Crash ha_partition::change_table_ptr New test file using DEBUG_SYNC for deterministic results. sql/ha_partition.cc: Bug#42438: Crash ha_partition::change_table_ptr allow some handler calls, used by error handling, even when no partitions are setup. Fallback to default handling if possible. sql/sql_base.cc: Bug#42438: Crash ha_partition::change_table_ptr Added DEBUG_SYNC point for deterministic test cases. sql/sql_table.cc: Bug#42438: Crash ha_partition::change_table_ptr Always use the table type written in the .frm-file (i.e. the current table type) when deleting a table. Moved the check for log-table to not depend of the cache. Added DEBUG_SYNC points for deterministic test cases. --- sql/ha_partition.cc | 33 +++++++++++++++++++++++----- sql/sql_base.cc | 1 + sql/sql_table.cc | 63 +++++++++++++++++++++++++++-------------------------- 3 files changed, 60 insertions(+), 37 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 451631ff373..099b663f5c2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1719,13 +1719,23 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info) void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) { - handler **file_array= m_file; + handler **file_array; table= table_arg; table_share= share; - do + /* + m_file can be NULL when using an old cached table in DROP TABLE, when the + table just has REMOVED PARTITIONING, see Bug#42438 + */ + if (m_file) { - (*file_array)->change_table_ptr(table_arg, share); - } while (*(++file_array)); + file_array= m_file; + DBUG_ASSERT(*file_array); + do + { + (*file_array)->change_table_ptr(table_arg, share); + } while (*(++file_array)); + } + if (m_added_file && m_added_file[0]) { /* if in middle of a drop/rename etc */ @@ -5986,7 +5996,13 @@ void ha_partition::print_error(int error, myf errflag) if (error == HA_ERR_NO_PARTITION_FOUND) m_part_info->print_no_partition_found(table); else - m_file[m_last_part]->print_error(error, errflag); + { + /* In case m_file has not been initialized, like in bug#42438 */ + if (m_file) + m_file[m_last_part]->print_error(error, errflag); + else + handler::print_error(error, errflag); + } DBUG_VOID_RETURN; } @@ -5996,7 +6012,12 @@ bool ha_partition::get_error_message(int error, String *buf) DBUG_ENTER("ha_partition::get_error_message"); /* Should probably look for my own errors first */ - DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf)); + + /* In case m_file has not been initialized, like in bug#42438 */ + if (m_file) + DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf)); + DBUG_RETURN(handler::get_error_message(error, buf)); + } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cf8a0b32764..b13a067bfd7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2165,6 +2165,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) proc_info=thd->proc_info; thd_proc_info(thd, "Waiting for table"); DBUG_ENTER("wait_for_condition"); + DEBUG_SYNC(thd, "waiting_for_table"); if (!thd->killed) (void) pthread_cond_wait(cond, mutex); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 869ae42c98c..5097c0b4945 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -22,6 +22,9 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_show.h" +#if defined(ENABLED_DEBUG_SYNC) +#include "debug_sync.h" +#endif #ifdef __WIN__ #include @@ -1870,30 +1873,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, pthread_mutex_lock(&LOCK_open); - /* - If we have the table in the definition cache, we don't have to check the - .frm file to find if the table is a normal table (not view) and what - engine to use. - */ - - for (table= tables; table; table= table->next_local) - { - TABLE_SHARE *share; - table->db_type= NULL; - if ((share= get_cached_table_share(table->db, table->table_name))) - table->db_type= share->db_type(); - - /* Disable drop of enabled log tables */ - if (share && (share->table_category == TABLE_CATEGORY_PERFORMANCE) && - check_if_log_table(table->db_length, table->db, - table->table_name_length, table->table_name, 1)) - { - my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(1); - } - } - if (!drop_temporary && lock_table_names_exclusively(thd, tables)) { pthread_mutex_unlock(&LOCK_open); @@ -1904,7 +1883,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { char *db=table->db; handlerton *table_type; - enum legacy_db_type frm_db_type; + enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN; DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx", table->db, table->table_name, (long) table->table, @@ -1945,6 +1924,15 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error= 0; } + /* Disable drop of enabled log tables */ + if (check_if_log_table(table->db_length, table->db, + table->table_name_length, table->table_name, 1)) + { + my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); + pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(1); + } + /* If row-based replication is used and the table is not a temporary table, we add the table name to the drop statement @@ -1969,7 +1957,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, built_query.append("`,"); } - table_type= table->db_type; if (!drop_temporary) { TABLE *locked_table; @@ -1996,9 +1983,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->internal_tmp_table ? FN_IS_TMP : 0); } + DEBUG_SYNC(thd, "rm_table_part2_before_delete_table"); if (drop_temporary || - ((table_type == NULL && - access(path, F_OK) && + ((access(path, F_OK) && ha_create_table_from_engine(thd, db, alias)) || (!drop_view && mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) @@ -2014,15 +2001,25 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, else { char *end; - if (table_type == NULL) + /* + Cannot use the db_type from the table, since that might have changed + while waiting for the exclusive name lock. We are under LOCK_open, + so reading from the frm-file is safe. + */ + if (frm_db_type == DB_TYPE_UNKNOWN) { - mysql_frm_type(thd, path, &frm_db_type); - table_type= ha_resolve_by_legacy_type(thd, frm_db_type); + mysql_frm_type(thd, path, &frm_db_type); + DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path)); } + table_type= ha_resolve_by_legacy_type(thd, frm_db_type); // Remove extension for delete *(end= path + path_length - reg_ext_length)= '\0'; + DBUG_PRINT("info", ("deleting table of type %d", + (table_type ? table_type->db_type : 0))); error= ha_delete_table(thd, table_type, path, db, table->table_name, !dont_log_query); + + /* No error if non existent table and 'IF EXIST' clause or view */ if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && (if_exists || table_type == NULL)) { @@ -2062,6 +2059,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, on the table name. */ pthread_mutex_unlock(&LOCK_open); + DEBUG_SYNC(thd, "rm_table_part2_before_binlog"); thd->thread_specific_used|= tmp_table_deleted; error= 0; if (wrong_tables.length()) @@ -7097,6 +7095,7 @@ view_err: else create_info->data_file_name=create_info->index_file_name=0; + DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock"); /* Create a table with a temporary name. With create_info->frm_only == 1 this creates a .frm file only. @@ -7296,6 +7295,7 @@ view_err: intern_close_table(new_table); my_free(new_table,MYF(0)); } + DEBUG_SYNC(thd, "alter_table_before_rename_result_table"); VOID(pthread_mutex_lock(&LOCK_open)); if (error) { @@ -7438,6 +7438,7 @@ view_err: thd_proc_info(thd, "end"); DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); + DEBUG_SYNC(thd, "alter_table_before_main_binlog"); ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, thd->query(), thd->query_length(), -- cgit v1.2.1 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/opt_range.cc | 15 ++++--------- sql/opt_sum.cc | 17 +++----------- sql/sql_select.cc | 66 +++++++++++++------------------------------------------ sql/sql_update.cc | 9 +------- sql/table.cc | 5 ++--- sql/table.h | 14 ++++++++++++ 6 files changed, 39 insertions(+), 87 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 94204962345..34757a44c2f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1171,11 +1171,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() if (file) { range_end(); - if (head->key_read) - { - head->key_read= 0; - file->extra(HA_EXTRA_NO_KEYREAD); - } + head->set_keyread(FALSE); if (free_file) { DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, @@ -1377,10 +1373,7 @@ end: head->file= file; /* We don't have to set 'head->keyread' here as the 'file' is unique */ if (!head->no_keyread) - { - head->key_read= 1; head->mark_columns_used_by_index(index); - } head->prepare_for_position(); head->file= org_file; bitmap_copy(&column_bitmap, head->read_set); @@ -8165,7 +8158,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); /* We're going to just read rowids. */ - file->extra(HA_EXTRA_KEYREAD); + head->set_keyread(TRUE); head->prepare_for_position(); cur_quick_it.rewind(); @@ -8241,7 +8234,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() delete unique; doing_pk_scan= FALSE; /* index_merge currently doesn't support "using index" at all */ - file->extra(HA_EXTRA_NO_KEYREAD); + head->set_keyread(FALSE); init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); DBUG_RETURN(result); } @@ -10628,7 +10621,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) int result; DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); - file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ + head->set_keyread(TRUE); /* We need only the key attributes */ if ((result= file->ha_index_init(index,1))) DBUG_RETURN(result); if (quick_prefix_select && quick_prefix_select->reset()) diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index e009cf1ca9f..70d6d0a5b17 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -326,11 +326,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) if (!error && reckey_in_range(0, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; - if (table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_end(); if (error) { @@ -413,11 +409,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) if (!error && reckey_in_range(1, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_end(); if (error) { @@ -876,10 +868,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, converted (for example to upper case) */ if (field->part_of_key.is_set(idx)) - { - table->key_read= 1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); return 1; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d5ce32902c4..ab8b65b5cc7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6594,10 +6594,7 @@ make_join_readinfo(JOIN *join, ulonglong options) case JT_CONST: // Only happens with left join if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); break; case JT_ALL: /* @@ -6658,10 +6655,7 @@ make_join_readinfo(JOIN *join, ulonglong options) if (tab->select && tab->select->quick && tab->select->quick->index != MAX_KEY && //not index_merge table->covering_keys.is_set(tab->select->quick->index)) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree @@ -6745,11 +6739,7 @@ void JOIN_TAB::cleanup() limit= 0; if (table) { - if (table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_or_rnd_end(); /* We need to reset this for next select @@ -11595,16 +11585,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) !table->no_keyread && (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); + table->set_keyread(TRUE); tab->index= tab->ref.key; } error=join_read_const(tab); - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); if (error) { tab->info="unique row not found"; @@ -11959,12 +11944,8 @@ join_read_first(JOIN_TAB *tab) { int error; TABLE *table=tab->table; - if (!table->key_read && table->covering_keys.is_set(tab->index) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + if (table->covering_keys.is_set(tab->index) && !table->no_keyread) + table->set_keyread(TRUE); tab->table->status=0; tab->read_record.read_record=join_read_next; tab->read_record.table=table; @@ -11998,12 +11979,8 @@ join_read_last(JOIN_TAB *tab) { TABLE *table=tab->table; int error; - if (!table->key_read && table->covering_keys.is_set(tab->index) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + if (table->covering_keys.is_set(tab->index) && !table->no_keyread) + table->set_keyread(TRUE); tab->table->status=0; tab->read_record.read_record=join_read_prev; tab->read_record.table=table; @@ -13413,11 +13390,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, If ref_key used index tree reading only ('Using index' in EXPLAIN), and best_key doesn't, then revert the decision. */ - if (!table->covering_keys.is_set(best_key) && table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + if (!table->covering_keys.is_set(best_key)) + table->set_keyread(FALSE); if (!quick_created) { tab->index= best_key; @@ -13430,10 +13404,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, select->quick= 0; } if (table->covering_keys.is_set(best_key)) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); table->file->ha_index_or_rnd_end(); if (join->select_options & SELECT_DESCRIBE) { @@ -13607,11 +13578,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, We can only use 'Only index' if quick key is same as ref_key and in index_merge 'Only index' cannot be used */ - if (table->key_read && ((uint) tab->ref.key != select->quick->index)) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + if (((uint) tab->ref.key != select->quick->index)) + table->set_keyread(FALSE); } else { @@ -13667,11 +13635,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tab->type=JT_ALL; // Read with normal read_record tab->read_first_record= join_init_read_record; tab->join->examined_rows+=examined_rows; - if (table->key_read) // Restore if we used indexes - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); // Restore if we used indexes DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); err: DBUG_RETURN(-1); 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); } diff --git a/sql/table.cc b/sql/table.cc index c06ecf99926..9561e5fcc4b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4374,7 +4374,7 @@ void st_table::mark_columns_used_by_index(uint index) MY_BITMAP *bitmap= &tmp_set; DBUG_ENTER("st_table::mark_columns_used_by_index"); - (void) file->extra(HA_EXTRA_KEYREAD); + set_keyread(TRUE); bitmap_clear_all(bitmap); mark_columns_used_by_index_no_reset(index, bitmap); column_bitmaps_set(bitmap, bitmap); @@ -4397,8 +4397,7 @@ void st_table::restore_column_maps_after_mark_index() { DBUG_ENTER("st_table::restore_column_maps_after_mark_index"); - key_read= 0; - (void) file->extra(HA_EXTRA_NO_KEYREAD); + set_keyread(FALSE); default_column_bitmaps(); file->column_bitmaps_signal(); DBUG_VOID_RETURN; diff --git a/sql/table.h b/sql/table.h index eae261cc97d..e797ef2b2de 100644 --- a/sql/table.h +++ b/sql/table.h @@ -902,6 +902,20 @@ struct st_table { inline bool needs_reopen_or_name_lock() { return s->version != refresh_version; } bool is_children_attached(void); + inline void set_keyread(bool flag) + { + DBUG_ASSERT(file); + if (flag && !key_read) + { + key_read= 1; + file->extra(HA_EXTRA_KEYREAD); + } + else if (!flag && key_read) + { + key_read= 0; + file->extra(HA_EXTRA_NO_KEYREAD); + } + } }; enum enum_schema_table_state -- cgit v1.2.1 From e0fb0d9d018e0bc1a2da9f62a929cf669efd8343 Mon Sep 17 00:00:00 2001 From: Magne Mahre Date: Tue, 9 Feb 2010 11:30:50 +0100 Subject: Bug#47974 'TYPE=storage_engine' is deprecated and will be removed in MySQL 6.0 CREATE TABLE... TYPE= returns the warning "The syntax 'TYPE=storage_engine' is deprecated and will be removed in MySQL 6.0. Please use 'ENGINE=storage_engine' instead" This syntax is deprecated already from version 5.4.4, so the message has been changed. In addition, the deprecation macro was changed to reflect the ServerPT decision not to include version number in the warning message. A number of test result files have been changed as a consequence of the change in the deprecation macro. --- sql/mysql_priv.h | 12 +++++++----- sql/share/errmsg.txt | 2 +- sql/sql_yacc.yy | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1b775e658f1..90b02f5337a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -118,13 +118,15 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define WARN_DEPRECATED(Thd,Ver,Old,New) \ do { \ DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \ - if (((uchar*)Thd) != NULL) \ + if (((uchar*)Thd) != NULL) \ push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \ - ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER), \ - (Old), (Ver), (New)); \ + ER_WARN_DEPRECATED_SYNTAX, \ + ER(ER_WARN_DEPRECATED_SYNTAX), \ + (Old), (New)); \ else \ - sql_print_warning("The syntax '%s' is deprecated and will be removed " \ - "in a future release. Please use %s instead.", (Old), (New)); \ + sql_print_warning("'%s' is deprecated and will be removed " \ + "in a future release. Please use '%s' instead.", \ + (Old), (New)); \ } while(0) extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 06ce848399b..bbae17c4327 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5027,7 +5027,7 @@ ER_UNKNOWN_STORAGE_ENGINE 42000 # When using this error code, use ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER) # for the message string. See, for example, code in mysql_priv.h. ER_WARN_DEPRECATED_SYNTAX - eng "'%s' is deprecated; use '%s' instead" + eng "'%s' is deprecated and will be removed in a future release. Please use %s instead" ger "'%s' ist veraltet. Bitte benutzen Sie '%s'" por "'%s' é desatualizado. Use '%s' em seu lugar" spa "'%s' está desaprobado, use '%s' en su lugar" diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8dc08f8425f..37150bf835d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4596,7 +4596,7 @@ create_table_option: | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; - WARN_DEPRECATED(yythd, "6.0", "TYPE=storage_engine", + WARN_DEPRECATED(yythd, "5.4.4", "TYPE=storage_engine", "'ENGINE=storage_engine'"); Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; } -- cgit v1.2.1 From f2aee2371ef3f9140fb4f812ca7dcdcf2f6720bb Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 10 Feb 2010 18:56:47 +0400 Subject: Bug#45195 valgrind warnings about uninitialized values in store_record_in_cache() The problem becomes apparent only if HAVE_purify is undefined. It related to the part of code placed in open_table_from_share() fuction where we initialize record buffer only if HAVE_purify is enabled. So in case of HAVE_purify=OFF record buffer is not initialized on open table stage. Next we read key, find NULL value and update appropriate null bit but do not update record buffer. After that the record is stored in the join cache(store_record_in_cache). For CHAR fields we strip trailing spaces and in our case this procedure uses uninitialized record buffer. The fix is to skip stripping space procedure in case of null values for CHAR fields(partially based on 6.0 JOIN_CACHE implementation). mysql-test/r/join.result: test case mysql-test/t/join.test: test case sql/field.cc: code updated according to new CACHE_FIELD struct sql/sql_select.cc: code updated according to new CACHE_FIELD struct sql/sql_select.h: CACHE_FIELD struct: added new fields: Field *field, uint type; removed fields: Field_blob *blob_field, bool strip; --- sql/field.cc | 11 +++++------ sql/sql_select.cc | 51 +++++++++++++++++++++++++++++---------------------- sql/sql_select.h | 8 ++++++-- 3 files changed, 40 insertions(+), 30 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index d8db3fdbae4..15ee9c4a86c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1705,11 +1705,10 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) uint store_length; copy->str=ptr; copy->length=pack_length(); - copy->blob_field=0; + copy->field= this; if (flags & BLOB_FLAG) { - copy->blob_field=(Field_blob*) this; - copy->strip=0; + copy->type= CACHE_BLOB; copy->length-= table->s->blob_ptr_size; return copy->length; } @@ -1717,15 +1716,15 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) (type() == MYSQL_TYPE_STRING && copy->length >= 4 && copy->length < 256)) { - copy->strip=1; /* Remove end space */ + copy->type= CACHE_STRIPPED; store_length= 2; } else { - copy->strip=0; + copy->type= 0; store_length= 0; } - return copy->length+ store_length; + return copy->length + store_length; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1efaf67b9b..a3ce50fe4ee 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14149,7 +14149,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { used_fields--; length+=field->fill_cache_field(copy); - if (copy->blob_field) + if (copy->type == CACHE_BLOB) (*blob_ptr++)=copy; if (field->real_maybe_null()) null_fields++; @@ -14164,8 +14164,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { /* must copy null bits */ copy->str= tables[i].table->null_flags; copy->length= tables[i].table->s->null_bytes; - copy->strip=0; - copy->blob_field=0; + copy->type=0; + copy->field=0; length+=copy->length; copy++; cache->fields++; @@ -14175,8 +14175,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { copy->str= (uchar*) &tables[i].table->null_row; copy->length=sizeof(tables[i].table->null_row); - copy->strip=0; - copy->blob_field=0; + copy->type=0; + copy->field=0; length+=copy->length; copy++; cache->fields++; @@ -14201,9 +14201,10 @@ used_blob_length(CACHE_FIELD **ptr) uint length,blob_length; for (length=0 ; *ptr ; ptr++) { - (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length(); + Field_blob *field_blob= (Field_blob *) (*ptr)->field; + (*ptr)->blob_length=blob_length= field_blob->get_length(); length+=blob_length; - (*ptr)->blob_field->get_ptr(&(*ptr)->str); + field_blob->get_ptr(&(*ptr)->str); } return length; } @@ -14232,30 +14233,35 @@ store_record_in_cache(JOIN_CACHE *cache) cache->records++; for (copy=cache->field ; copy < end_field; copy++) { - if (copy->blob_field) + if (copy->type == CACHE_BLOB) { + Field_blob *blob_field= (Field_blob *) copy->field; if (last_record) { - copy->blob_field->get_image(pos, copy->length+sizeof(char*), - copy->blob_field->charset()); + blob_field->get_image(pos, copy->length+sizeof(char*), + blob_field->charset()); pos+=copy->length+sizeof(char*); } else { - copy->blob_field->get_image(pos, copy->length, // blob length - copy->blob_field->charset()); + blob_field->get_image(pos, copy->length, // blob length + blob_field->charset()); memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data pos+=copy->length+copy->blob_length; } } else { - if (copy->strip) + if (copy->type == CACHE_STRIPPED) { uchar *str,*end; - for (str=copy->str,end= str+copy->length; - end > str && end[-1] == ' ' ; - end--) ; + Field *field= copy->field; + if (field && field->maybe_null() && field->is_null()) + end= str= copy->str; + else + for (str=copy->str,end= str+copy->length; + end > str && end[-1] == ' ' ; + end--) ; length=(uint) (end-str); memcpy(pos+2, str, length); int2store(pos, length); @@ -14304,23 +14310,24 @@ read_cached_record(JOIN_TAB *tab) copy < end_field; copy++) { - if (copy->blob_field) + if (copy->type == CACHE_BLOB) { + Field_blob *blob_field= (Field_blob *) copy->field; if (last_record) { - copy->blob_field->set_image(pos, copy->length+sizeof(char*), - copy->blob_field->charset()); + blob_field->set_image(pos, copy->length+sizeof(char*), + blob_field->charset()); pos+=copy->length+sizeof(char*); } else { - copy->blob_field->set_ptr(pos, pos+copy->length); - pos+=copy->length+copy->blob_field->get_length(); + blob_field->set_ptr(pos, pos+copy->length); + pos+=copy->length + blob_field->get_length(); } } else { - if (copy->strip) + if (copy->type == CACHE_STRIPPED) { length= uint2korr(pos); memcpy(copy->str, pos+2, length); diff --git a/sql/sql_select.h b/sql/sql_select.h index bfff0a0ffa2..ef43f9b049c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -95,6 +95,10 @@ typedef struct st_table_ref } TABLE_REF; + +#define CACHE_BLOB 1 /* blob field */ +#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */ + /** CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer table @@ -103,8 +107,8 @@ typedef struct st_table_ref typedef struct st_cache_field { uchar *str; uint length, blob_length; - Field_blob *blob_field; - bool strip; + Field *field; + uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */ } CACHE_FIELD; -- cgit v1.2.1 From 07c30f911e86b34f004f15b26771a4b20a513b15 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Sat, 13 Feb 2010 08:35:14 -0200 Subject: Bug#50624: crash in check_table_access during call procedure This bug is just one facet of stored routines not being able to detect changes in meta-data (WL#4179). This particular problem can be triggered within a single session due to the improper management of the pre-locking list if the view is expanded after the pre-locking list is calculated. Since the overall solution for the meta-data detection issue is planned for a later release, for now a workaround is used to fix this particular aspect that only involves a single session. The workaround is to flush the thread-local stored routine cache every time a view is created or modified, causing locally cached routines to be re-evaluated upon invocation. mysql-test/r/sp-bugs.result: Add test case result for Bug#50624. mysql-test/t/sp-bugs.test: Add test case for Bug#50624. sql/sp_cache.cc: Update function description. sql/sql_view.cc: Invalidate the SP cache if a view is being created or modified. --- sql/sp_cache.cc | 5 +++-- sql/sql_view.cc | 13 +++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index b8209a373a2..12d21aee22c 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -175,8 +175,9 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) sp_cache_invalidate() NOTE - This is called when a VIEW definition is modifed. We can't destroy sp_head - objects here as one may modify VIEW definitions from prelocking-free SPs. + This is called when a VIEW definition is created or modified (and in some + other contexts). We can't destroy sp_head objects here as one may modify + VIEW definitions from prelocking-free SPs. */ void sp_cache_invalidate() diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c6d412112c2..c66990c54c6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -400,17 +400,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_ASSERT(!lex->proc_list.first && !lex->result && !lex->param_list.elements); - if (mode != VIEW_CREATE_NEW) + if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view)) { - if (mode == VIEW_ALTER && - fill_defined_view_parts(thd, view)) - { - res= TRUE; - goto err; - } - sp_cache_invalidate(); + res= TRUE; + goto err; } + sp_cache_invalidate(); + if (!lex->definer) { /* -- cgit v1.2.1 From 32058ba9c6365f1190e36c290ced9779f79cbdfe Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 15 Feb 2010 10:54:27 +0200 Subject: Addendum 2 for bug #46175: NULL read_view and consistent read assertion Fixed a compilation warning. --- sql/sql_select.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.h b/sql/sql_select.h index 8d3520bf9c8..b39827ef61b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -769,7 +769,7 @@ protected: if ((res= item->save_in_field(to_field, 1))) { if (!err) - err= res; + err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */ } /* Item::save_in_field() may call Item::val_xxx(). And if this is a subquery @@ -779,7 +779,7 @@ protected: err= 1; /* STORE_KEY_FATAL */ } null_key= to_field->is_null() || item->null_value; - return ((err < 0 || err > 2) ? STORE_KEY_FATAL : (store_key_result) err); + return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); } }; -- cgit v1.2.1 From 82e2d858a441295e3c2d2714df43f8118ff7048f Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 16 Feb 2010 13:13:49 +0400 Subject: Bug#50591 bit(31) causes Duplicate entry '1-NULL' for key 'group_key' The problem is that during temporary table creation uneven bits are not taken into account for hidden fields. It leads to incorrect calculation&allocation of null bytes size for table record. And if grouped value is null we set wrong bit for this value(see end_update()). Fixed by adding separate calculation of uneven bit for hidden fields. mysql-test/r/type_bit.result: test case mysql-test/t/type_bit.test: test case sql/sql_select.cc: added separate calculation of uneven bit for hidden fields --- sql/sql_select.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a3ce50fe4ee..52f9aae7a0c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9822,7 +9822,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, KEY_PART_INFO *key_part_info; Item **copy_func; MI_COLUMNDEF *recinfo; - uint total_uneven_bit_length= 0; + /* + total_uneven_bit_length is uneven bit length for visible fields + hidden_uneven_bit_length is uneven bit length for hidden fields + */ + uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0; bool force_copy_fields= param->force_copy_fields; /* Treat sum functions as normal ones when loose index scan is used. */ save_sum_fields|= param->precomputed_group_by; @@ -10099,6 +10103,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, */ param->hidden_field_count= fieldnr; null_count= 0; + /* + On last hidden field we store uneven bit length in + hidden_uneven_bit_length and proceed calculation of + uneven bits for visible fields into + total_uneven_bit_length variable. + */ + hidden_uneven_bit_length= total_uneven_bit_length; + total_uneven_bit_length= 0; } } DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field)); @@ -10144,7 +10156,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, else null_count++; } - hidden_null_pack_length=(hidden_null_count+7)/8; + hidden_null_pack_length= (hidden_null_count + 7 + + hidden_uneven_bit_length) / 8; null_pack_length= (hidden_null_pack_length + (null_count + total_uneven_bit_length + 7) / 8); reclength+=null_pack_length; -- cgit v1.2.1 From 6cb7abe667533084e09f3df6951591332138ae0e Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 16 Feb 2010 11:42:22 +0100 Subject: post push fix for bug#42438, did not compile on non debug, due to ifdef of include file sql/sql_table.cc: removed if defined since DEBUG_SYNC macro is defined in that include file. --- sql/sql_table.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b201fbc3d3e..871b2f2d552 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -22,9 +22,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_show.h" -#if defined(ENABLED_DEBUG_SYNC) #include "debug_sync.h" -#endif #ifdef __WIN__ #include -- cgit v1.2.1 From 4b260b668d66cfd6f7e8c2612461c66d2914219d Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 17 Feb 2010 16:13:42 +0400 Subject: Bug#33717 INSERT...(default) fails for enum. Crashes CSV tables, loads spaces for MyISAM Table corruption happens during table reading in ha_tina::find_current_row() func. Field::store() method returns error(true) if stored value is 0. The fix: added special case for enum type which correctly processes 0 value. Additional fix: INSERT...(default) and INSERT...() have the same behaviour now for enum type. mysql-test/r/csv.result: test result mysql-test/r/default.result: result fix mysql-test/t/csv.test: test case sql/item.cc: Changes: do not print warning for 'enum' type if there is no default value. set default value. storage/csv/ha_tina.cc: Table corruption happens during table reading in ha_tina::find_current_row() func. Field::store() method returns error(true) if stored value is 0. The fix: added special case for enum type which correctly processes 0 value. --- sql/item.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index df266434f72..f8cca3a0667 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6488,7 +6488,8 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (!arg) { - if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) + if (field_arg->flags & NO_DEFAULT_VALUE_FLAG && + field_arg->real_type() != MYSQL_TYPE_ENUM) { if (field_arg->reset()) { -- cgit v1.2.1