List:Commits« Previous MessageNext Message »
From:Ramil Kalimullin Date:October 18 2009 4:27pm
Subject:bzr commit into mysql-5.1-bugteam branch (ramil:3182) Bug#47963
View as plain text  
#At file:///home/ram/mysql/mysql-5.1-bugteam/ based on revid:alexey.kopytov@stripped

 3182 Ramil Kalimullin	2009-10-18 [merge]
      Fix for bug#47963: Wrong results when index is used
      
      Problem: using null microsecond part in a WHERE condition 
      (e.g. WHERE date_time_field <= "YYYY-MM-DD HH:MM:SS.0000") 
      may lead to wrong results due to improper DATETIMEs 
      comparison in some cases.
      
      Fix: comparing DATETIMEs as strings we must trim trailing 0's
      in such cases.
     @ mysql-test/r/innodb_mysql.result
        Fix for bug#47963: Wrong results when index is used
          - test result.
     @ mysql-test/t/innodb_mysql.test
        Fix for bug#47963: Wrong results when index is used
          - test case.
     @ sql/item.cc
        Fix for bug#47963: Wrong results when index is used
          - comparing DATETIMEs as strings we must trim trailing 0's in the 
        microsecond part to ensure
        'YYYY-MM-DD HH:MM:SS.000' == 'YYYY-MM-DD HH:MM:SS'

    modified:
      mysql-test/r/innodb_mysql.result
      mysql-test/t/innodb_mysql.test
      sql/item.cc
=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result	2009-10-05 13:16:27 +0000
+++ b/mysql-test/r/innodb_mysql.result	2009-10-13 04:43:27 +0000
@@ -2209,4 +2209,46 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRI
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index	NULL	PRIMARY	4	NULL	128	Using where
 DROP TABLE t1;
+#
+# Bug #47963: Wrong results when index is used
+#
+CREATE TABLE t1(
+a VARCHAR(5) NOT NULL, 
+b VARCHAR(5) NOT NULL,
+c DATETIME NOT NULL,
+KEY (c) 
+) ENGINE=InnoDB;
+INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00');
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001';
+a	b	c
+TEST	TEST	2009-10-09 00:00:00
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
+a	b	c
+EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND 
+c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+DROP TABLE t1;
 End of 5.1 tests

=== modified file 'mysql-test/t/innodb_mysql.test'
--- a/mysql-test/t/innodb_mysql.test	2009-07-07 12:52:34 +0000
+++ b/mysql-test/t/innodb_mysql.test	2009-10-13 04:43:27 +0000
@@ -461,4 +461,33 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRI
 
 DROP TABLE t1;
 
+--echo #
+--echo # Bug #47963: Wrong results when index is used
+--echo #
+CREATE TABLE t1(
+  a VARCHAR(5) NOT NULL, 
+  b VARCHAR(5) NOT NULL,
+  c DATETIME NOT NULL,
+  KEY (c) 
+) ENGINE=InnoDB;
+INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00');
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001';
+SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
+EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND 
+  c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00';
+DROP TABLE t1;
+
+
 --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 04:43:27 +0000
@@ -6900,17 +6900,37 @@ int stored_field_cmp_to_item(Field *fiel
     /*
       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.
+      A DATE converted to string is 10 (MAX_DATE_WIDTH) characters, 
+      and a DATETIME converted to string is 19 (MAX_DATETIME_WIDTH) characters.
     */
     field_type= field->type();
+    uint32 item_length= item_result->length();
     if (field_type == MYSQL_TYPE_DATE &&
-        item_result->length() == 19)
+        item_length == MAX_DATETIME_WIDTH)
       field_tmp.append(" 00:00:00");
-    else if (field_type == MYSQL_TYPE_DATETIME &&
-             item_result->length() == 10)
-      item_result->append(" 00:00:00");
-
+    else if (field_type == MYSQL_TYPE_DATETIME)
+    {
+      if (item_length == MAX_DATE_WIDTH)
+        item_result->append(" 00:00:00");
+      else if (item_length > MAX_DATETIME_WIDTH)
+      {
+        /*
+          We don't store microsecond part of DATETIME in field
+          but item_result contains it. As we compare DATETIMEs as strings
+          we must trim trailing 0's in item_result's microsecond part
+          to ensure "YYYY-MM-DD HH:MM:SS" == "YYYY-MM-DD HH:MM:SS.0000"
+        */
+        char *end= (char *) item_result->ptr() + item_length - 1;
+        /* Trim trailing 0's */
+        while (*end == '0')
+          end--;
+        /* Trim '.' if no microseconds */
+        if (*end == '.')
+          end--;
+        DBUG_ASSERT(end - item_result->ptr() + 1 >= MAX_DATETIME_WIDTH);
+        item_result->length(end - item_result->ptr() + 1);
+      }
+    }
     return stringcmp(&field_tmp,item_result);
   }
   if (res_type == INT_RESULT)


Attachment: [text/bzr-bundle] bzr/ramil@mysql.com-20091018162655-z4dlolfx5s0zem8l.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (ramil:3182) Bug#47963Ramil Kalimullin18 Oct