Bug #60786 | For update:Trailing white space not ignored with index, is ignored without index | ||
---|---|---|---|
Submitted: | 7 Apr 2011 0:18 | Modified: | 28 Nov 2019 21:59 |
Reporter: | Ariel S | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: DML | Severity: | S2 (Serious) |
Version: | 5.1.49/5.5 | OS: | Linux (Debian Squeeze) |
Assigned to: | CPU Architecture: | Any | |
Tags: | index update whitespace |
[7 Apr 2011 0:18]
Ariel S
[7 Apr 2011 0:42]
MySQL Verification Team
Thank you for the bug report. C:\DBS>c:\dbs\5.1\bin\mysql -uroot --port=3306 --prompt="mysql 5.1 >" Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.1.57-Win X64-log Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.1 >use test Database changed mysql 5.1 >CREATE TABLE `test_trailing` ( -> `last` varchar(20) NOT NULL, -> `ord` tinyint(2) unsigned zerofill NOT NULL, -> `deleted` timestamp NULL DEFAULT NULL, -> UNIQUE KEY `last` (`last`,`ord`), -> KEY `deleted` (`deleted`) -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.75 sec) mysql 5.1 >INSERT INTO `test_trailing` VALUES ('RUPERD ',01,NULL); Query OK, 1 row affected (0.45 sec) mysql 5.1 >INSERT INTO `test_trailing` VALUES ('RUPERD ',02,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.1 >INSERT INTO `test_trailing` VALUES ('RUPERD',03,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.1 >INSERT INTO `test_trailing` VALUES ('RUPERD ',04,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.1 >INSERT INTO `test_trailing` VALUES ('RUPERD',05,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.1 >SELECT * FROM test_trailing WHERE last = 'RUPERD'; +---------+-----+---------+ | last | ord | deleted | +---------+-----+---------+ | RUPERD | 01 | NULL | | RUPERD | 02 | NULL | | RUPERD | 03 | NULL | | RUPERD | 04 | NULL | | RUPERD | 05 | NULL | +---------+-----+---------+ 5 rows in set (0.07 sec) mysql 5.1 >SELECT * FROM test_trailing FORCE INDEX (last) WHERE last = 'RUPERD'; +---------+-----+---------+ | last | ord | deleted | +---------+-----+---------+ | RUPERD | 01 | NULL | | RUPERD | 02 | NULL | | RUPERD | 03 | NULL | | RUPERD | 04 | NULL | | RUPERD | 05 | NULL | +---------+-----+---------+ 5 rows in set (0.00 sec) mysql 5.1 >UPDATE test_trailing SET deleted = NOW() WHERE last = 'RUPERD'; Query OK, 5 rows affected (0.02 sec) Rows matched: 5 Changed: 5 Warnings: 0 mysql 5.1 >UPDATE test_trailing FORCE INDEX (last) SET deleted = NOW() WHERE last = 'RUPERD'; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql 5.1 >exit Bye C:\DBS>55 C:\DBS>c:\dbs\5.5\bin\mysql -uroot --port=3540 --prompt="mysql 5.5 >" Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.5.12 Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.5 >use test Database changed mysql 5.5 >CREATE TABLE `test_trailing` ( -> `last` varchar(20) NOT NULL, -> `ord` tinyint(2) unsigned zerofill NOT NULL, -> `deleted` timestamp NULL DEFAULT NULL, -> UNIQUE KEY `last` (`last`,`ord`), -> KEY `deleted` (`deleted`) -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.93 sec) mysql 5.5 > mysql 5.5 >INSERT INTO `test_trailing` VALUES ('RUPERD ',01,NULL); Query OK, 1 row affected (0.07 sec) mysql 5.5 >INSERT INTO `test_trailing` VALUES ('RUPERD ',02,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.5 >INSERT INTO `test_trailing` VALUES ('RUPERD',03,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.5 >INSERT INTO `test_trailing` VALUES ('RUPERD ',04,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.5 >INSERT INTO `test_trailing` VALUES ('RUPERD',05,NULL); Query OK, 1 row affected (0.00 sec) mysql 5.5 >SELECT * FROM test_trailing WHERE last = 'RUPERD'; +---------+-----+---------+ | last | ord | deleted | +---------+-----+---------+ | RUPERD | 01 | NULL | | RUPERD | 02 | NULL | | RUPERD | 03 | NULL | | RUPERD | 04 | NULL | | RUPERD | 05 | NULL | +---------+-----+---------+ 5 rows in set (0.10 sec) mysql 5.5 >SELECT * FROM test_trailing FORCE INDEX (last) WHERE last = 'RUPERD'; +---------+-----+---------+ | last | ord | deleted | +---------+-----+---------+ | RUPERD | 01 | NULL | | RUPERD | 02 | NULL | | RUPERD | 03 | NULL | | RUPERD | 04 | NULL | | RUPERD | 05 | NULL | +---------+-----+---------+ 5 rows in set (0.00 sec) mysql 5.5 >UPDATE test_trailing SET deleted = NOW() WHERE last = 'RUPERD'; Query OK, 5 rows affected (0.03 sec) Rows matched: 5 Changed: 5 Warnings: 0 mysql 5.5 >UPDATE test_trailing FORCE INDEX (last) SET deleted = NOW() WHERE last = 'RUPERD'; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql 5.5 >exit Bye
[7 Apr 2011 2:05]
MySQL Verification Team
Just a side note, the testcase requires a sleep between the two updates otherwise it will not work as expected. Then, I'm surprised to see this bug at all! http://dev.mysql.com/doc/refman/5.5/en/index-hints.html says "Index hints are accepted but ignored for UPDATE statements."
[7 Apr 2011 5:11]
Ariel S
I encountered the bug without using index hints. When I ran a query that happened to use the index it occurred, and I couldn't understand why it didn't occur after deleting some rows. I finally figured out it was related to the index. Putting in the hint is just a way to test it, it's not actually necessary in order to trigger the bug.
[7 Apr 2011 8:13]
Peter Laursen
Another side-remark: Is this really correct behavior: SELECT 'RUPERD' = 'RUPERD '; -- returns 1 If so it surprises me! They are two different strings.
[7 Apr 2011 8:27]
Peter Laursen
In my understanding this leads to completely weird and inconsistent behavior when comparing using "=" and "LIKE" operators: SELECT 'a' = 'a'; -- 1 SELECT 'a' LIKE 'a'; -- 1 SELECT 'a' = 'a '; -- 1 SELECT 'a' LIKE 'a '; -- 0 New report?
[20 Nov 2015 8:59]
Roy Lyseng
This behavior: SELECT 'RUPERD' = 'RUPERD '; -- returns 1 is correct: Quoting from manual, section "The CHAR and VARCHAR Types" "All MySQL collations are of type PADSPACE. This means that all CHAR, VARCHAR, and TEXT values in MySQL are compared without regard to any trailing spaces. “Comparison” in this context does not include the LIKE pattern-matching operator, for which trailing spaces are significant. " PAD SPACE is a property defined by the SQL standard. Notice also that the equality operator '=' and LIKE are two different operators: The second operand to LIKE is a pattern string where every character is significant. Section "String Comparison Functions" in the manual explains this: "Per the SQL standard, LIKE performs matching on a per-character basis, thus it can produce results different from the = comparison operator:" and "In particular, trailing spaces are significant, which is not true for CHAR or VARCHAR comparisons performed with the = operator"
[28 Nov 2019 21:59]
Roy Lyseng
Posted by developer: Fixed in 5.7.29. Notice that with the NOPAD collations introduced in 8.0, only two rows will be selected and updated.