#At file:///data0/martin/bzr/bug47925/5.1bt/ based on revid:v.narayanan@stripped
3162 Martin Hansson 2009-10-13
Bug#47925: regression of range optimizer and date comparison in 5.1.39!
When a query was using a DATE or DATETIME value formatted
using other separator characters than the most commonly used
hyphen '-', a query with a greater-or-equal '>=' condition
matching only the greatest value in an indexed column, the
result was empty if index range scan was employed.
The range optimizer got a new feature between 5.1.38 and
5.1.39 that changes a greater-or-equal condition to a
greater-than if the value matching that in the query was not
present in the table. But the value comparison function
compared the dates as strings instead of dates.
The bug was fixed by parsing the date strings and comparing
the integer representation of the dates.
@ mysql-test/r/range.result
Bug#47925: Test result
@ mysql-test/t/range.test
Bug#47925: Test case and the obligatory "End of 5.1 tests"
@ sql/item.cc
Bug#47925: Fix + some edit on the comments
modified:
mysql-test/r/range.result
mysql-test/t/range.test
sql/item.cc
=== modified file 'mysql-test/r/range.result'
--- a/mysql-test/r/range.result 2009-10-09 09:30:40 +0000
+++ b/mysql-test/r/range.result 2009-10-13 15:34:44 +0000
@@ -1398,3 +1398,57 @@ a < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 range a a 5 NULL 8 Using where; Using index
DROP TABLE t1, t2, t3;
+#
+# Bug#47925: regression of range optimizer and date comparison in 5.1.39!
+#
+CREATE TABLE t1 ( a DATE, KEY ( a ) );
+CREATE TABLE t2 ( a DATETIME, KEY ( a ) );
+# Make optimizer choose range scan
+INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22');
+INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23');
+INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'),
+('2009-09-22 12:00:00');
+INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'),
+('2009-09-23 12:00:00');
+# DATE vs DATE
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2009/09/23';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 4 NULL 4 Using where; Using index
+SELECT * FROM t1 WHERE a >= '2009/09/23';
+a
+2009-09-23
+2009-09-23
+2009-09-23
+# DATE vs DATETIME
+EXPLAIN
+SELECT * FROM t2 WHERE a >= '2009/09/23';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range a a 9 NULL 4 Using where; Using index
+SELECT * FROM t2 WHERE a >= '2009/09/23';
+a
+2009-09-23 12:00:00
+2009-09-23 12:00:00
+2009-09-23 12:00:00
+# DATETIME vs DATETIME
+EXPLAIN
+SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range a a 9 NULL 4 Using where; Using index
+SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00';
+a
+2009-09-23 12:00:00
+2009-09-23 12:00:00
+2009-09-23 12:00:00
+# DATETIME vs DATE
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 4 NULL 4 Using where; Using index
+SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00';
+a
+2009-09-23
+2009-09-23
+2009-09-23
+DROP TABLE t1, t2;
+End of 5.1 tests
=== modified file 'mysql-test/t/range.test'
--- a/mysql-test/t/range.test 2009-10-09 09:30:40 +0000
+++ b/mysql-test/t/range.test 2009-10-13 15:34:44 +0000
@@ -1171,3 +1171,42 @@ a < 5 OR
a < 10;
DROP TABLE t1, t2, t3;
+
+--echo #
+--echo # Bug#47925: regression of range optimizer and date comparison in 5.1.39!
+--echo #
+CREATE TABLE t1 ( a DATE, KEY ( a ) );
+CREATE TABLE t2 ( a DATETIME, KEY ( a ) );
+
+--echo # Make optimizer choose range scan
+INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22');
+INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23');
+
+INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'),
+ ('2009-09-22 12:00:00');
+INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'),
+ ('2009-09-23 12:00:00');
+
+--echo # DATE vs DATE
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2009/09/23';
+SELECT * FROM t1 WHERE a >= '2009/09/23';
+
+--echo # DATE vs DATETIME
+EXPLAIN
+SELECT * FROM t2 WHERE a >= '2009/09/23';
+SELECT * FROM t2 WHERE a >= '2009/09/23';
+
+--echo # DATETIME vs DATETIME
+EXPLAIN
+SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00';
+SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00';
+
+--echo # DATETIME vs DATE
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00';
+SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00';
+
+DROP TABLE t1, t2;
+
+--echo End of 5.1 tests
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2009-09-29 02:23:38 +0000
+++ b/sql/item.cc 2009-10-13 15:34:44 +0000
@@ -6866,15 +6866,19 @@ void resolve_const_item(THD *thd, Item *
}
/**
- Compare the value stored in field, with the original item.
+ Compare the value stored in field with the expression from the query.
- @param field field which the item is converted and stored in
- @param item original item
+ @param field Field which the item is converted and then stored in
+ @param item Original expression from query
- @return Return an integer greater than, equal to, or less than 0 if
- the value stored in the field is greater than, equal to,
+ @return Returns an integer greater than, equal to, or less than 0 if
+ the value stored in the field is greater than, equal to,
or less than the original item
+ @retval -1 field < item
+ @retval 0 field = item or item is NULL
+ @retval 1 field > item
+
@note We only use this on the range optimizer/partition pruning,
because in some cases we can't store the value in the field
without some precision/character loss.
@@ -6889,29 +6893,50 @@ int stored_field_cmp_to_item(Field *fiel
{
char item_buff[MAX_FIELD_WIDTH];
char field_buff[MAX_FIELD_WIDTH];
- String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result;
+ String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin);
String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
- enum_field_types field_type;
- item_result=item->val_str(&item_tmp);
- if (item->null_value)
- return 0;
- field->val_str(&field_tmp);
-
+ String *item_result, *field_result;
+ item_result= item->val_str(&item_tmp);
/*
- If comparing DATE with DATETIME, append the time-part to the DATE.
- So that the strings are equally formatted.
- A DATE converted to string is 10 characters, and a DATETIME converted
- to string is 19 characters.
+ Item_date::val_str(String*) actually modifies the field Item::null_value!
+ Hence we can't check it earlier.
*/
- field_type= field->type();
- if (field_type == MYSQL_TYPE_DATE &&
- item_result->length() == 19)
- field_tmp.append(" 00:00:00");
- else if (field_type == MYSQL_TYPE_DATETIME &&
- item_result->length() == 10)
- item_result->append(" 00:00:00");
-
- return stringcmp(&field_tmp,item_result);
+ if (item->null_value)
+ return 0;
+ field_result= field->val_str(&field_tmp);
+ DBUG_PRINT("hej3", ("item '%s'", item_result->ptr()));
+ DBUG_PRINT("hej3", ("field '%s'", field_result->ptr()));
+
+ if (field->type() == MYSQL_TYPE_DATE ||
+ field->type() == MYSQL_TYPE_DATETIME)
+ {
+ MYSQL_TIME field_time_value, item_time_value;
+ int ingored_was_cut;
+ enum_mysql_timestamp_type ignored_type;
+
+ ignored_type= str_to_datetime(field_result->ptr(), field_result->length(),
+ &field_time_value, TIME_FUZZY_DATE,
+ &ingored_was_cut);
+
+ ignored_type= str_to_datetime(item_result->ptr(), item_result->length(),
+ &item_time_value, TIME_FUZZY_DATE,
+ &ingored_was_cut);
+
+ ulonglong field_time_integer_value, item_time_integer_value;
+ field_time_integer_value= TIME_to_ulonglong_datetime(&field_time_value);
+ item_time_integer_value= TIME_to_ulonglong_datetime(&item_time_value);
+
+ DBUG_PRINT("hej3", ("comparing %llu to %llu",
+ field_time_integer_value, item_time_integer_value));
+
+ if (field_time_integer_value > item_time_integer_value)
+ return 1;
+ if (field_time_integer_value < item_time_integer_value)
+ return -1;
+ return 0;
+ }
+ else
+ return stringcmp(field_result, item_result);
}
if (res_type == INT_RESULT)
return 0; // Both are of type int
Attachment: [text/bzr-bundle] bzr/martin.hansson@sun.com-20091013153444-j205dhigu72h1x86.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (martin.hansson:3162) Bug#47925 | Martin Hansson | 13 Oct |