Bug #70732 | hex-literals in querys | ||
---|---|---|---|
Submitted: | 26 Oct 2013 14:17 | Modified: | 1 Nov 2013 10:25 |
Reporter: | Nick Icanhas | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Data Types | Severity: | S3 (Non-critical) |
Version: | 5.5, 5.6 | OS: | Linux (UBUNTU 12.4) |
Assigned to: | CPU Architecture: | Any | |
Tags: | bit operations, Calculation, hex literals |
[26 Oct 2013 14:17]
Nick Icanhas
[29 Oct 2013 18:49]
MySQL Verification Team
For me making addition operations (including 0) on the largest 64-bit unsigned integer is not a bug. However, the queries of the type: SELECT 0x20000000000000 + 1; and similar are definitely a bug, although not a serious one at all. This is due to the various allowed ways of entering complex character set strings. CAST() function is, of course, a very simple workaround.
[1 Nov 2013 10:25]
Nick Icanhas
Thanks for the feedback, I wonder whether you did notice that the highest “64-bit signed integer” does not have 64-bit precision when used in mathematical context. mysql> SELECT 0xFFFFFFFFFFFFFFFF + 0; +------------------------+ | 0xFFFFFFFFFFFFFFFF + 0 | +------------------------+ | 18446744073709552000 | +------------------------+ mysql> SELECT CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED); +--------------------------------------+ | CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) | +--------------------------------------+ | 18446744073709551615 | +--------------------------------------+ According to the manual and to your own interpretation, it should come with 64-bit precision, but it doesn't. Of course the significance for this bug is low, if you assume that people will do maths with big integers using hex-literals. (why should they in the first place ?). I was more concerned about operations on the bit level when some calculation is involved as well. Take for instance some arbitrary hex-literal like 0x0FFFFFFFFFFFFFFE. Here we see instantly that the first four and the last bit are not set. Now some bold programmer might come to mind to switch the last bit by adding one (1) to the hex-literal and as he also wants the second four bits to be unset he decides to to something like this: SELECT (0x0FFFFFFFFFFFFFFE + 1) >> 4 Of course the right operator would be a bit OR ( | ) instead of the + but this involves pressing two keys and we know how lazy programmers tend to be. So he gets: mysql> SELECT (0x0FFFFFFFFFFFFFFE + 1) >> 4; +-------------------------------+ | (0x0FFFFFFFFFFFFFFE + 1) >> 4 | +-------------------------------+ | 72057594037927936 | +-------------------------------+ this is a small difference in decimal notation (72057594037927935 is correct) but a very huge one if you look at the bits: 0x00FFFFFFFFFFFFFF vs. 0x100000000000000 Now as only few people use hex-literals for calculation there might be quite a few that use them for bit operations. A container with 64 different yes/no values comes can be quite handy at times. If you can even see which bits are set, like this is the case with hex notation (some experience assumed) than the most natural way is to use hex-literals. Of course the CAST function is a possible workaround but the problem is, that you would never use it intuitively before you encounter the problem above. Moreover by the way the conversion from hex string to number is implemented, it yields, more often than not, correct results, thus misleading the programmers into thinking, that in numeric context the conversion will be to a 64-bit integer and even the manual encourages this belief. Btw., a faster workaround than the cast to unsigned is: mysql> SELECT 0xFFFFFFFFFFFFFFFF >> 0; +-------------------------+ | 0xFFFFFFFFFFFFFFFF >> 0 | +-------------------------+ | 18446744073709551615 | +-------------------------+ This all said, I think that there is a potential to break real world applications and that the significance of the bug is much higher than “not serious at all”.
[27 Oct 2016 7:42]
MySQL Verification Team
FWIW, current trunk tells us : mysql> SELECT 0xFFFFFFFFFFFFFFFF + 0; +------------------------+ | 0xFFFFFFFFFFFFFFFF + 0 | +------------------------+ | 18446744073709551615 | +------------------------+ 1 row in set (0.00 sec) mysql> SELECT 0x20000000000000 + 1; +----------------------+ | 0x20000000000000 + 1 | +----------------------+ | 9007199254740993 | +----------------------+ 1 row in set (0.00 sec) mysql> SELECT 0x20000000000000 + 2; +----------------------+ | 0x20000000000000 + 2 | +----------------------+ | 9007199254740994 | +----------------------+ 1 row in set (0.00 sec) mysql> SELECT 0x20000000000000 + 1; +----------------------+ | 0x20000000000000 + 1 | +----------------------+ | 9007199254740993 | +----------------------+ 1 row in set (0.00 sec) mysql> SELECT 0xFFFFFFFFFFFFFFFF + 0; +------------------------+ | 0xFFFFFFFFFFFFFFFF + 0 | +------------------------+ | 18446744073709551615 | +------------------------+ 1 row in set (0.00 sec) mysql> SELECT CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED); +--------------------------------------+ | CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) | +--------------------------------------+ | 18446744073709551615 | +--------------------------------------+ 1 row in set (0.00 sec) mysql> SELECT (0x0FFFFFFFFFFFFFFE + 1) >> 4 -> ; +-------------------------------+ | (0x0FFFFFFFFFFFFFFE + 1) >> 4 | +-------------------------------+ | 72057594037927935 | +-------------------------------+ 1 row in set (0.00 sec) mysql> SELECT (0x0FFFFFFFFFFFFFFE + 1) >> 4; +-------------------------------+ | (0x0FFFFFFFFFFFFFFE + 1) >> 4 | +-------------------------------+ | 72057594037927935 | +-------------------------------+ 1 row in set (0.00 sec) mysql> SELECT 0xFFFFFFFFFFFFFFFF >> 0; +-------------------------+ | 0xFFFFFFFFFFFFFFFF >> 0 | +-------------------------+ | 18446744073709551615 | +-------------------------+ 1 row in set (0.00 sec) mysql> select version(); +-----------+ | version() | +-----------+ | 8.0.1-dmr | +-----------+ 1 row in set (0.00 sec)