Bug #34731 | highest possible value for INT erroneously filtered by WHERE | ||
---|---|---|---|
Submitted: | 21 Feb 2008 15:30 | Modified: | 7 Apr 2008 17:30 |
Reporter: | Peter Laursen (Basic Quality Contributor) | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: DML | Severity: | S2 (Serious) |
Version: | 5.0.51a, 5.0.54, 5.1.23 | OS: | Windows (probably any) |
Assigned to: | Tatiana Azundris Nuernberg | CPU Architecture: | Any |
Tags: | qc |
[21 Feb 2008 15:30]
Peter Laursen
[21 Feb 2008 15:36]
Peter Laursen
now .. don't forget to check TINYINT, SMALLINT, BIGINT as well as UNSIGNED option for all!
[21 Feb 2008 16:37]
Valeriy Kravchuk
Thank you for a bug report. Verified just as described: C:\Program Files\MySQL\MySQL Server 5.1\bin>mysql -uroot -proot -P3308 test Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.0.54-enterprise-gpl-nt-log MySQL Enterprise Server (GPL) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> CREATE TABLE `int_simple` ( -> `aa` int(11) NOT NULL, -> `bb` varchar(20) NOT NULL, -> PRIMARY KEY (`aa`) -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; Query OK, 0 rows affected (0.36 sec) mysql> insert into int_simple values(2147483645, 'x'); Query OK, 1 row affected (0.05 sec) mysql> insert into int_simple values(2147483647, 'y'); Query OK, 1 row affected (0.00 sec) mysql> select * from int_simple; +------------+----+ | aa | bb | +------------+----+ | 2147483645 | x | | 2147483647 | y | +------------+----+ 2 rows in set (0.03 sec) mysql> select * from int_simple where aa < 2147483648; +------------+----+ | aa | bb | +------------+----+ | 2147483645 | x | +------------+----+ 1 row in set (0.02 sec)
[21 Feb 2008 16:56]
Peter Laursen
.. and also check if there should be similar issues with lower boundaries and "<" operator!
[21 Feb 2008 17:39]
Peter Laursen
-- finally I was wondering if other datatypes (SET, ENUM) are indirectly affected!
[27 Feb 2008 20:18]
Tatiana Azundris Nuernberg
Only occurs when index is used (aa is PRIMARY KEY in example). Verified as dependent on that condition with MyISAM and InnoDB.
[27 Feb 2008 21:39]
Peter Laursen
I think it also happens if that column is part of a *compound* PK! Just for completenes!
[4 Mar 2008 7:24]
Tatiana Azundris Nuernberg
#0 handler::compare_key (this=0x8d7e6a8, range=0x8d7e720) at handler.cc:2721 #1 0x0831af7d in handler::read_range_first (this=0x8d7e6a8, start_key=0x0, end_key=0x8d99544, eq_range_arg=false, sorted=false) at handler.cc:2660 #2 0x0831b2c0 in handler::read_multi_range_first (this=0x8d7e6a8, found_range_p=0xb5059f70, ranges=0x8d99538, range_count=1, sorted=false, buffer=0x0) at handler.cc:2527 #3 0x082fe75a in QUICK_RANGE_SELECT::get_next (this=0x8d7eba0) at opt_range.cc:6896 #4 0x08315429 in rr_quick (info=0x8d9eb30) at records.cc:224 #5 0x0828b95f in join_init_read_record (tab=0x8d9eaf0) at sql_select.cc:11310 #6 0x0828b223 in sub_select (join=0x8d9d6e0, join_tab=0x8d9eaf0, end_of_records=false) at sql_select.cc:10669 #7 0x08293280 in do_select (join=0x8d9d6e0, fields=0x8d66220, table=0x0, procedure=0x0) at sql_select.cc:10433 #8 0x082a97ea in JOIN::exec (this=0x8d9d6e0) at sql_select.cc:2118 #9 0x082a5723 in mysql_select (thd=0x8d651e8, rref_pointer_array=0x8d662b0, tables=0x8d9d2d0, wild_num=1, fields=@0x8d66220, conds=0x8d9d578, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2156153344, result=0x8d9d6c8, unit=0x8d65f54, select_lex=0x8d6618c) at sql_select.cc:2296 #10 0x082a9afe in handle_select (thd=0x8d651e8, lex=0x8d65efc, result=0x8d9d6c8, setup_tables_done_option=0) at sql_select.cc:257 #11 0x0823d809 in mysql_execute_command (thd=0x8d651e8) at sql_parse.cc:2736 SELECT SQL_NO_CACHE * FROM t1 WHERE indexed < 256; (gdb) print last_range->flag $39 = 9 NO_MIN_RNAGE | NEAR_MAX (gdb) print *start_key $40 = {key = 0x8d9a540 "/¥¥¥¥¥¥¥ÿ·¥¥¥¥¥¥", length = 0, flag = HA_READ_KEY_OR_NEXT} (gdb) print *end_key $41 = {key = 0x8d9a548 "ÿ·¥¥¥¥¥¥", length = 1, flag = HA_READ_BEFORE_KEY} (gdb) print end_key->key[0] $43 = -1 'ÿ' So. key = 255, and thanks to read-before, key_compare_result_on_equal becomes 1 in read_range_first(). When we compare (255 == 255) in handler::compare_key(), we hence return compare_result_on_equal (== 1 for "row_key > range_key"). We could fudge the special case in the range down here certainly, but much more interestingly, when does 256 become 255, and why isn't it eliminated altogether? INSERT behaves as expected: > INSERT INTO t1 VALUES (256,256,'impossible'); Query OK, 1 row affected, 2 warnings INSERT corrects to MAX-TINY and throws warnings. range-key (of 256) is also limited to 255, but throws no warning. Since our cond is now "< 255", our "= 255" is ignored. This produces correct results (key is still corrected to 255, but we use <=), so the "<= 256" cond becomes "<= 255" which selects our "= 255" element: SELECT SQL_NO_CACHE * FROM t1 WHERE indexed <= 256; (gdb) print last_range->flag $49 = 1 <-- NEAR_MAX not set (gdb) print *start_key $50 = {key = 0x8d9a540 "", length = 0, flag = HA_READ_KEY_OR_NEXT} (gdb) print *end_key $51 = {key = 0x8d9a548 "ÿ·¥¥¥¥¥¥", length = 1, flag = HA_READ_AFTER_KEY} Clearing NEAR_MAX manually for the range for "< 256" fixes the behaviour.
[5 Mar 2008 21:23]
Tatiana Azundris Nuernberg
int Field_tiny::store(longlong nr, bool unsigned_val) fails with 1 (overflow, obviously) Hence in get_mm_leaf() @ 4407 err= value->save_in_field_no_warnings(field, 1); if (err > 0 && field->cmp_type() != value->result_type()) err==1, but then since both field and constant are of INT type, we do no error handling and erroneously set some flags. Forcing error handling by using different types like so SELECT SQL_NO_CACHE * FROM t1 WHERE indexed < 256.0; results in NEAR_MAX not being set and the query being executed correctly.
[10 Mar 2008 10:12]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/43666 ChangeSet@1.2595, 2008-03-10 11:12:12+01:00, tnurnberg@mysql.com +3 -0 Bug#34731: highest possible value for INT erroneously filtered by WHERE WHERE f1 < n ignored row if f1 was indexed integer column and f1 = TYPE_MAX ^ n = TYPE_MAX+1. The latter value when treated as TYPE overflowed (obviously). This was not handled, it is now.
[28 Mar 2008 5:41]
Tatiana Azundris Nuernberg
pushed to 5.0.60, 5.1.24-rc in -bugteam
[31 Mar 2008 14:52]
Bugs System
Pushed into 5.0.60
[31 Mar 2008 14:53]
Bugs System
Pushed into 5.1.24-rc
[31 Mar 2008 19:18]
Paul DuBois
Noted in 5.0.60, 5.1.24 changelogs. For an indexed integer column col_name and a value N that is one greater than the maximum value allowed for the data type of col_name, conditions of the form WHERE col_name < N failed to return rows where the value of col_name is N - 1. Resetting report to Patch queued waiting for push into 6.0.x.
[3 Apr 2008 13:01]
Bugs System
Pushed into 6.0.5-alpha
[7 Apr 2008 17:30]
Paul DuBois
Noted in 6.0.5 changelog.