Hey all, I think this might be a bug, but it’s killing me. I am using MySQL 5.1.41 on an Ubuntu Linux server. I’m trying to write a function to create a random signed BIGINT value. Because the precision of RAND() is too small to generate the full range of possible BIGINT values, I decided to try to combine four 32-bit words using bit operators.
I fired up MySQL Workbench, and tried the following to see if bit shift operators work correctly with negative numbers:
SELECT HEX((0x1ACE - 0x8000) << 0x10);
0x1ACE – 0x8000 is -25906, so if I shift 16 bits to the left, I should be multiplying by 65536, right? The answer I got back was 0xFFFFFFFF9ACE0000, which is the signed representation of -1697775616, or -25906 * 65536. Wunderbar, it works!!!
So my plan was to use that to generate the first 32-bit word of the random signed BIGINT, and use a simple loop to add three more 32-bit words to the value, shifting the bits over four bytes at a time. Excitedly, I started out by putting the following code in my function, using a hard-coded value to test my plan with:
DECLARE x BIGINT;
SET x = (0x1ACE - 0x8000) << 0x10;
If I set the value so that the value being shifted is positive, everything works fine. However, after performing this calculation with a shifted negative value (-25906 in this case), I kept getting that x was 0x7FFFFFFFFFFFFFFF, which is the maximum positive value of a signed 64-bit integer. I’m totally baffled. The exact same operation is generating a totally different result depending on whether it is in a SET operation in a function or a SELECT statement.
So I started messing around with whether x was signed or unsigned and things got really weird. I tried making x unsigned and tried the following:
DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000);
When I did that, I got x equal to zero. Not surprising, since x is unsigned and the result is negative. However, on a lark, I tried this:
DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000) << 0;
To my surprise, x was set to 0xFFFFFFFFFFFF9ACE!
Can someone please help? I’ve been working for hours on a function that does nothing more than efficiently generates a random signed BIGINT, I’m tired, and the more I look at this stuff, the more frustrated I get and the less sense I can make of it. Any help, either in explaining what’s going on here or advice in writing this function so that it consistently works now and, if this is a bug, in later version if it gets fixed, would be greatly appreciated!
Okay, I think I just figured it out. According to the documentation, the bit shift operators result in unsigned 64-bit integers. So when you try:
What is happening is that in order for guid << 0 to return an unsigned integer, it is trying to convert guid from a negative signed integer to an unsigned integer, resulting in 0x7FFFFFFFFFFFFFFF, then shifting it over zero places, which is an identity operation resulting in the same 0x7FFFFFFFFFFFFFFF.
It appears that multiplication (*), however, works correctly on signed and unsigned numbers. I can achieve my desired result by the following: