Bug #1723 | Assigning negative value to bigint unsigned records (maxval_bigint - value) | ||
---|---|---|---|
Submitted: | 31 Oct 2003 4:14 | Modified: | 12 Nov 2003 1:06 |
Reporter: | [ name withheld ] | Email Updates: | |
Status: | Won't fix | Impact on me: | |
Category: | MySQL Server | Severity: | S3 (Non-critical) |
Version: | 4.0.13-max-log | OS: | Linux (Linux 2.4.18) |
Assigned to: | CPU Architecture: | Any |
[31 Oct 2003 4:14]
[ name withheld ]
[31 Oct 2003 5:06]
[ name withheld ]
This behaviour also works the other way. Trying to find out the minimum of two values with the LEAST()-function results in the previous inserted negative value. An inserted positive value shows an equal result: INSERT INTO bigint_test VALUES(18446744073709550000); SELECT LEAST(1, temp) AS least, temp FROM bigint_test;
[12 Nov 2003 1:06]
Sergei Golubchik
I don't know what we can do here. It's a price for having max possible integer range. If usigned bigint would be in the range [0..9223372036854775807], then we could be able to detect a negative value there and convert it to zero.
[4 Jun 2004 21:13]
Kevin Dooley
The underlying problem seems to be that even though a BIGINT is defined as UNSIGNED, the bit-wise or operator (|) is not treating it as such. Below is an example (using binary numbers to make what's happening a little clearer) that shows what happens when you set the sign (left-most) bit on an INT (32 bits) and a BIGINT (64 bits). I get the same result running MySQL 3.23.56 on RedHat 9, and 4.0.18-nt on Win2K. CREATE TABLE t ( t32 INT UNSIGNED NOT NULL DEFAULT 0, t64 BIGINT UNSIGNED NOT NULL DEFAULT 0 ); INSERT INTO t SET t32=0, t64=0; SELECT LPAD(CONV(t32, 10, 2), 32, "0") AS t32, LPAD(CONV(t64, 10, 2), 64, "0") as t64 FROM t; +----------------------------------+------------------------------------------------------------------+ | t32 | t64 | +----------------------------------+------------------------------------------------------------------+ | 00000000000000000000000000000000 | 0000000000000000000000000000000000000000000000000000000000000000 | +----------------------------------+------------------------------------------------------------------+ UPDATE t SET t32 = t32 | CONV('00100000000000000000000000000000', 2, 10), t64 = t64 | CONV('0010000000000000000000000000000000000000000000000000000000000000', 2, 10); SELECT LPAD(CONV(t32, 10, 2), 32, "0") AS t32, LPAD(CONV(t64, 10, 2), 64, "0") as t64 FROM t; +----------------------------------+------------------------------------------------------------------+ | t32 | t64 | +----------------------------------+------------------------------------------------------------------+ | 00100000000000000000000000000000 | 0010000000000000000000000000000000000000000000000000000000000000 | +----------------------------------+------------------------------------------------------------------+ UPDATE t SET t32 = t32 | CONV('01000000000000000000000000000000', 2, 10), t64 = t64 | CONV('0100000000000000000000000000000000000000000000000000000000000000', 2, 10); SELECT LPAD(CONV(t32, 10, 2), 32, "0") AS t32, LPAD(CONV(t64, 10, 2), 64, "0") as t64 FROM t +----------------------------------+------------------------------------------------------------------+ | t32 | t64 | +----------------------------------+------------------------------------------------------------------+ | 01100000000000000000000000000000 | 0110000000000000000000000000000000000000000000000000000000000000 | +----------------------------------+------------------------------------------------------------------+ # Watch out! Here it comes! UPDATE t SET t32 = t32 | CONV('10000000000000000000000000000000', 2, 10), t64 = t64 | CONV('1000000000000000000000000000000000000000000000000000000000000000', 2, 10); SELECT LPAD(CONV(t32, 10, 2), 32, "0") AS t32, LPAD(CONV(t64, 10, 2), 64, "0") as t64 FROM t; +----------------------------------+------------------------------------------------------------------+ | t32 | t64 | +----------------------------------+------------------------------------------------------------------+ | 11100000000000000000000000000000 | 0111111111111111111111111111111111111111111111111111111111111111 | +----------------------------------+------------------------------------------------------------------+ # This also happens when working with user-defined variables SET @t32 = 0, @t64= 0; SET @t32 = @t32 | CONV('10000000000000000000000000000000', 2, 10), @t64 = @t64 | CONV('1000000000000000000000000000000000000000000000000000000000000000', 2, 10); SELECT LPAD(CONV(@t32, 10, 2), 32, "0") AS '@t32', LPAD(CONV(@t64, 10, 2), 64, "0") as '@t64'; +----------------------------------+------------------------------------------------------------------+ | @t32 | @t64 | +----------------------------------+------------------------------------------------------------------+ | 10000000000000000000000000000000 | 0111111111111111111111111111111111111111111111111111111111111111 | +----------------------------------+------------------------------------------------------------------+ # Interestingly, you can initialize a BIGINT with just the left most bit set, you just can't 'or' it and preserve the other bits... DELETE FROM t; INSERT INTO t SET t32 = CONV('10000000000000000000000000000000', 2, 10), t64 = CONV('1000000000000000000000000000000000000000000000000000000000000000', 2, 10) SELECT LPAD(CONV(t32, 10, 2), 32, "0") AS '@t32', LPAD(CONV(t64, 10, 2), 64, "0") as '@t64' FROM t +----------------------------------+------------------------------------------------------------------+ | @t32 | @t64 | +----------------------------------+------------------------------------------------------------------+ | 10000000000000000000000000000000 | 1000000000000000000000000000000000000000000000000000000000000000 | +----------------------------------+------------------------------------------------------------------+ Kevin B=)x