Bug #15308 | Problem of Order with Enum Column in Primary Key | ||
---|---|---|---|
Submitted: | 29 Nov 2005 10:59 | Modified: | 20 Jun 2010 0:43 |
Reporter: | Didier G. | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: InnoDB storage engine | Severity: | S3 (Non-critical) |
Version: | 5.0.16/5.0.17 BK | OS: | Linux (Debian 2.6/Linux Suse) |
Assigned to: | CPU Architecture: | Any |
[29 Nov 2005 10:59]
Didier G.
[29 Nov 2005 14:35]
MySQL Verification Team
This bug not happend on 4.1.XX and only affects InnODB engine on 5.0.17. miguel@hegel:~/dbs/5.0> bin/mysql -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 to server version: 5.0.17-debug Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> create database db7; Query OK, 1 row affected (0.04 sec) mysql> use db7 Database changed mysql> CREATE TABLE `findrecord` ( -> `ind` enum('0','1','2') NOT NULL default '0', -> `string1` varchar(250) NOT NULL, -> PRIMARY KEY (`ind`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.01 sec) mysql> mysql> INSERT INTO `findrecord` VALUES ('1', ''); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO `findrecord` VALUES ('2', ''); Query OK, 1 row affected (0.01 sec) mysql> mysql> SELECT * FROM `findrecord` ORDER BY string1; ERROR 1032 (HY000): Can't find record in 'findrecord' mysql> mysql> ALTER TABLE `findrecord` ADD INDEX ( `string1` ); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM `findrecord` ORDER BY string1; +-----+---------+ | ind | string1 | +-----+---------+ | 1 | | | 2 | | +-----+---------+ 2 rows in set (0.00 sec) mysql> ALTER TABLE `findrecord` ADD `string2` VARCHAR( 250 ) NOT NULL ; Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM `findrecord` ORDER BY string2; ERROR 1032 (HY000): Can't find record in 'findrecord' mysql> mysql> ALTER TABLE `findrecord` CHANGE `ind` `ind` TINYINT NOT NULL DEFAULT '0'; Query OK, 2 rows affected (0.04 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> mysql> SELECT * FROM `findrecord` ORDER BY string2; +-----+---------+---------+ | ind | string1 | string2 | +-----+---------+---------+ | 2 | | | | 3 | | | +-----+---------+---------+ 2 rows in set (0.01 sec) miguel@hegel:~/dbs/5.0> bin/mysql -uroot db7 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 to server version: 5.0.17-debug Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> CREATE TABLE `findrecord` ( -> `ind` enum('0','1','2') NOT NULL default '0', -> `string1` varchar(250) NOT NULL, -> PRIMARY KEY (`ind`) -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.01 sec) mysql> mysql> INSERT INTO `findrecord` VALUES ('1', ''); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO `findrecord` VALUES ('2', ''); Query OK, 1 row affected (0.01 sec) mysql> mysql> SELECT * FROM `findrecord` ORDER BY string1; +-----+---------+ | ind | string1 | +-----+---------+ | 1 | | | 2 | | +-----+---------+ 2 rows in set (0.00 sec) miguel@hegel:~/dbs/4.1> bin/mysql -uroot db7 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 to server version: 4.1.16-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> CREATE TABLE `findrecord` ( -> `ind` enum('0','1','2') NOT NULL default '0', -> `string1` varchar(250) NOT NULL, -> PRIMARY KEY (`ind`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.04 sec) mysql> mysql> INSERT INTO `findrecord` VALUES ('1', ''); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO `findrecord` VALUES ('2', ''); Query OK, 1 row affected (0.00 sec) mysql> mysql> SELECT * FROM `findrecord` ORDER BY string1; +-----+---------+ | ind | string1 | +-----+---------+ | 1 | | | 2 | | +-----+---------+ 2 rows in set (0.00 sec)
[29 Nov 2005 14:58]
Didier G.
So do I have to come back to a 4.1 version ? or remain in 5.015? .... what are you planning to do?
[29 Nov 2005 15:15]
Didier G.
Is it a "ipod grade" bug?
[29 Nov 2005 16:20]
Heikki Tuuri
Hi! I will look at this in the next hour. Regards, Heikki
[29 Nov 2005 17:40]
Heikki Tuuri
Jan, the reason for the bug is that in: } else { /* Here we handle all other data types except the true VARCHAR, BLOB and TEXT. Note that the column value we store may be also in a column prefix index. */ CHARSET_INFO* cs; ulint len; const mysql_byte* src_start; int error=0; if (is_null) { buff += key_part->length; continue; } cs = key_part->field->charset(); src_start = record + key_part->offset; if (key_part->length > 0 && cs->mbmaxlen > 1) { len = (ulint) cs->cset->well_formed_len(cs, (const char *) src_start, (const char *) src_start + key_part->le\ ngth, key_part->length / cs->mbmaxlen, &error); } else { len = key_part->length; } memcpy(buff, src_start, len); buff+=len; /* Pad the unused space with spaces */ if (len < key_part->length) { len = key_part->length - len; memset(buff, ' ', len); buff+=len; } } you are accessing key_part->field->charset() even though the type may not be a string type! I checked that for an INT, charset->mb_maxlen == 1, while for an ENUM, charset->mb_maxlen == 3! That is, MySQL thinks the ENUM is a UTF-8 string though it really is stored in a binary format. But it might as well crash since charset is not a sensible attribute for an INT. Fix: only if: (mysql_type == MYSQL_TYPE_VAR_STRING || mysql_type == MYSQL_TYPE_STRING || mysql_type == MYSQL_TYPE_BIT) && !(field->real_type() == FIELD_TYPE_ENUM || field->real_type() == FIELD_TYPE_SET)) do access key_part->field->charset(). Otherwise, do not look at the charset! Check inside gdb that MYSQL_TYPE_BIT has a sensible charset. Check it separately in 4.1 and 5.0. Regards, Heikki I have derived string types from: ha_innodb.cc: if (field->real_type() == FIELD_TYPE_ENUM || field->real_type() == FIELD_TYPE_SET) { /* MySQL has field->type() a string type for these, but the data is actually internally stored as an unsigned integer code! */ *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned flag set to zero, even though internally this is an unsigned integer type */ return(DATA_INT); } switch (field->type()) { /* NOTE that we only allow string types in DATA_MYSQL and DATA_VARMYSQL */ case MYSQL_TYPE_VAR_STRING: /* old <= 4.1 VARCHAR */ case MYSQL_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */ if (field->binary()) { return(DATA_BINARY); } else if (strcmp( field->charset()->name, "latin1_swedish_ci") == 0) { return(DATA_VARCHAR); } else { return(DATA_VARMYSQL); } case MYSQL_TYPE_BIT: case MYSQL_TYPE_STRING: if (field->binary()) { return(DATA_FIXBINARY); } else if (strcmp( field->charset()->name, "latin1_swedish_ci") == 0) { return(DATA_CHAR); } else { return(DATA_MYSQL); } case FIELD_TYPE_NEWDECIMAL: return(DATA_FIXBINARY);
[29 Nov 2005 17:43]
Heikki Tuuri
Jan, this bug came from the bug fix of http://bugs.mysql.com/bug.php?id=14056 It is not yet in any published 4.1 version. Fix this quickly, so that it does not get into any 4.1 release! Regards, Heikki
[30 Nov 2005 6:29]
Jan Lindström
Heikki, bug #14056 is not fixed on 4.1. Should it be fixed there also ?
[30 Nov 2005 8:06]
Jan Lindström
Bit type seems to have correct charset information, below information from gdb: Breakpoint 1, ha_innobase::store_key_val_for_row (this=0x8c72930, keynr=0, buff=0x8c72b58 '¥' <repeats 16 times>, "test", buff_len=1, record=0x8c5a748 "") at ha_innodb.cc:2842 2842 KEY* key_info = table->key_info + keynr; (gdb) next 2843 KEY_PART_INFO* key_part = key_info->key_part; (gdb) 2844 KEY_PART_INFO* end = key_part + key_info->key_parts; (gdb) 2845 char* buff_start = buff; (gdb) 2852 DBUG_ENTER("store_key_val_for_row"); (gdb) 2879 bzero(buff, buff_len); (gdb) 2881 for (; key_part != end; key_part++) { (gdb) 2882 is_null = FALSE; (gdb) 2884 if (key_part->null_bit) { (gdb) 2895 field = key_part->field; (gdb) 2896 mysql_type = field->type(); (gdb) 2898 if (mysql_type == MYSQL_TYPE_VARCHAR) { (gdb) 2956 } else if (mysql_type == FIELD_TYPE_TINY_BLOB (gdb) 3025 int error=0; (gdb) 3027 if (is_null) { (gdb) 3037 if (mysql_type == MYSQL_TYPE_VAR_STRING (gdb) 3043 cs = key_part->field->charset(); (gdb) 3044 src_start = record + key_part->offset; (gdb) p *cs $1 = {number = 63, primary_number = 0, binary_number = 0, state = 817, csname = 0x851d053 "binary", name = 0x851d053 "binary", comment = 0x851d05a "", tailoring = 0x0, ctype = 0x86353a0 "", to_lower = 0x86354c0 "", to_upper = 0x86354c0 "", sort_order = 0x0, contractions = 0x0, sort_order_big = 0x0, tab_to_uni = 0x0, tab_from_uni = 0x0, caseinfo = 0x86188a0, state_map = 0x86501a0 "\022\001\001\001\001\001\001\001\001\032\032\032\032\032", '\001' <repeats 18 times>, "\032\b!\v\002\001\021\n\001\001\025\001\001\001\020\024\016\016\016\016\016\016\016\016\016\016\027\026\t\b\b\001\030\002\037", '\002' <repeats 11 times>, " \002\002\002\002\002\002\002\002\002\036\002\002\001\023\001\001\002\033\002\037", '\002' <repeats 11 times>, " \002\002\002\002\002\002\002\002\002\036\002\002\001\021", '\001' <repeats 75 times>..., ident_map = 0x86502a0 "", strxfrm_multiply = 1, caseup_multiply = 1 '\001', casedn_multiply = 1 '\001', mbminlen = 1, mbmaxlen = 1, min_sort_char = 0, max_sort_char = 255, pad_char = 0 '\0', escape_with_backslash_is_dangerous = 0 '\0', cset = 0x8635640, coll = 0x8635600} (gdb) p mysql_type $2 = MYSQL_TYPE_BIT Regards, Jan
[30 Nov 2005 11:21]
Heikki Tuuri
Jan, good luck that this bug did not get into any 4.1 version. But http://bugs.mysql.com/bug.php?id=14056 should be fixed also in the 4.1 tree. Regards, Heikki
[1 Dec 2005 11:58]
Jan Lindström
Fix for 5.0 proposed.
[17 Jan 2006 16:18]
Alexander Ivanov
Fixed in 5.0.19.
[18 Jan 2006 0:11]
Mike Hillyer
Added note to 5.0.19 changelog: <listitem> <para> Performing an <literal>ORDER BY</literal> on an indexed <literal>ENUM</literal> column returned error. (Bug #15308) </para> </listitem>
[5 May 2010 15:23]
Bugs System
Pushed into 5.1.47 (revid:joro@sun.com-20100505145753-ivlt4hclbrjy8eye) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)
[6 May 2010 1:44]
Paul DuBois
Push resulted from incorporation of InnoDB tree. No changes pertinent to this bug. Re-closing.
[28 May 2010 6:04]
Bugs System
Pushed into mysql-next-mr (revid:alik@sun.com-20100524190136-egaq7e8zgkwb9aqi) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (pib:16)
[28 May 2010 6:32]
Bugs System
Pushed into 6.0.14-alpha (revid:alik@sun.com-20100524190941-nuudpx60if25wsvx) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)
[28 May 2010 7:00]
Bugs System
Pushed into 5.5.5-m3 (revid:alik@sun.com-20100524185725-c8k5q7v60i5nix3t) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)
[29 May 2010 22:53]
Paul DuBois
Push resulted from incorporation of InnoDB tree. No changes pertinent to this bug. Re-closing.
[17 Jun 2010 12:08]
Bugs System
Pushed into 5.1.47-ndb-7.0.16 (revid:martin.skold@mysql.com-20100617114014-bva0dy24yyd67697) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)
[17 Jun 2010 12:54]
Bugs System
Pushed into 5.1.47-ndb-6.2.19 (revid:martin.skold@mysql.com-20100617115448-idrbic6gbki37h1c) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)
[17 Jun 2010 13:35]
Bugs System
Pushed into 5.1.47-ndb-6.3.35 (revid:martin.skold@mysql.com-20100617114611-61aqbb52j752y116) (version source revid:vasil.dimov@oracle.com-20100331130613-8ja7n0vh36a80457) (merge vers: 5.1.46) (pib:16)