From d9175c214777ab3b37cd3752290c80f33c49be41 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 23 Mar 2010 17:07:00 +0200 Subject: [PATCH 1/2] Bug #51850: crash/memory overlap when using load data infile and set col equal to itself! There's no need to copy the value of a field into itself. While generally harmless (except for some performance penalties) it may be dangerous when the copy code doesn't expect this. Fixed by checking if the source field is the same as the destination field before copying the data. Note that we must preserve the order of assignment of the null flags (hence the null_value assignment addition). --- mysql-test/r/loaddata.result | 11 +++++++++++ mysql-test/t/loaddata.test | 14 ++++++++++++++ sql/item.cc | 16 ++++++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 1e488b320d7..0c3f8d04463 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -484,4 +484,15 @@ SET character_set_filesystem=default; select @@character_set_filesystem; @@character_set_filesystem binary +# +# Bug #51850: crash/memory overlap when using load data infile and set +# col equal to itself! +# +CREATE TABLE t1(col0 LONGBLOB); +SELECT 'test' INTO OUTFILE 't1.txt'; +LOAD DATA INFILE 't1.txt' IGNORE INTO TABLE t1 SET col0=col0; +SELECT * FROM t1; +col0 +test +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 7bfe2491c7c..a32fee6b46e 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -532,5 +532,19 @@ SET character_set_filesystem=default; select @@character_set_filesystem; +--echo # +--echo # Bug #51850: crash/memory overlap when using load data infile and set +--echo # col equal to itself! +--echo # + +CREATE TABLE t1(col0 LONGBLOB); +SELECT 'test' INTO OUTFILE 't1.txt'; +LOAD DATA INFILE 't1.txt' IGNORE INTO TABLE t1 SET col0=col0; +SELECT * FROM t1; + +DROP TABLE t1; +let $MYSQLD_DATADIR= `select @@datadir`; +remove_file $MYSQLD_DATADIR/test/t1.txt; + --echo End of 5.1 tests diff --git a/sql/item.cc b/sql/item.cc index d253e19e068..809377e80b3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5063,14 +5063,22 @@ int Item_field::save_in_field(Field *to, bool no_conversions) if (result_field->is_null()) { null_value=1; - res= set_field_to_null_with_conversions(to, no_conversions); + return set_field_to_null_with_conversions(to, no_conversions); } - else + to->set_notnull(); + + /* + If we're setting the same field as the one we're reading from there's + nothing to do. This can happen in 'SET x = x' type of scenarios. + */ + if (to == result_field) { - to->set_notnull(); - res= field_conv(to,result_field); null_value=0; + return 0; } + + res= field_conv(to,result_field); + null_value=0; return res; } From 658cf9e481dc26a45f22a50226969903e5706913 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 24 Mar 2010 14:37:28 +0400 Subject: [PATCH 2/2] Bug#48483 crash in get_best_combination() The crash happens because greedy_serach can not determine best plan due to wrong inner table dependences. These dependences affects join table sorting which performs before greedy_search starting. In our case table which has real 'no dependences' should be put on top of the list but it does not happen as inner tables have no dependences as well. The fix is to exclude RAND_TABLE_BIT mask from condition which checks if table dependences should be updated. --- mysql-test/r/join.result | 17 +++++++++++++++++ mysql-test/t/join.test | 12 ++++++++++++ sql/sql_select.cc | 13 ++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 7d6ef5b40ba..bacfa81160a 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -913,4 +913,21 @@ ON t4.a = t5.a ON t1.a = t3.a; a a a a a a DROP TABLE t1,t2,t3,t4,t5,t6; +# +# Bug#48483: crash in get_best_combination() +# +CREATE TABLE t1(f1 INT); +INSERT INTO t1 VALUES (1),(2); +CREATE VIEW v1 AS SELECT 1 FROM t1 LEFT JOIN t1 AS t2 on 1=1; +EXPLAIN EXTENDED +SELECT 1 FROM v1 right join v1 AS v2 ON RAND(); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` left join `test`.`t1` `t2` on((1 = 1)) left join (`test`.`t1` left join `test`.`t1` `t2` on((1 = 1))) on(rand()) where 1 +DROP VIEW v1; +DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 5b91d89836c..ba61da289bc 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -713,4 +713,16 @@ FROM DROP TABLE t1,t2,t3,t4,t5,t6; +--echo # +--echo # Bug#48483: crash in get_best_combination() +--echo # + +CREATE TABLE t1(f1 INT); +INSERT INTO t1 VALUES (1),(2); +CREATE VIEW v1 AS SELECT 1 FROM t1 LEFT JOIN t1 AS t2 on 1=1; +EXPLAIN EXTENDED +SELECT 1 FROM v1 right join v1 AS v2 ON RAND(); +DROP VIEW v1; +DROP TABLE t1; + --echo End of 5.0 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eecc2b086a3..cbc608ea972 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4819,6 +4819,11 @@ greedy_search(JOIN *join, if (best_extension_by_limited_search(join, remaining_tables, idx, record_count, read_time, search_depth, prune_level)) DBUG_RETURN(TRUE); + /* + 'best_read < DBL_MAX' means that optimizer managed to find + some plan and updated 'best_positions' array accordingly. + */ + DBUG_ASSERT(join->best_read < DBL_MAX); if (size_remain <= search_depth) { @@ -8431,8 +8436,14 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) we still make the inner tables dependent on the outer tables. It would be enough to set dependency only on one outer table for them. Yet this is really a rare case. + Note: + RAND_TABLE_BIT mask should not be counted as it + prevents update of inner table dependences. + For example it might happen if RAND() function + is used in JOIN ON clause. */ - if (!(prev_table->on_expr->used_tables() & ~prev_used_tables)) + if (!((prev_table->on_expr->used_tables() & ~RAND_TABLE_BIT) & + ~prev_used_tables)) prev_table->dep_tables|= used_tables; } }