From f48b42e77657dd2e27380201631fd0f137863b85 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Wed, 8 Oct 2008 02:34:00 +0500 Subject: [PATCH 01/10] Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' Concurrent execution of 1) multitable update with a NATURAL/USING join and 2) a such query as "FLUSH TABLES WITH READ LOCK" or "ALTER TABLE" of updating table led to a server crash. The mysql_multi_update_prepare() function call is optimized to lock updating tables only, so it postpones locking to the last, and if locking fails, it does cleanup of modified syntax structures and repeats a query analysis. However, that cleanup procedure was incomplete for NATURAL/USING join syntax data: 1) some Field_item items pointed into freed table structures, and 2) the TABLE_LIST::join_columns fields was not reset. Major change: short-living Field *Natural_join_column::table_field has been replaced with long-living Item*. mysql-test/r/lock_multi.result: Added test case for bug #38691. mysql-test/t/lock_multi.test: Added test case for bug #38691. sql/item.cc: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' The Item_field constructor has been modified to allocate and copy original database/table/field names always (not during PS preparation/1st execution only), because an initialization of Item_field items with a pointer to short-living Field structures is a common practice. sql/sql_base.cc: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' 1) Type adjustment for Natural_join_column::table_field (Field to Item_field); 2) The setup_natural_join_row_types function has been updated to take into account new first_natural_join_processing flag to skip unnecessary reinitialization of Natural_join_column::join_columns during table reopening after lock_tables() failure (like the 'first_execution' flag for PS). sql/sql_lex.cc: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' Initialization of the new st_select_lex::first_natural_join_processing flag has been added. sql/sql_lex.h: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' The st_select_lex::first_natural_join_processing flag has been added to skip unnecessary rebuilding of NATURAL/USING JOIN structures during table reopening after lock_tables failure. sql/sql_update.cc: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' Extra cleanup calls have been added to reset Natural_join_column::table_field items. sql/table.cc: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' Type adjustment for Natural_join_column::table_field (Field to Item_field). sql/table.h: Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while ``FLUSH TABLES WITH READ LOCK'' Type of the Natural_join_column::table_field field has been changed from Field that points into short-living TABLE memory to long-living Item_field that can be linked to (fixed) reopened table. --- mysql-test/r/lock_multi.result | 16 +++++ mysql-test/t/lock_multi.test | 119 +++++++++++++++++++++++++++++++++ sql/item.cc | 10 +-- sql/sql_base.cc | 34 ++++++++-- sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_update.cc | 13 +++- sql/table.cc | 24 ++++--- sql/table.h | 7 +- 9 files changed, 201 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 079f92ca420..d46aea24ac3 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -99,3 +99,19 @@ kill query ERROR 70100: Query execution was interrupted unlock tables; drop table t1; +CREATE TABLE t1 ( +a int(11) unsigned default NULL, +b varchar(255) default NULL, +UNIQUE KEY a (a), +KEY b (b) +); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); +CREATE TABLE t2 SELECT * FROM t1; +CREATE TABLE t3 SELECT * FROM t1; +# test altering of columns that multiupdate doesn't use +# normal mode +# PS mode +# test altering of columns that multiupdate uses +# normal mode +# PS mode +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 649c1a4efbd..fe22efeb8c2 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -281,4 +281,123 @@ unlock tables; connection default; drop table t1; +# +# Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while +# ``FLUSH TABLES WITH READ LOCK'' +# + +--connection default +CREATE TABLE t1 ( + a int(11) unsigned default NULL, + b varchar(255) default NULL, + UNIQUE KEY a (a), + KEY b (b) +); + +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); +CREATE TABLE t2 SELECT * FROM t1; +CREATE TABLE t3 SELECT * FROM t1; + +--echo # test altering of columns that multiupdate doesn't use + +--echo # normal mode + +--disable_query_log +let $i = 100; +while ($i) { +--dec $i + +--connection writer + send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) + SET a = NULL WHERE t1.b <> t2.b; + +--connection locker + ALTER TABLE t2 ADD COLUMN (c INT); + ALTER TABLE t2 DROP COLUMN c; + +--connection writer +--reap +} + +--echo # PS mode + +--connection writer +PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) + SET a = NULL WHERE t1.b <> t2.b'; + +let $i = 100; +while ($i) { +--dec $i + +--connection writer +--send EXECUTE stmt + +--connection locker + ALTER TABLE t2 ADD COLUMN (c INT); + ALTER TABLE t2 DROP COLUMN c; + +--connection writer +--reap +} +--enable_query_log + + +--echo # test altering of columns that multiupdate uses + +--echo # normal mode + +--connection default + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; + UPDATE t2 SET a=b; + +--connection writer +--send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b + +--connection locker +--error 0,1091 + ALTER TABLE t2 DROP COLUMN a; + +--connection writer +--error 0,1054 +--reap +} +--enable_query_log + +--echo # PS mode + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; + UPDATE t2 SET a=b; + +--connection writer + PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b'; +--send EXECUTE stmt + +--connection locker +--error 0,1091 + ALTER TABLE t2 DROP COLUMN a; + +--connection writer +--error 0,1054 +--reap + +} +--enable_query_log +--connection default +DROP TABLE t1, t2, t3; + # End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index f247f49293d..e49de88cea7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1758,14 +1758,16 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, We need to copy db_name, table_name and field_name because they must be allocated in the statement memory, not in table memory (the table structure can go away and pop up again between subsequent executions - of a prepared statement). + of a prepared statement or after the close_tables_for_reopen() call + in mysql_multi_update_prepare()). */ - if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { if (db_name) orig_db_name= thd->strdup(db_name); - orig_table_name= thd->strdup(table_name); - orig_field_name= thd->strdup(field_name); + if (table_name) + orig_table_name= thd->strdup(table_name); + if (field_name) + orig_field_name= thd->strdup(field_name); /* We don't restore 'name' in cleanup because it's not changed during execution. Still we need it to point to persistent diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 533b0070fee..d969c837891 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3617,8 +3617,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { /* This is a base table. */ DBUG_ASSERT(nj_col->view_field == NULL); - DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->table); - found_field= nj_col->table_field; + /* + This fix_fields is not necessary (initially this item is fixed by + the Item_field constructor; after reopen_tables the Item_func_eq + calls fix_fields on that item), it's just a check during table + reopening for columns that was dropped by the concurrent connection. + */ + if (!nj_col->table_field->fixed && + nj_col->table_field->fix_fields(thd, (Item **)&nj_col->table_field)) + { + DBUG_PRINT("info", ("column '%s' was dropped by the concurrent connection", + nj_col->table_field->name)); + DBUG_RETURN(NULL); + } + DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->field->table); + found_field= nj_col->table_field->field; update_field_dependencies(thd, found_field, nj_col->table_ref->table); } @@ -4450,7 +4463,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, const char *field_name_1; /* true if field_name_1 is a member of using_fields */ bool is_using_column_1; - if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) + if (!(nj_col_1= it_1.get_or_create_column_ref(thd, leaf_1))) goto err; field_name_1= nj_col_1->name(); is_using_column_1= using_fields && @@ -4471,7 +4484,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { Natural_join_column *cur_nj_col_2; const char *cur_field_name_2; - if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) + if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", @@ -4957,15 +4970,24 @@ static bool setup_natural_join_row_types(THD *thd, TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; + bool save_first_natural_join_processing= + context->select_lex->first_natural_join_processing; + + context->select_lex->first_natural_join_processing= FALSE; /* Note that tables in the list are in reversed order */ for (left_neighbor= table_ref_it++; left_neighbor ; ) { table_ref= left_neighbor; left_neighbor= table_ref_it++; - /* For stored procedures do not redo work if already done. */ - if (context->select_lex->first_execution) + /* + Do not redo work if already done: + 1) for stored procedures, + 2) for multitable update after lock failure and table reopening. + */ + if (save_first_natural_join_processing) { + context->select_lex->first_natural_join_processing= FALSE; if (store_top_level_join_columns(thd, table_ref, left_neighbor, right_neighbor)) return TRUE; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0cf7c11b447..ba9c0e93134 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1205,6 +1205,7 @@ void st_select_lex::init_query() subquery_in_having= explicit_limit= 0; is_item_list_lookup= 0; first_execution= 1; + first_natural_join_processing= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 563172594d2..9f020f4adc5 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -586,6 +586,7 @@ public: case of an error during prepare the PS is not created. */ bool first_execution; + bool first_natural_join_processing; bool first_cond_optimization; /* do not wrap view fields with Item_ref */ bool no_wrap_view_item; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7d47659fbcc..109786df7de 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -852,11 +852,14 @@ reopen_tables: } /* now lock and fill tables */ - if (lock_tables(thd, table_list, table_count, &need_reopen)) + if (!thd->stmt_arena->is_stmt_prepare() && + lock_tables(thd, table_list, table_count, &need_reopen)) { if (!need_reopen) DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("lock_tables failed, reopening")); + /* We have to reopen tables since some of them were altered or dropped during lock_tables() or something was done with their triggers. @@ -872,6 +875,14 @@ reopen_tables: for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); + /* + Also we need to cleanup Natural_join_column::table_field items. + To not to traverse a join tree we will cleanup whole + thd->free_list (in PS execution mode that list may not contain + items from 'fields' list, so the cleanup above is necessary to. + */ + cleanup_items(thd->free_list); + close_tables_for_reopen(thd, &table_list); goto reopen_tables; } diff --git a/sql/table.cc b/sql/table.cc index 7fe9aa774f3..3abd2c24c94 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2191,7 +2191,7 @@ TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find) } /* - cleunup items belonged to view fields translation table + cleanup items belonged to view fields translation table SYNOPSIS TABLE_LIST::cleanup_items() @@ -2637,10 +2637,10 @@ Natural_join_column::Natural_join_column(Field_translator *field_param, } -Natural_join_column::Natural_join_column(Field *field_param, +Natural_join_column::Natural_join_column(Item_field *field_param, TABLE_LIST *tab) { - DBUG_ASSERT(tab->table == field_param->table); + DBUG_ASSERT(tab->table == field_param->field->table); table_field= field_param; view_field= NULL; table_ref= tab; @@ -2668,7 +2668,7 @@ Item *Natural_join_column::create_item(THD *thd) return create_view_field(thd, table_ref, &view_field->item, view_field->name); } - return new Item_field(thd, &thd->lex->current_select->context, table_field); + return table_field; } @@ -2679,7 +2679,7 @@ Field *Natural_join_column::field() DBUG_ASSERT(table_field == NULL); return NULL; } - return table_field; + return table_field->field; } @@ -2811,7 +2811,7 @@ void Field_iterator_natural_join::next() cur_column_ref= column_ref_it++; DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field || cur_column_ref->table_ref->table == - cur_column_ref->table_field->table); + cur_column_ref->table_field->field->table); } @@ -2975,7 +2975,7 @@ GRANT_INFO *Field_iterator_table_ref::grant() */ Natural_join_column * -Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref) +Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_table_ref) { Natural_join_column *nj_col; bool is_created= TRUE; @@ -2988,7 +2988,11 @@ Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref) { /* The field belongs to a stored table. */ Field *tmp_field= table_field_it.field(); - nj_col= new Natural_join_column(tmp_field, table_ref); + Item_field *tmp_item= + new Item_field(thd, &thd->lex->current_select->context, tmp_field); + if (!tmp_item) + return NULL; + nj_col= new Natural_join_column(tmp_item, table_ref); field_count= table_ref->table->s->fields; } else if (field_it == &view_field_it) @@ -3012,7 +3016,7 @@ Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref) DBUG_ASSERT(nj_col); } DBUG_ASSERT(!nj_col->table_field || - nj_col->table_ref->table == nj_col->table_field->table); + nj_col->table_ref->table == nj_col->table_field->field->table); /* If the natural join column was just created add it to the list of @@ -3077,7 +3081,7 @@ Field_iterator_table_ref::get_natural_column_ref() nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col && (!nj_col->table_field || - nj_col->table_ref->table == nj_col->table_field->table)); + nj_col->table_ref->table == nj_col->table_field->field->table)); return nj_col; } diff --git a/sql/table.h b/sql/table.h index cff4be630e4..08326e2fbe0 100644 --- a/sql/table.h +++ b/sql/table.h @@ -18,6 +18,7 @@ class Item; /* Needed by ORDER */ class Item_subselect; +class Item_field; class GRANT_TABLE; class st_select_lex_unit; class st_select_lex; @@ -469,7 +470,7 @@ class Natural_join_column: public Sql_alloc { public: Field_translator *view_field; /* Column reference of merge view. */ - Field *table_field; /* Column reference of table or temp view. */ + Item_field *table_field; /* Column reference of table or temp view. */ TABLE_LIST *table_ref; /* Original base table/view reference. */ /* True if a common join column of two NATURAL/USING join operands. Notice @@ -481,7 +482,7 @@ public: bool is_common; public: Natural_join_column(Field_translator *field_param, TABLE_LIST *tab); - Natural_join_column(Field *field_param, TABLE_LIST *tab); + Natural_join_column(Item_field *field_param, TABLE_LIST *tab); const char *name(); Item *create_item(THD *thd); Field *field(); @@ -899,7 +900,7 @@ public: GRANT_INFO *grant(); Item *create_item(THD *thd) { return field_it->create_item(thd); } Field *field() { return field_it->field(); } - Natural_join_column *get_or_create_column_ref(TABLE_LIST *parent_table_ref); + Natural_join_column *get_or_create_column_ref(THD *thd, TABLE_LIST *parent_table_ref); Natural_join_column *get_natural_column_ref(); }; From 9e71cd43f05960f706c64fbbf754ca3773e457ec Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 8 Oct 2008 09:46:30 +0200 Subject: [PATCH 02/10] Bug#37453: Dropping/creating index on partitioned table with InnoDB Plugin locks table This is a pre fix update that does the change to the handler api. This is done since there are already changes in this version, so the real fix does not need to change the api. sql/handler.h: Bug#37453: Dropping/creating index on partitioned table with InnoDB Plugin locks table The check for which alter table flags a handler have is done through the handlerton, which will not work correctly for any partitioned table. It must be through the handler interface. To be able to fix this I have to add a virtual function to the handler class. --- sql/handler.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/handler.h b/sql/handler.h index b943e188962..4ac80014cde 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1732,6 +1732,12 @@ public: but we don't have a primary key */ virtual void use_hidden_primary_key(); + virtual uint alter_table_flags(uint flags) + { + if (ht->alter_table_flags) + return ht->alter_table_flags(flags); + return 0; + } protected: /* Service methods for use by storage engines. */ From dcd050c550e14cc0681a5f8a662c430c7ead785e Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 8 Oct 2008 11:15:00 +0200 Subject: [PATCH 03/10] Bug #34707: Row based replication: slave creates table within wrong database The failure was caused by executing a CREATE-SELECT statement that creates a table in another database than the current one. In row-based logging, the CREATE statement was written to the binary log without the database, hence creating the table in the wrong database, causing the following inserts to fail since the table didn't exist in the given database. Fixed the bug by adding a parameter to store_create_info() that will make the function print the database name before the table name and used that in the calls that write the CREATE statement to the binary log. The database name is only printed if it is different than the currently selected database. The output of SHOW CREATE TABLE has not changed and is still printed without the database name. mysql-test/suite/rpl/t/rpl_row_create_table.test: Added test to check that CREATE-SELECT into another database than the current one replicates. sql/sql_insert.cc: Adding parameter to calls to store_create_info(). sql/sql_show.cc: Adding parameter to calls to store_create_info(). Extending store_create_info() with parameter 'show_database' that will cause the database to be written before the table name. sql/sql_show.h: Adding parameter to call to store_create_info() to tell if the database should be shown or not. sql/sql_table.cc: Adding parameter to calls to store_create_info(). --- .../suite/rpl/r/rpl_row_create_table.result | 21 +++++++++++++++ .../suite/rpl/t/rpl_row_create_table.test | 17 ++++++++++++ sql/handler.cc | 2 ++ sql/log.cc | 4 +-- sql/sql_class.cc | 24 ++++++++++++++++- sql/sql_class.h | 19 +++++++++++++ sql/sql_insert.cc | 3 ++- sql/sql_parse.cc | 4 +++ sql/sql_show.cc | 27 ++++++++++++++++--- sql/sql_show.h | 2 +- sql/sql_table.cc | 5 ++-- 11 files changed, 118 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index c4cf8353bca..ad659c37b7f 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -430,4 +430,25 @@ a 1 2 DROP TABLE t1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE DATABASE mysqltest1; +CREATE TABLE mysqltest1.without_select (f1 BIGINT); +CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # CREATE DATABASE mysqltest1 +master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1 BIGINT) +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` ( + `f1` int(1) NOT NULL DEFAULT '0' +) +master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; COMMIT +DROP DATABASE mysqltest1; end of the tests diff --git a/mysql-test/suite/rpl/t/rpl_row_create_table.test b/mysql-test/suite/rpl/t/rpl_row_create_table.test index e5cdfa4341a..3fb5aa8e1f2 100644 --- a/mysql-test/suite/rpl/t/rpl_row_create_table.test +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test @@ -259,5 +259,22 @@ connection master; DROP TABLE t1; sync_slave_with_master; +# +# BUG#34707: Row based replication: slave creates table within wrong database +# + +source include/master-slave-reset.inc; + +connection master; +CREATE DATABASE mysqltest1; + +CREATE TABLE mysqltest1.without_select (f1 BIGINT); +CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1; +source include/show_binlog_events.inc; +sync_slave_with_master; + +connection master; +DROP DATABASE mysqltest1; +sync_slave_with_master; --echo end of the tests diff --git a/sql/handler.cc b/sql/handler.cc index 600991aeec8..435f3cd2150 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4338,6 +4338,8 @@ static int write_locked_table_maps(THD *thd) (long) thd, (long) thd->lock, (long) thd->locked_tables, (long) thd->extra_lock)); + DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps())); + if (thd->get_binlog_table_maps() == 0) { MYSQL_LOCK *locks[3]; diff --git a/sql/log.cc b/sql/log.cc index b5539525ea6..8ab2e892b27 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1377,6 +1377,8 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), FLAGSTR(thd->options, OPTION_BEGIN))); + thd->binlog_flush_pending_rows_event(TRUE); + /* NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of only transactional tables. If the transaction contain changes to @@ -1395,8 +1397,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, were, we would have to ensure that we're not ending a statement inside a stored function. */ - thd->binlog_flush_pending_rows_event(TRUE); - error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev); trx_data->reset(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c4a4312ad85..63dcc6404c6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3558,6 +3558,24 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end) } +static const char * +show_query_type(THD::enum_binlog_query_type qtype) +{ + switch (qtype) { + case THD::ROW_QUERY_TYPE: + return "ROW"; + case THD::STMT_QUERY_TYPE: + return "STMT"; + case THD::MYSQL_QUERY_TYPE: + return "MYSQL"; + } + + static char buf[64]; + sprintf(buf, "UNKNOWN#%d", qtype); + return buf; +} + + /* Member function that will log query, either row-based or statement-based depending on the value of the 'current_stmt_binlog_row_based' @@ -3586,7 +3604,8 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, THD::killed_state killed_status_arg) { DBUG_ENTER("THD::binlog_query"); - DBUG_PRINT("enter", ("qtype: %d query: '%s'", qtype, query_arg)); + DBUG_PRINT("enter", ("qtype: %s query: '%s'", + show_query_type(qtype), query_arg)); DBUG_ASSERT(query_arg && mysql_bin_log.is_open()); /* @@ -3625,6 +3644,9 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, switch (qtype) { case THD::ROW_QUERY_TYPE: + DBUG_PRINT("debug", + ("current_stmt_binlog_row_based: %d", + current_stmt_binlog_row_based)); if (current_stmt_binlog_row_based) DBUG_RETURN(0); /* Otherwise, we fall through */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 82c162f923f..26437d5db83 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -996,6 +996,21 @@ enum enum_thread_type SYSTEM_THREAD_EVENT_WORKER= 32 }; +inline char const * +show_system_thread(enum_thread_type thread) +{ +#define RETURN_NAME_AS_STRING(NAME) case (NAME): return #NAME + switch (thread) { + RETURN_NAME_AS_STRING(NON_SYSTEM_THREAD); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_DELAYED_INSERT); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_IO); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_SQL); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_NDBCLUSTER_BINLOG); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_SCHEDULER); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER); + } +#undef RETURN_NAME_AS_STRING +} /** This class represents the interface for internal error handlers. @@ -2092,6 +2107,10 @@ public: Don't reset binlog format for NDB binlog injector thread. */ + DBUG_PRINT("debug", + ("temporary_tables: %d, in_sub_stmt: %d, system_thread: %s", + (int) temporary_tables, in_sub_stmt, + show_system_thread(system_thread))); if ((temporary_tables == NULL) && (in_sub_stmt == 0) && (system_thread != SYSTEM_THREAD_NDBCLUSTER_BINLOG)) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 268e040288e..8762d3dc8fa 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3635,7 +3635,8 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) tmp_table_list.table = *tables; query.length(0); // Have to zero it since constructor doesn't - result= store_create_info(thd, &tmp_table_list, &query, create_info); + result= store_create_info(thd, &tmp_table_list, &query, create_info, + /* show_database */ TRUE); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ if (mysql_bin_log.is_open()) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 30fef9c7ee7..c1ad24a2d30 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5488,6 +5488,10 @@ void mysql_reset_thd_for_next_command(THD *thd) */ thd->reset_current_stmt_binlog_row_based(); + DBUG_PRINT("debug", + ("current_stmt_binlog_row_based: %d", + thd->current_stmt_binlog_row_based)); + DBUG_VOID_RETURN; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cc465db7720..a57d966f173 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -619,7 +619,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if ((table_list->view ? view_store_create_info(thd, table_list, &buffer) : - store_create_info(thd, table_list, &buffer, NULL))) + store_create_info(thd, table_list, &buffer, NULL, + FALSE /* show_database */))) DBUG_RETURN(TRUE); List field_list; @@ -810,7 +811,8 @@ mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd) DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str)); protocol->prepare_for_resend(); - if (store_create_info(thd, table_list, packet, NULL)) + if (store_create_info(thd, table_list, packet, NULL, + FALSE /* show_database */)) DBUG_RETURN(-1); if (fd < 0) @@ -1062,7 +1064,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, */ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, - HA_CREATE_INFO *create_info_arg) + HA_CREATE_INFO *create_info_arg, bool show_database) { List field_list; char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH]; @@ -1110,6 +1112,25 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, alias= share->table_name.str; } } + + /* + Print the database before the table name if told to do that. The + database name is only printed in the event that it is different + from the current database. The main reason for doing this is to + avoid having to update gazillions of tests and result files, but + it also saves a few bytes of the binary log. + */ + if (show_database) + { + const LEX_STRING *const db= + table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db; + if (strcmp(db->str, thd->db) != 0) + { + append_identifier(thd, packet, db->str, db->length); + packet->append(STRING_WITH_LEN(".")); + } + } + append_identifier(thd, packet, alias, strlen(alias)); packet->append(STRING_WITH_LEN(" (\n")); /* diff --git a/sql/sql_show.h b/sql/sql_show.h index d63217584b2..3baaef00a7d 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -33,7 +33,7 @@ find_files_result find_files(THD *thd, List *files, const char *db, const char *path, const char *wild, bool dir); int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, - HA_CREATE_INFO *create_info_arg); + HA_CREATE_INFO *create_info_arg, bool show_database); int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e317cdab952..c866fdfc173 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5010,8 +5010,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, } VOID(pthread_mutex_unlock(&LOCK_open)); - IF_DBUG(int result=) store_create_info(thd, table, &query, - create_info); + IF_DBUG(int result=) + store_create_info(thd, table, &query, + create_info, FALSE /* show_database */); DBUG_ASSERT(result == 0); // store_create_info() always return 0 write_bin_log(thd, TRUE, query.ptr(), query.length()); From a720bdf0ae9c5f3312109da4bdfdbf08f0f0eb4c Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Wed, 8 Oct 2008 18:52:57 +0500 Subject: [PATCH 04/10] Fix for bug#39585: innodb and myisam corruption after binary upgrade from <=5.0.46 to >=5.0.48 Problem: 'check table .. for upgrade' doesn't detect incompatible collation changes made in 5.0.48. Fix: check for incompatible collation changes. sql/handler.cc: Fix for bug#39585: innodb and myisam corruption after binary upgrade from <=5.0.46 to >=5.0.48 - check for incompatible collation changes made in 5.0.48: bug #29461 latin7_general_ci latin7_general_cs latin7_estonian_cs latin2_hungarian_ci koi8u_general_ci cp1251_ukrainian_ci cp1250_general_ci bug #29499, bug #27562 ascii_general_ci --- sql/handler.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ sql/handler.h | 1 + 2 files changed, 50 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index 619db99b891..a988c34b7ca 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2752,8 +2752,53 @@ bool handler::get_error_message(int error, String* buf) } +/** + Check for incompatible collation changes. + + @retval + HA_ADMIN_NEEDS_UPGRADE Table may have data requiring upgrade. + @retval + 0 No upgrade required. +*/ + +int handler::check_collation_compatibility() +{ + ulong mysql_version= table->s->mysql_version; + + if (mysql_version < 50048) + { + KEY *key= table->key_info; + KEY *key_end= key + table->s->keys; + for (; key < key_end; key++) + { + KEY_PART_INFO *key_part= key->key_part; + KEY_PART_INFO *key_part_end= key_part + key->key_parts; + for (; key_part < key_part_end; key_part++) + { + if (!key_part->fieldnr) + continue; + Field *field= table->field[key_part->fieldnr - 1]; + uint cs_number= field->charset()->number; + if (mysql_version < 50048 && + (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ + cs_number == 41 || /* latin7_general_ci - bug #29461 */ + cs_number == 42 || /* latin7_general_cs - bug #29461 */ + cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ + cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ + cs_number == 22 || /* koi8u_general_ci - bug #29461 */ + cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ + cs_number == 26)) /* cp1250_general_ci - bug #29461 */ + return HA_ADMIN_NEEDS_UPGRADE; + } + } + } + return 0; +} + + int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) { + int error; KEY *keyinfo, *keyend; KEY_PART_INFO *keypart, *keypartend; @@ -2782,6 +2827,10 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) } if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) return HA_ADMIN_NEEDS_ALTER; + + if ((error= check_collation_compatibility())) + return error; + return check_for_upgrade(check_opt); } diff --git a/sql/handler.h b/sql/handler.h index 4ac80014cde..b7d4d689d40 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1211,6 +1211,7 @@ public: int ha_delete_row(const uchar * buf); void ha_release_auto_increment(); + int check_collation_compatibility(); int ha_check_for_upgrade(HA_CHECK_OPT *check_opt); /** to be actually called to get 'check()' functionality*/ int ha_check(THD *thd, HA_CHECK_OPT *check_opt); From b0d9eb1648716361b6fbf43a2a3f14fd5d3df699 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 8 Oct 2008 18:04:36 +0300 Subject: [PATCH 05/10] fixed a compilation problem in 5.1-5.1.29-rc --- sql/sql_class.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 26437d5db83..0f14e282294 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2108,8 +2108,8 @@ public: Don't reset binlog format for NDB binlog injector thread. */ DBUG_PRINT("debug", - ("temporary_tables: %d, in_sub_stmt: %d, system_thread: %s", - (int) temporary_tables, in_sub_stmt, + ("temporary_tables: %p, in_sub_stmt: %d, system_thread: %s", + temporary_tables, in_sub_stmt, show_system_thread(system_thread))); if ((temporary_tables == NULL) && (in_sub_stmt == 0) && (system_thread != SYSTEM_THREAD_NDBCLUSTER_BINLOG)) From c3296418e111e314cbdbd566545a9d2917f0cb21 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 8 Oct 2008 18:25:24 +0300 Subject: [PATCH 06/10] fixed a compile warning in 5.1-5.1.29-rc --- sql/sql_class.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 63dcc6404c6..abbb2de0a82 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3558,6 +3558,7 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end) } +#if !defined(DBUG_OFF) && !defined(_lint) static const char * show_query_type(THD::enum_binlog_query_type qtype) { @@ -3568,12 +3569,16 @@ show_query_type(THD::enum_binlog_query_type qtype) return "STMT"; case THD::MYSQL_QUERY_TYPE: return "MYSQL"; + case THD::QUERY_TYPE_COUNT: + default: + DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT); } static char buf[64]; sprintf(buf, "UNKNOWN#%d", qtype); return buf; } +#endif /* From 0bc7aa2516fa4d4147d02faffeceaf810eb817e5 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 9 Oct 2008 13:39:42 +0300 Subject: [PATCH 07/10] WL4403: --general_log and --slow_query_log don't turn on the logging. Fixed a compilation warning --- sql/mysqld.cc | 4 ---- sql/sql_class.h | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5c64f3f866d..d59ea8eca45 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7665,8 +7665,6 @@ mysqld_get_one_option(int optid, break; case 'l': WARN_DEPRECATED(NULL, "7.0", "--log", "'--general_log'/'--general_log_file'"); - /* FALL-THROUGH */ - case OPT_GENERAL_LOG_FILE: opt_log=1; break; case 'h': @@ -7837,8 +7835,6 @@ mysqld_get_one_option(int optid, #endif /* HAVE_REPLICATION */ case (int) OPT_SLOW_QUERY_LOG: WARN_DEPRECATED(NULL, "7.0", "--log_slow_queries", "'--slow_query_log'/'--slow_query_log_file'"); - /* FALL-THROUGH */ - case (int) OPT_SLOW_QUERY_LOG_FILE: opt_slow_log= 1; break; #ifdef WITH_CSV_STORAGE_ENGINE diff --git a/sql/sql_class.h b/sql/sql_class.h index 0f14e282294..7696882bbcc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1010,6 +1010,7 @@ show_system_thread(enum_thread_type thread) RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER); } #undef RETURN_NAME_AS_STRING + return "UNKNOWN"; /* keep gcc happy */ } /** From d9df61cc1d91f04a87abafb19fdd7ebf3039d084 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 9 Oct 2008 15:46:03 +0300 Subject: [PATCH 08/10] set back version to 5.1.29 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index c75bd617f8f..4c98b2b6dc8 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.30) +AM_INIT_AUTOMAKE(mysql, 5.1.29) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From a83f5b18efaa54df3b56c86c1ab9244280447f24 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Thu, 9 Oct 2008 20:24:31 +0500 Subject: [PATCH 09/10] Bug#38499: flush tables and multitable table update with derived table cause crash When a multi-UPDATE command fails to lock some table, and subsequently succeeds, the tables need to be reopened if they were altered. But the reopening procedure failed for derived tables. Extra cleanup has been added. mysql-test/r/lock_multi.result: Added test case for bug #38499. mysql-test/t/lock_multi.test: Added test case for bug #38499. sql/sql_union.cc: Bug#38499: flush tables and multitable table update with derived table cause crash Obsolete assertion has been removed. sql/sql_update.cc: Bug#38499: flush tables and multitable table update with derived table cause crash Extra cleanup for derived tables has been added: 1) unit.cleanup(), 2) unit->reinit_exec_mechanism(). --- mysql-test/r/lock_multi.result | 18 +++ mysql-test/t/lock_multi.test | 202 +++++++++++++++++++++++++++++++++ sql/sql_union.cc | 1 - sql/sql_update.cc | 20 ++++ 4 files changed, 240 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index d46aea24ac3..0430d560a7a 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -115,3 +115,21 @@ CREATE TABLE t3 SELECT * FROM t1; # normal mode # PS mode DROP TABLE t1, t2, t3; +CREATE TABLE t1( a INT, b INT ); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4); +# 1. test regular tables +# 1.1. test altering of columns that multiupdate doesn't use +# 1.1.1. normal mode +# 1.1.2. PS mode +# 1.2. test altering of columns that multiupdate uses +# 1.2.1. normal mode +# 1.2.2. PS mode +ALTER TABLE t1 ADD COLUMN a INT; +# 2. test UNIONs +# 2.1. test altering of columns that multiupdate doesn't use +# 2.1.1. normal mode +# 2.1.2. PS mode +# 2.2. test altering of columns that multiupdate uses +# 2.2.1. normal mode +# 2.2.2. PS mode +DROP TABLE t1; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index fe22efeb8c2..089a60edb3d 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -400,4 +400,206 @@ while ($i) { --connection default DROP TABLE t1, t2, t3; +# +# Bug#38499: flush tables and multitable table update with derived table cause +# crash +# + +CREATE TABLE t1( a INT, b INT ); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4); + +--echo # 1. test regular tables +--echo # 1.1. test altering of columns that multiupdate doesn't use +--echo # 1.1.1. normal mode + +--disable_query_log +let $i = 100; +while ($i) { +--dec $i + +--connection writer + send UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0; + +--connection locker + ALTER TABLE t1 ADD COLUMN (c INT); + ALTER TABLE t1 DROP COLUMN c; + +--connection writer +--reap +} + +--echo # 1.1.2. PS mode + +--connection writer +PREPARE stmt FROM 'UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0'; + +let $i = 100; +while ($i) { +--dec $i + +--connection writer +--send EXECUTE stmt + +--connection locker + ALTER TABLE t1 ADD COLUMN (c INT); + ALTER TABLE t1 DROP COLUMN c; + +--connection writer +--reap +} +--enable_query_log + +--echo # 1.2. test altering of columns that multiupdate uses +--echo # 1.2.1. normal mode + +--connection default + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t1 ADD COLUMN a int(11) unsigned default NULL; + UPDATE t1 SET a=b; + +--connection writer +--send UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0; + +--connection locker +--error 0,1091 + ALTER TABLE t1 DROP COLUMN a; + +--connection writer +--error 0,1054 # unknown column error +--reap +} +--enable_query_log + +--echo # 1.2.2. PS mode + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t1 ADD COLUMN a INT; + UPDATE t1 SET a=b; + +--connection writer + PREPARE stmt FROM 'UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0'; +--send EXECUTE stmt + +--connection locker +--error 0,1091 + ALTER TABLE t1 DROP COLUMN a; + +--connection writer +--error 0,1054 # Unknown column 'a' in 'field list' +--reap +} +--enable_query_log +--connection default +ALTER TABLE t1 ADD COLUMN a INT; + +--echo # 2. test UNIONs +--echo # 2.1. test altering of columns that multiupdate doesn't use +--echo # 2.1.1. normal mode + +--disable_query_log +let $i = 100; +while ($i) { +--dec $i + +--connection writer + send UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0; + +--connection locker + ALTER TABLE t1 ADD COLUMN (c INT); + ALTER TABLE t1 DROP COLUMN c; + +--connection writer +--reap +} + +--echo # 2.1.2. PS mode + +--connection writer +PREPARE stmt FROM 'UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0'; + +let $i = 100; +while ($i) { +--dec $i + +--connection writer +--send EXECUTE stmt + +--connection locker + ALTER TABLE t1 ADD COLUMN (c INT); + ALTER TABLE t1 DROP COLUMN c; + +--connection writer +--reap +} +--enable_query_log + +--echo # 2.2. test altering of columns that multiupdate uses +--echo # 2.2.1. normal mode + +--connection default + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t1 ADD COLUMN a int(11) unsigned default NULL; + UPDATE t1 SET a=b; + +--connection writer +--send UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0; + +--connection locker +--error 0,1091 + ALTER TABLE t1 DROP COLUMN a; + +--connection writer +--error 0,1054 # Unknown column 'a' in 'field list' +--reap +} +--enable_query_log + +--echo # 2.2.2. PS mode + +--disable_query_log +let $i = 100; +while ($i) { + dec $i; + +--connection locker +--error 0,1060 + ALTER TABLE t1 ADD COLUMN a INT; + UPDATE t1 SET a=b; + +--connection writer + PREPARE stmt FROM 'UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0'; +--send EXECUTE stmt + +--connection locker +--error 0,1091 + ALTER TABLE t1 DROP COLUMN a; + +--connection writer +--error 0,1054 # Unknown column 'a' in 'field list' +--reap +} +--enable_query_log +--connection default +DROP TABLE t1; + # End of 5.0 tests diff --git a/sql/sql_union.cc b/sql/sql_union.cc index da5e118b069..2875aefbd97 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -399,7 +399,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } else { - DBUG_ASSERT(!thd->stmt_arena->is_conventional()); /* We're in execution of a prepared statement or stored procedure: reset field items to point at fields from the created temporary table. diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 109786df7de..eb4e9b7ed73 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -875,6 +875,26 @@ reopen_tables: for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); + /* + To not to hog memory (as a result of the + unit->reinit_exec_mechanism() call below): + */ + lex->unit.cleanup(); + + for (SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + SELECT_LEX_UNIT *unit= sl->master_unit(); + unit->reinit_exec_mechanism(); // reset unit->prepared flags + /* + Reset 'clean' flag back to force normal execution of + unit->cleanup() in Prepared_statement::cleanup_stmt() + (call to lex->unit.cleanup() above sets this flag to TRUE). + */ + unit->unclean(); + } + /* Also we need to cleanup Natural_join_column::table_field items. To not to traverse a join tree we will cleanup whole From 64191b6e688bf755b3e57562eeba1110e906c7b7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Oct 2008 13:54:46 +0200 Subject: [PATCH 10/10] Raise version number after cloning 5.1.29-rc --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4c98b2b6dc8..c75bd617f8f 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.29) +AM_INIT_AUTOMAKE(mysql, 5.1.30) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10