From f534708bd6637da06a0dbeb5192351072a8bbbcd Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 29 Nov 2013 20:21:05 +0100 Subject: [PATCH 1/7] MDEV-5266 MySQL:57657 - Temporary MERGE table with temporary underlying is broken by ALTER Fix ha_myisammrg::update_create_info() to do what ha_myisammrg::append_create_info() does - take sub-table names from TABLE_LIST, not reverse engineer tablefile names. Backport praveenkumar.hulakund@oracle.com-20120127081643-u7dxy23i8yyqarm7 from mysql-5.6 --- mysql-test/r/merge.result | 7 ++++++ mysql-test/t/merge.test | 9 +++++++ storage/myisammrg/ha_myisammrg.cc | 39 +++++++++++++++++-------------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 937fa77a885..7b50be68281 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2368,4 +2368,11 @@ FLUSH TABLES; ERROR HY000: Can't reopen table: 'm1' UNLOCK TABLES; DROP TABLE t1, t2, t3, m1; +create temporary table t1_temp(i int); +create temporary table tm_temp_temp (i int) engine=merge union=(t1_temp) insert_method=last; +alter table tm_temp_temp insert_method=first; +check table tm_temp_temp; +Table Op Msg_type Msg_text +test.tm_temp_temp check status OK +drop temporary table t1_temp, tm_temp_temp; End of 5.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index eecf892869f..cc26ba35661 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1863,6 +1863,15 @@ FLUSH TABLES; UNLOCK TABLES; DROP TABLE t1, t2, t3, m1; +# +# MDEV-5266 MySQL:57657 - Temporary MERGE table with temporary underlying is broken by ALTER +# +create temporary table t1_temp(i int); +create temporary table tm_temp_temp (i int) engine=merge union=(t1_temp) insert_method=last; +alter table tm_temp_temp insert_method=first; +check table tm_temp_temp; +drop temporary table t1_temp, tm_temp_temp; + --echo End of 5.1 tests --disable_result_log diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 28e2a87e3c5..99ee81d2438 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1111,31 +1111,36 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info) if (!(create_info->used_fields & HA_CREATE_USED_UNION)) { - MYRG_TABLE *open_table; + TABLE_LIST *child_table; THD *thd=current_thd; create_info->merge_list.next= &create_info->merge_list.first; create_info->merge_list.elements=0; - for (open_table=file->open_tables ; - open_table != file->end_table ; - open_table++) + if (table->child_l != NULL) { - TABLE_LIST *ptr; - LEX_STRING db, name; - LINT_INIT(db.str); + for (child_table= table->child_l;; + child_table= child_table->next_global) + { + TABLE_LIST *ptr; - if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) - goto err; - split_file_name(open_table->table->filename, &db, &name); - if (!(ptr->table_name= thd->strmake(name.str, name.length))) - goto err; - if (db.length && !(ptr->db= thd->strmake(db.str, db.length))) - goto err; + if (!(ptr= (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) + goto err; - create_info->merge_list.elements++; - (*create_info->merge_list.next) = ptr; - create_info->merge_list.next= &ptr->next_local; + if (!(ptr->table_name= thd->strmake(child_table->table_name, + child_table->table_name_length))) + goto err; + if (child_table->db && !(ptr->db= thd->strmake(child_table->db, + child_table->db_length))) + goto err; + + create_info->merge_list.elements++; + (*create_info->merge_list.next)= ptr; + create_info->merge_list.next= &ptr->next_local; + + if (&child_table->next_global == table->child_last_l) + break; + } } *create_info->merge_list.next=0; } From 62e959437ee5bf64e89c7b16233ab2ca0fd8507c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 3 Dec 2013 15:08:43 +0400 Subject: [PATCH 2/7] MDEV-5374 main.func_time fails with valgrind warning "Conditional jump or move depends on uninitialised" in Item_time_typecast::get_date. Adding "null_value" into the debug assert condition. --- sql/item_func.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/item_func.h b/sql/item_func.h index a176d5781ac..0838bbc2e99 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -159,7 +159,8 @@ public: inline bool get_arg0_time(MYSQL_TIME *ltime) { null_value= args[0]->get_time(ltime); - DBUG_ASSERT(ltime->time_type != MYSQL_TIMESTAMP_TIME || ltime->day == 0); + DBUG_ASSERT(null_value || + ltime->time_type != MYSQL_TIMESTAMP_TIME || ltime->day == 0); return null_value; } bool is_null() { From b78f721460de41e1a749f78e064f42a8e2953247 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2013 16:54:33 +0200 Subject: [PATCH 3/7] MDEV-5353: server crash on subselect if WHERE applied to some result field Correct processing of view/derived with no tables added. --- mysql-test/r/derived.result | 14 ++++++++++++++ mysql-test/t/derived.test | 10 ++++++++++ sql/item.h | 7 +++++-- sql/table.cc | 6 ++---- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index e68636e0394..3ad9d99651a 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -465,5 +465,19 @@ t1.val=t3.val ; ERROR 42S22: Unknown column 'v.val' in 'field list' drop table t1, t2; +# +# MDEV-5353: server crash on subselect if WHERE applied to some +# result field +# +SELECT * FROM +( SELECT 100 a, subsel.b FROM ( SELECT 200 b ) subsel ) tmp +WHERE tmp.b; +a b +100 200 +SELECT * FROM +( SELECT 100 a, subsel.b FROM ( SELECT 200 b ) subsel ) tmp +WHERE tmp.a; +a b +100 200 # End of 5.3 tests set optimizer_switch=@save_derived_optimizer_switch; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 2a5ba77f38e..4f6b8443055 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -383,7 +383,17 @@ set drop table t1, t2; +--echo # +--echo # MDEV-5353: server crash on subselect if WHERE applied to some +--echo # result field +--echo # +SELECT * FROM +( SELECT 100 a, subsel.b FROM ( SELECT 200 b ) subsel ) tmp +WHERE tmp.b; +SELECT * FROM +( SELECT 100 a, subsel.b FROM ( SELECT 200 b ) subsel ) tmp +WHERE tmp.a; --echo # End of 5.3 tests set optimizer_switch=@save_derived_optimizer_switch; diff --git a/sql/item.h b/sql/item.h index 03b333e7997..5e8e4dfc892 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2963,13 +2963,16 @@ class Item_direct_view_ref :public Item_direct_ref TABLE_LIST *view; TABLE *null_ref_table; +#define NO_NULL_TABLE (reinterpret_cast(0x1)) + bool check_null_ref() { if (null_ref_table == NULL) { - null_ref_table= view->get_real_join_table(); + if (!(null_ref_table= view->get_real_join_table())) + null_ref_table= NO_NULL_TABLE; } - if (null_ref_table->null_row) + if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row) { null_value= 1; return TRUE; diff --git a/sql/table.cc b/sql/table.cc index 9e1c53f7b22..066eb506835 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4487,10 +4487,8 @@ TABLE *TABLE_LIST::get_real_join_table() */ for (TABLE_LIST *t= ti++; t; t= ti++) tbl= t; - /* - It is impossible that the list is empty - so tbl can't be NULL after above loop. - */ + if (!tbl) + return NULL; // view/derived with no tables if (!tbl->nested_join) break; /* go deeper if we've found nested join */ From ccf5871d7bf8be15fcf9a03842a2f40337a7f72f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 5 Dec 2013 11:13:20 -0800 Subject: [PATCH 4/7] Fixed bug mdev-5382 When marking used columns the function find_field_in_table_ref() erroneously called the walk method for the real item behind a view/derived table field with the second parameter set to TRUE. This erroneous code was introduced in 2006. --- mysql-test/r/union.result | 15 +++++++++++++++ mysql-test/t/union.test | 16 ++++++++++++++++ sql/sql_base.cc | 4 ++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 05dab9e2874..d4effc8448d 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1738,4 +1738,19 @@ i 6 DROP VIEW v1; DROP TABLE t1; +# +# mdev-5382: UNION with ORDER BY in subselect +# +CREATE TABLE t1 (a int DEFAULT NULL); +INSERT INTO t1 VALUES (2), (4); +CREATE TABLE t2 (b int DEFAULT NULL); +INSERT INTO t2 VALUES (1), (3); +SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b +UNION ALL +SELECT a FROM t1 WHERE t1.a+3<= t2.b +ORDER BY a DESC) AS c1 FROM t2) t3; +c1 +NULL +2 +DROP TABLE t1,t2; End of 5.3 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index bb0e5610a26..bc995aac0a0 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1227,5 +1227,21 @@ deallocate prepare stmt1; DROP VIEW v1; DROP TABLE t1; +--echo # +--echo # mdev-5382: UNION with ORDER BY in subselect +--echo # + + CREATE TABLE t1 (a int DEFAULT NULL); + INSERT INTO t1 VALUES (2), (4); + CREATE TABLE t2 (b int DEFAULT NULL); + INSERT INTO t2 VALUES (1), (3); + + SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b + UNION ALL + SELECT a FROM t1 WHERE t1.a+3<= t2.b + ORDER BY a DESC) AS c1 FROM t2) t3; + + DROP TABLE t1,t2; + --echo End of 5.3 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 130763de76a..3eeb8afef6b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6429,9 +6429,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, else { if (thd->mark_used_columns == MARK_COLUMNS_READ) - it->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); + it->walk(&Item::register_field_in_read_map, 0, (uchar *) 0); else - it->walk(&Item::register_field_in_write_map, 1, (uchar *) 0); + it->walk(&Item::register_field_in_write_map, 0, (uchar *) 0); } } else From d5262a63fcbb13e3c2b1734ada36f3db8c6cb0c3 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 7 Dec 2013 07:51:02 -0800 Subject: [PATCH 5/7] Fixed bug mdev-5400: a memory leak in save_index() first seen in the test case for mdev-5382. --- sql/sql_select.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 43f70b80557..a66c6bd15d8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10533,7 +10533,6 @@ void JOIN::cleanup(bool full) { tab->cleanup(); } - table= 0; } else { From fde2777b2722a2b81f995c74e74cc3e47c0f8788 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 11 Dec 2013 10:13:08 -0800 Subject: [PATCH 6/7] Another attempt to fix the memory leak of mdev-5400. --- sql/sql_select.cc | 1 + sql/sql_union.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a66c6bd15d8..d38363f15d1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10533,6 +10533,7 @@ void JOIN::cleanup(bool full) { tab->cleanup(); } + table= 0; } else { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5c4a9a8db5f..f82657a837c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -628,6 +628,7 @@ bool st_select_lex_unit::exec() { ha_rows records_at_start= 0; thd->lex->current_select= sl; + fake_select_lex->uncacheable|= sl->uncacheable; { set_limit(sl); From 3ec4296ec413e866c3efabc8dfa94172ad5f7c04 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 12 Dec 2013 13:55:33 -0800 Subject: [PATCH 7/7] Fixed bug mdev-5410. The fix for bug #27937 was incomplete: it did not handle correctly the queries containing UNION with global ORDER BY in subselects. --- mysql-test/r/ps.result | 23 +++++++++++++++++++++++ mysql-test/t/ps.test | 22 ++++++++++++++++++++++ sql/sql_lex.h | 2 +- sql/sql_union.cc | 17 +++++++++++++---- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 75aef40b529..e5411b2a210 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -3284,4 +3284,27 @@ Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 deallocate prepare st; drop table t1; +# +# Bug mdev-5410: crash at the execution of PS with subselect +# formed by UNION with global ORDER BY +# +CREATE TABLE t1 (a int DEFAULT NULL); +INSERT INTO t1 VALUES (2), (4); +CREATE TABLE t2 (b int DEFAULT NULL); +INSERT INTO t2 VALUES (1), (3); +PREPARE stmt FROM " +SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b + UNION ALL + SELECT a FROM t1 WHERE t1.a+3<= t2.b + ORDER BY a DESC) AS c1 FROM t2) t3; +"; +EXECUTE stmt; +c1 +NULL +2 +EXECUTE stmt; +c1 +NULL +2 +DROP TABLE t1,t2; # End of 5.3 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index f1941337874..4d7c6848da7 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -3308,4 +3308,26 @@ show status like '%Handler_read%'; deallocate prepare st; drop table t1; +--echo # +--echo # Bug mdev-5410: crash at the execution of PS with subselect +--echo # formed by UNION with global ORDER BY +--echo # + +CREATE TABLE t1 (a int DEFAULT NULL); +INSERT INTO t1 VALUES (2), (4); +CREATE TABLE t2 (b int DEFAULT NULL); +INSERT INTO t2 VALUES (1), (3); + +PREPARE stmt FROM " +SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b + UNION ALL + SELECT a FROM t1 WHERE t1.a+3<= t2.b + ORDER BY a DESC) AS c1 FROM t2) t3; +"; + +EXECUTE stmt; +EXECUTE stmt; + +DROP TABLE t1,t2; + --echo # End of 5.3 tests diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4b4496a7df8..d5639724d5f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -584,7 +584,7 @@ public: void print(String *str, enum_query_type query_type); bool add_fake_select_lex(THD *thd); - void init_prepare_fake_select_lex(THD *thd); + void init_prepare_fake_select_lex(THD *thd, bool first_execution); inline bool is_prepared() { return prepared; } bool change_result(select_result_interceptor *result, select_result_interceptor *old_result); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index f82657a837c..5ca4af8eb0d 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -184,13 +184,15 @@ void select_union::cleanup() SYNOPSIS st_select_lex_unit::init_prepare_fake_select_lex() thd - thread handler + first_execution - TRUE at the first execution of the union RETURN options of SELECT */ void -st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg) +st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, + bool first_execution) { thd_arg->lex->current_select= fake_select_lex; fake_select_lex->table_list.link_in_list(&result_table_list, @@ -198,7 +200,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg) fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table= fake_select_lex->get_table_list(); - if (!fake_select_lex->first_execution) + /* + The flag fake_select_lex->first_execution indicates whether this is + called at the first execution of the statement, while first_execution + shows whether this is called at the first execution of the union that + may form just a subselect. + */ + if (!fake_select_lex->first_execution && first_execution) { for (ORDER *order= global_parameters->order_list.first; order; @@ -472,7 +480,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { /* Validate the global parameters of this union */ - init_prepare_fake_select_lex(thd); + init_prepare_fake_select_lex(thd, TRUE); /* Should be done only once (the only item_list per statement) */ DBUG_ASSERT(fake_select_lex->join == 0); if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options, @@ -612,6 +620,7 @@ bool st_select_lex_unit::exec() SELECT_LEX *select_cursor=first_select(); ulonglong add_rows=0; ha_rows examined_rows= 0; + bool first_execution= !executed; DBUG_ENTER("st_select_lex_unit::exec"); if (executed && !uncacheable && !describe) @@ -714,7 +723,7 @@ bool st_select_lex_unit::exec() if (!thd->is_fatal_error) // Check if EOM { set_limit(global_parameters); - init_prepare_fake_select_lex(thd); + init_prepare_fake_select_lex(thd, first_execution); JOIN *join= fake_select_lex->join; if (!join) {