From 06bf25e4d429682a518bea5a1b67392fe51756da Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Wed, 27 Aug 2008 17:03:17 +0400 Subject: [PATCH 1/2] Bug#38195: Incorrect handling of aggregate functions when loose index scan is used causes server crash. When the loose index scan access method is used values of aggregated functions are precomputed by it. Aggregation of such functions shouldn't be performed in this case and functions should be treated as normal ones. The create_tmp_table function wasn't taking this into account and this led to a crash if a query has MIN/MAX aggregate functions and employs temporary table and loose index scan. Now the JOIN::exec and the create_tmp_table functions treat MIN/MAX aggregate functions as normal ones when the loose index scan is used. mysql-test/r/group_min_max.result: Added a test case for the bug#38195. mysql-test/t/group_min_max.test: Added a test case for the bug#38195. sql/sql_select.cc: Bug#38195: Incorrect handling of aggregate functions when loose index scan is used causes server crash. The JOIN::exec and the create_tmp_table functions treat MIN/MAX aggregate functions as normal ones when the loose index scan is used. --- mysql-test/r/group_min_max.result | 76 +++++++++++++++++++++++++++++++ mysql-test/t/group_min_max.test | 19 ++++++++ sql/sql_select.cc | 5 +- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 5982931e677..f2f488650d5 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2353,3 +2353,79 @@ a MIN(b) MAX(b) AVG(b) 2 1 3 2.0000 1 1 3 2.0000 DROP TABLE t1; +create table t1 (a int, b int, primary key (a,b), key `index` (a,b)) engine=MyISAM; +insert into t1 (a,b) values +(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(0,6), +(0,7),(0,8),(0,9),(0,10),(0,11),(0,12),(0,13), +(1,0),(1,1),(1,2),(1,3),(1,4),(1,5),(1,6), +(1,7),(1,8),(1,9),(1,10),(1,11),(1,12),(1,13), +(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),(2,6), +(2,7),(2,8),(2,9),(2,10),(2,11),(2,12),(2,13), +(3,0),(3,1),(3,2),(3,3),(3,4),(3,5),(3,6), +(3,7),(3,8),(3,9),(3,10),(3,11),(3,12),(3,13); +insert into t1 (a,b) select a, max(b)+1 from t1 where a = 0 group by a; +select * from t1; +a b +0 0 +0 1 +0 2 +0 3 +0 4 +0 5 +0 6 +0 7 +0 8 +0 9 +0 10 +0 11 +0 12 +0 13 +0 14 +1 0 +1 1 +1 2 +1 3 +1 4 +1 5 +1 6 +1 7 +1 8 +1 9 +1 10 +1 11 +1 12 +1 13 +2 0 +2 1 +2 2 +2 3 +2 4 +2 5 +2 6 +2 7 +2 8 +2 9 +2 10 +2 11 +2 12 +2 13 +3 0 +3 1 +3 2 +3 3 +3 4 +3 5 +3 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +3 13 +explain extended select sql_buffer_result a, max(b)+1 from t1 where a = 0 group by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,index PRIMARY 4 NULL 3 Using where; Using index for group-by; Using temporary +Warnings: +Note 1003 select sql_buffer_result `test`.`t1`.`a` AS `a`,(max(`test`.`t1`.`b`) + 1) AS `max(b)+1` from `test`.`t1` where (`test`.`t1`.`a` = 0) group by `test`.`t1`.`a` +drop table t1; diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 7f2607b513d..f7aed7301fb 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -916,3 +916,22 @@ SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; DROP TABLE t1; + +# +# Bug#38195: Incorrect handling of aggregate functions when loose index scan is +# used causes server crash. +# +create table t1 (a int, b int, primary key (a,b), key `index` (a,b)) engine=MyISAM; +insert into t1 (a,b) values +(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(0,6), + (0,7),(0,8),(0,9),(0,10),(0,11),(0,12),(0,13), +(1,0),(1,1),(1,2),(1,3),(1,4),(1,5),(1,6), + (1,7),(1,8),(1,9),(1,10),(1,11),(1,12),(1,13), +(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),(2,6), + (2,7),(2,8),(2,9),(2,10),(2,11),(2,12),(2,13), +(3,0),(3,1),(3,2),(3,3),(3,4),(3,5),(3,6), + (3,7),(3,8),(3,9),(3,10),(3,11),(3,12),(3,13); +insert into t1 (a,b) select a, max(b)+1 from t1 where a = 0 group by a; +select * from t1; +explain extended select sql_buffer_result a, max(b)+1 from t1 where a = 0 group by a; +drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6de4b296d34..6928effc1a5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1724,7 +1724,8 @@ JOIN::exec() if (!items1) { items1= items0 + all_fields.elements; - if (sort_and_group || curr_tmp_table->group) + if (sort_and_group || curr_tmp_table->group || + tmp_table_param.precomputed_group_by) { if (change_to_use_tmp_fields(thd, items1, tmp_fields_list1, tmp_all_fields1, @@ -9259,6 +9260,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, MI_COLUMNDEF *recinfo; uint total_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; DBUG_ENTER("create_tmp_table"); DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d", (int) distinct, (int) save_sum_fields, From 54a59681d68d9e2edd1354443d35e54bd8373090 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Thu, 28 Aug 2008 02:10:37 +0500 Subject: [PATCH 2/2] Bug #37799: SELECT with a BIT column in WHERE clause returns unexpected result If: 1. a table has a not nullable BIT column c1 with a length shorter than 8 bits and some additional not nullable columns c2 etc, and 2. the WHERE clause is like: (c1 = constant) AND c2 ..., the SELECT query returns unexpected result set. The server stores BIT columns in a tricky way to save disk space: if column's bit length is not divisible by 8, the server places reminder bits among the null bits at the start of a record. The rest bytes are stored in the record itself, and Field::ptr points to these rest bytes. However if a bit length of the whole column is less than 8, there are no remaining bytes, and there is nothing to store in the record at its regular place. In this case Field::ptr points to bytes actually occupied by the next column in a record. If both columns (BIT and the next column) are NOT NULL, the Field::eq function incorrectly deduces that this is the same column, so query transformation/equal item elimination code (see build_equal_items_for_cond) may mix these columns and damage conditions containing references to them. mysql-test/r/type_bit.result: Added test case for bug #37799. mysql-test/t/type_bit.test: Added test case for bug #37799. sql/field.h: 1. The Field::eq function has been modified to take types of comparing columns into account to distinguish between BIT and not BIT columns referencing the same bytes in a record. 2. Unnecessary type comparison has been removed from the Field_bit::eq function (moved to Field::eq). --- mysql-test/r/type_bit.result | 24 ++++++++++++++++++++++++ mysql-test/t/type_bit.test | 19 +++++++++++++++++++ sql/field.h | 3 +-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 4c4fcb9a9ae..68c0e1635a3 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -684,4 +684,28 @@ SELECT 1 FROM t1 GROUP BY a; 1 1 DROP TABLE t1; +CREATE TABLE t1 (b BIT NOT NULL, i2 INTEGER NOT NULL, s VARCHAR(255) NOT NULL); +INSERT INTO t1 VALUES(0x01,100,''), (0x00,300,''), (0x01,200,''), (0x00,100,''); +SELECT HEX(b), i2 FROM t1 WHERE (i2>=100 AND i2<201) AND b=TRUE; +HEX(b) i2 +1 100 +1 200 +CREATE TABLE t2 (b1 BIT NOT NULL, b2 BIT NOT NULL, i2 INTEGER NOT NULL, +s VARCHAR(255) NOT NULL); +INSERT INTO t2 VALUES (0x01,0x00,100,''), (0x00,0x01,300,''), +(0x01,0x00,200,''), (0x00,0x01,100,''); +SELECT HEX(b1), i2 FROM t2 WHERE (i2>=100 AND i2<201) AND b1=TRUE; +HEX(b1) i2 +1 100 +1 200 +SELECT HEX(b2), i2 FROM t2 WHERE (i2>=100 AND i2<201) AND b2=FALSE; +HEX(b2) i2 +0 100 +0 200 +SELECT HEX(b1), HEX(b2), i2 FROM t2 +WHERE (i2>=100 AND i2<201) AND b1=TRUE AND b2=FALSE; +HEX(b1) HEX(b2) i2 +1 0 100 +1 0 200 +DROP TABLE t1, t2; End of 5.0 tests diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 3095311bfbc..6a6b29deda4 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -333,4 +333,23 @@ SELECT 1 FROM t1 GROUP BY a; DROP TABLE t1; +# +# Bug#37799 SELECT with a BIT column in WHERE clause returns unexpected result +# + +CREATE TABLE t1 (b BIT NOT NULL, i2 INTEGER NOT NULL, s VARCHAR(255) NOT NULL); +INSERT INTO t1 VALUES(0x01,100,''), (0x00,300,''), (0x01,200,''), (0x00,100,''); +SELECT HEX(b), i2 FROM t1 WHERE (i2>=100 AND i2<201) AND b=TRUE; + +CREATE TABLE t2 (b1 BIT NOT NULL, b2 BIT NOT NULL, i2 INTEGER NOT NULL, + s VARCHAR(255) NOT NULL); +INSERT INTO t2 VALUES (0x01,0x00,100,''), (0x00,0x01,300,''), + (0x01,0x00,200,''), (0x00,0x01,100,''); +SELECT HEX(b1), i2 FROM t2 WHERE (i2>=100 AND i2<201) AND b1=TRUE; +SELECT HEX(b2), i2 FROM t2 WHERE (i2>=100 AND i2<201) AND b2=FALSE; +SELECT HEX(b1), HEX(b2), i2 FROM t2 + WHERE (i2>=100 AND i2<201) AND b1=TRUE AND b2=FALSE; + +DROP TABLE t1, t2; + --echo End of 5.0 tests diff --git a/sql/field.h b/sql/field.h index 241ad61f339..7b2dda77095 100644 --- a/sql/field.h +++ b/sql/field.h @@ -138,7 +138,7 @@ public: virtual bool eq(Field *field) { return (ptr == field->ptr && null_ptr == field->null_ptr && - null_bit == field->null_bit); + null_bit == field->null_bit && field->type() == type()); } virtual bool eq_def(Field *field); @@ -1489,7 +1489,6 @@ public: bool eq(Field *field) { return (Field::eq(field) && - field->type() == type() && bit_ptr == ((Field_bit *)field)->bit_ptr && bit_ofs == ((Field_bit *)field)->bit_ofs); }