From c394dbe14ad17d2ede6d3fd9dfa8cd2b205a427d Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Fri, 7 Dec 2007 17:14:59 -0800 Subject: [PATCH 1/5] Fixed bug #32815. The index (key_part_1, key_part-2) was erroneously considered as compatible with the required ordering in the function test_test_if_order_by_key when a query with an ORDER BY clause contained a condition of the form key_part_1=const OR key_part_1 IS NULL and the order list contained only key_part_2. This happened because the value of the const_key_parts field in the KEYUSE structure was not formed correctly for the keys that could be used for ref_or_null access. This was fixed in the code of the update_ref_and_keys function. The problem could not manifest itself for MyISAM databases because the implementation of the keys_to_use_for_scanning() handler function always returns an empty bitmap for the MyISAM engine. --- mysql-test/r/innodb_mysql.result | 12 ++++++++++++ mysql-test/t/innodb_mysql.test | 15 +++++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index b073e4bd6ce..7450d8c349b 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1213,4 +1213,16 @@ a b 3 2 1 1 DROP TABLE t1; +CREATE TABLE t1 (id int, type char(6), d int, INDEX idx(id,d)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); +EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL idx NULL NULL NULL 3 Using where; Using filesort +SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; +id type d +191 member 1 +NULL member 3 +NULL member 4 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index f64efd600c5..f1b15d05a60 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -960,4 +960,19 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +# +# Bug #32815: query with ORDER BY and a possible ref_or_null access +# + +CREATE TABLE t1 (id int, type char(6), d int, INDEX idx(id,d)) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); + +EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; +SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; + +DROP TABLE t1; + + + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bcf538cdde2..d1bd018878a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3691,7 +3691,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, found_eq_constant=0; for (i=0 ; i < keyuse->elements-1 ; i++,use++) { - if (!use->used_tables) + if (!use->used_tables && use->optimize != KEY_OPTIMIZE_REF_OR_NULL) use->table->const_key_parts[use->key]|= use->keypart_map; if (use->keypart != FT_KEYPART) { From c04d3727dcae1a7de83d2caf0b72869d703470cf Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Fri, 7 Dec 2007 23:36:58 -0800 Subject: [PATCH 2/5] Fixed bug #27545. Both arguments of the function NAME_CONST must be constant expressions. This constraint is checked in the Item_name_const::fix_fields method. Yet if the argument of the function was not a constant expression no error message was reported. As a result the client hanged waiting for a response. Now the function Item_name_const::fix_fields reports an error message when any of the additional context conditions imposed on the function NAME_CONST is not satisfied. --- mysql-test/r/func_misc.result | 5 +++++ mysql-test/t/func_misc.test | 13 +++++++++++++ sql/item.cc | 14 +++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index c941790c35b..d04c22c0c9d 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -207,4 +207,9 @@ test SELECT NAME_CONST('test', 'test'); test test +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (5), (2); +SELECT NAME_CONST(x,2) FROM (SELECT a x FROM t1) t; +ERROR HY000: The 'NAME_CONST' syntax is reserved for purposes internal to the MySQL server +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 2c34f77b1ff..e8ee76b3a96 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -204,5 +204,18 @@ SELECT NAME_CONST('test', 1.0); SELECT NAME_CONST('test', -1.0); SELECT NAME_CONST('test', 'test'); +# +# Bug #27545: erroneous usage of NAME_CONST with a name as the first parameter +# resolved against a column name of a derived table hangs the client +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (5), (2); + +--error ER_RESERVED_SYNTAX +SELECT NAME_CONST(x,2) FROM (SELECT a x FROM t1) t; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index 3555df40060..4eeb2b2aa84 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1221,14 +1221,14 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) s.length(0); if (value_item->fix_fields(thd, &value_item) || - name_item->fix_fields(thd, &name_item)) + name_item->fix_fields(thd, &name_item) || + !value_item->const_item() || + !name_item->const_item() || + !(item_name= name_item->val_str(&s))) // Can't have a NULL name + { + my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST"); return TRUE; - if (!(value_item->const_item() && name_item->const_item())) - return TRUE; - - if (!(item_name= name_item->val_str(&s))) - return TRUE; /* Can't have a NULL name */ - + } set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info); max_length= value_item->max_length; decimals= value_item->decimals; From 0e3e5cf40d310751eac8ff9109b9a768c2096a7a Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Sun, 9 Dec 2007 11:53:07 -0800 Subject: [PATCH 3/5] Forced compilers to remove the warning appeared after the patch with a fix for bug 32694. --- sql/item_cmpfunc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1881d2f7f1f..4b584f5cb0b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -353,6 +353,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item, ulong orig_sql_mode= thd->variables.sql_mode; enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields; ulonglong orig_field_val; /* original field value if valid */ + LINT_INIT(orig_field_val); thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) | MODE_INVALID_DATES; thd->count_cuted_fields= CHECK_FIELD_IGNORE; From dd0854db54a0fc9f939d69dd91bd710726e9847f Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Thu, 13 Dec 2007 13:38:22 +0300 Subject: [PATCH 4/5] BUG#32198: Comparison of DATE with DATETIME still not using indexes correctly - Make conditions like "date_col $CMP$ 'datetime-const'" range-sargable --- mysql-test/r/range.result | 18 ++++++++++++++++++ mysql-test/t/range.test | 20 ++++++++++++++++++++ sql/field.cc | 3 +++ sql/opt_range.cc | 27 ++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 58f8d077ac5..e0084b53320 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1135,3 +1135,21 @@ item started price A1 2005-11-01 08:00:00 1000.000 A1 2005-11-15 00:00:00 2000.000 DROP TABLE t1; + +BUG#32198 "Comparison of DATE with DATETIME still not using indexes correctly" + +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +dateval date default NULL, +PRIMARY KEY (id), +KEY dateval (dateval) +) AUTO_INCREMENT=173; +INSERT INTO t1 VALUES +(1,'2007-01-01'),(2,'2007-01-02'),(3,'2007-01-03'),(4,'2007-01-04'), +(5,'2007-01-05'),(6,'2007-01-06'),(7,'2007-01-07'),(8,'2007-01-08'), +(9,'2007-01-09'),(10,'2007-01-10'),(11,'2007-01-11'); +This must use range access: +explain select * from t1 where dateval >= '2007-01-01 00:00:00' and dateval <= '2007-01-02 23:59:59'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range dateval dateval 4 NULL 2 Using where +drop table t1; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index b8d4b91f03d..87ba3510326 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -935,4 +935,24 @@ SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00'; DROP TABLE t1; +--echo +--echo BUG#32198 "Comparison of DATE with DATETIME still not using indexes correctly" +--echo +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + dateval date default NULL, + PRIMARY KEY (id), + KEY dateval (dateval) +) AUTO_INCREMENT=173; + +INSERT INTO t1 VALUES +(1,'2007-01-01'),(2,'2007-01-02'),(3,'2007-01-03'),(4,'2007-01-04'), +(5,'2007-01-05'),(6,'2007-01-06'),(7,'2007-01-07'),(8,'2007-01-08'), +(9,'2007-01-09'),(10,'2007-01-10'),(11,'2007-01-11'); + +--echo This must use range access: +explain select * from t1 where dateval >= '2007-01-01 00:00:00' and dateval <= '2007-01-02 23:59:59'; + +drop table t1; + # End of 5.0 tests diff --git a/sql/field.cc b/sql/field.cc index 86853389c64..955694933a0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5259,6 +5259,9 @@ void Field_date::sql_type(String &res) const 1 Value was cut during conversion 2 Wrong date string 3 Datetime value that was cut (warning level NOTE) + This is used by opt_range.cc:get_mm_leaf(). Note that there is a + nearly-identical class Field_date doesn't ever return 3 from its + store function. */ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7a51dbbe76c..5d8bba69422 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4414,6 +4414,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, { tree= new (alloc) SEL_ARG(field, 0, 0); tree->type= SEL_ARG::IMPOSSIBLE; + goto end; } else { @@ -4422,8 +4423,32 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, for the cases like int_field > 999999999999999999999999 as well. */ tree= 0; + if (err == 3 && field->type() == FIELD_TYPE_DATE && + (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || + type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) + { + /* + We were saving DATETIME into a DATE column, the conversion went ok + but a non-zero time part was cut off. + + In MySQL's SQL dialect, DATE and DATETIME are compared as datetime + values. Index over a DATE column uses DATE comparison. Changing + from one comparison to the other is possible: + + datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10' + datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10' + + datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10' + datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10' + + but we'll need to convert '>' to '>=' and '<' to '<='. This will + be done together with other types at the end of this function + (grep for field_is_equal_to_item) + */ + } + else + goto end; } - goto end; } if (err < 0) { From 9df070ed7c0f2877e71572e59aec871f4bc039fd Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Thu, 13 Dec 2007 15:47:23 +0400 Subject: [PATCH 5/5] after merge fix --- mysql-test/r/delayed.result | 16 ---------------- mysql-test/r/func_misc.result | 2 +- mysql-test/t/func_misc.test | 3 +-- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index e7ee23b3e2a..9f6ebea7e1b 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -109,20 +109,12 @@ c1 DROP TABLE t1; SET @@auto_increment_offset= @bug20627_old_auto_increment_offset; -Warnings: -Warning 1292 Truncated incorrect auto-increment-offset value: '0' SET @@auto_increment_increment= @bug20627_old_auto_increment_increment; -Warnings: -Warning 1292 Truncated incorrect auto-increment-increment value: '0' SET @@session.auto_increment_offset= @bug20627_old_session_auto_increment_offset; -Warnings: -Warning 1292 Truncated incorrect auto-increment-offset value: '0' SET @@session.auto_increment_increment= @bug20627_old_session_auto_increment_increment; -Warnings: -Warning 1292 Truncated incorrect auto-increment-increment value: '0' SET @bug20830_old_auto_increment_offset= @@auto_increment_offset; SET @bug20830_old_auto_increment_increment= @@ -245,20 +237,12 @@ SUM(c1) DROP TABLE t1; SET @@auto_increment_offset= @bug20830_old_auto_increment_offset; -Warnings: -Warning 1292 Truncated incorrect auto-increment-offset value: '0' SET @@auto_increment_increment= @bug20830_old_auto_increment_increment; -Warnings: -Warning 1292 Truncated incorrect auto-increment-increment value: '0' SET @@session.auto_increment_offset= @bug20830_old_session_auto_increment_offset; -Warnings: -Warning 1292 Truncated incorrect auto-increment-offset value: '0' SET @@session.auto_increment_increment= @bug20830_old_session_auto_increment_increment; -Warnings: -Warning 1292 Truncated incorrect auto-increment-increment value: '0' CREATE TABLE t1(a BIT); INSERT DELAYED INTO t1 VALUES(1); FLUSH TABLE t1; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 4ba5ee674a9..4f6b6d3a0d8 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -210,7 +210,7 @@ test CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (5), (2); SELECT NAME_CONST(x,2) FROM (SELECT a x FROM t1) t; -ERROR HY000: The 'NAME_CONST' syntax is reserved for purposes internal to the MySQL server +ERROR HY000: Incorrect arguments to NAME_CONST DROP TABLE t1; CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (), (), (); diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 82db9ddbd67..ccb59df5677 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -212,12 +212,11 @@ SELECT NAME_CONST('test', 'test'); CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (5), (2); ---error ER_RESERVED_SYNTAX +--error ER_WRONG_ARGUMENTS SELECT NAME_CONST(x,2) FROM (SELECT a x FROM t1) t; DROP TABLE t1; ---echo End of 5.0 tests # # Bug #32559: connection hangs on query with name_const