From e3917c3d43471725a79f89aae12eabbdc5dc55a4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 29 Oct 2010 12:23:06 +0400 Subject: [PATCH] Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field Lines below which were added in the patch for Bug#56814 cause this crash: + if (table->table) + table->table->maybe_null= FALSE; Consider following test case: -- CREATE TABLE t1(f1 INT NOT NULL); INSERT INTO t1 VALUES (16777214),(0); SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; DROP TABLE t1; -- We set TABLE::maybe_null to FALSE for t2 table and in create_tmp_field() we create appropriate tmp table field using create_tmp_field_from_item() function instead of create_tmp_field_from_field. As a result we have LONGLONG field. As we have GROUP BY clause we calculate group buffer length, see calc_group_buffer(). Item from group list which is used for calculation refer to the field from real tables and have LONG type. So group buffer length become insufficient for storing of LONGLONG value. It leads to overwriting of wrong memory area in do_field_int() function which is called from end_update(). After some investigation I found out that create_tmp_field_from_item() is used only for OLAP grouping and can not be used for common grouping as it could be an incompatibility between tmp table fields and group buffer length. We can not remove create_tmp_field_from_item() call from create_tmp_field as OLAP needs it and we can not use this function for common grouping. So we should remove setting TABLE::maybe_null to FALSE from simplify_joins(). In this case we'll get wrong behaviour of list_contains_unique_index() back. To fix it we could use Field::real_maybe_null() check instead of Field::maybe_null() and add addition check of TABLE_LIST::outer_join. --- mysql-test/r/group_by.result | 10 ++++++++++ mysql-test/r/join_outer.result | 30 ++++++++++++++++++++++++++++++ mysql-test/t/group_by.test | 11 +++++++++++ mysql-test/t/join_outer.test | 29 +++++++++++++++++++++++++++++ sql/sql_select.cc | 11 +++-------- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index f74584f6bcf..83f1f220023 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1845,4 +1845,14 @@ SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; SUBSTRING(a,1,10) LENGTH(a) 1111111111 1300 DROP TABLE t1; +# +# Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +# +CREATE TABLE t1(f1 INT NOT NULL); +INSERT INTO t1 VALUES (16777214),(0); +SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 +ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; +COUNT(*) +2 +DROP TABLE t1; # End of 5.1 tests diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 8e438934b23..d9c4ac5478e 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1397,4 +1397,34 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select straight_join `test`.`jt1`.`f1` AS `f1` from `test`.`t1` `jt6` left join (`test`.`t1` `jt3` join `test`.`t1` `jt4` left join `test`.`t1` `jt5` on(1) left join `test`.`t1` `jt2` on(1)) on((`test`.`jt6`.`f1` and 1)) left join `test`.`t1` `jt1` on(1) where 1 DROP TABLE t1; +# +# Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +# +CREATE TABLE t1 (f1 INT NOT NULL, PRIMARY KEY (f1)); +CREATE TABLE t2 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY (f1, f2)); +INSERT INTO t1 VALUES (4); +INSERT INTO t2 VALUES (3, 3); +INSERT INTO t2 VALUES (7, 7); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using temporary; Using filesort +1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using index +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; +f1 f1 f2 +4 NULL NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort +1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; +f1 f1 f2 +DROP TABLE t1,t2; End of 5.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 75ec1d82b02..580c2e5091c 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1235,5 +1235,16 @@ SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; DROP TABLE t1; +--echo # +--echo # Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +--echo # + +CREATE TABLE t1(f1 INT NOT NULL); +INSERT INTO t1 VALUES (16777214),(0); + +SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 +ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; + +DROP TABLE t1; --echo # End of 5.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index cf881e6aaa2..3251ff292b6 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -981,4 +981,33 @@ EXPLAIN EXTENDED SELECT STRAIGHT_JOIN jt1.f1 FROM t1 AS jt1 DROP TABLE t1; +--echo # +--echo # Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +--echo # + +CREATE TABLE t1 (f1 INT NOT NULL, PRIMARY KEY (f1)); +CREATE TABLE t2 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY (f1, f2)); + +INSERT INTO t1 VALUES (4); +INSERT INTO t2 VALUES (3, 3); +INSERT INTO t2 VALUES (7, 7); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; + +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; + +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; + +DROP TABLE t1,t2; + --echo End of 5.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 11acd0685a8..9767839b5bf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8832,13 +8832,6 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) that reject nulls => the outer join can be replaced by an inner join. */ table->outer_join= 0; - /* - Update TABLE::maybe_null field as it could have - the value(maybe_null==TRUE) based on the assumption - that this join is outer(see setup_table_map() func). - */ - if (table->table) - table->table->maybe_null= FALSE; if (table->on_expr) { /* Add on expression to the where condition. */ @@ -13219,6 +13212,8 @@ static bool list_contains_unique_index(TABLE *table, bool (*find_func) (Field *, void *), void *data) { + if (table->pos_in_table_list->outer_join) + return 0; for (uint keynr= 0; keynr < table->s->keys; keynr++) { if (keynr == table->s->primary_key || @@ -13232,7 +13227,7 @@ list_contains_unique_index(TABLE *table, key_part < key_part_end; key_part++) { - if (key_part->field->maybe_null() || + if (key_part->field->real_maybe_null() || !find_func(key_part->field, data)) break; }