#At file:///home/lb200670/mysql/40950/ based on revid:hky@stripped
3069 lars-erik.bjork@stripped 2009-03-23
This is a patch for bug#40950 Falcon indexes broken for unsigned bigint
As explained in the bug report, the problem is that Falcon does not find the value in the index if the sign bit is set. This is because the value is intepreted as negative.
The way I have fixed this is by encoding unsigned bigint (MYSQL_TYPE_LONGLONG) using BigInt instead of int64. I have also changed StorageDatabase::getSegmentValue accordingly to create working index values.
added:
mysql-test/suite/falcon/r/falcon_bug_40950.result
mysql-test/suite/falcon/t/falcon_bug_40950.test
modified:
storage/falcon/BigInt.cpp
storage/falcon/BigInt.h
storage/falcon/StorageDatabase.cpp
storage/falcon/Value.cpp
storage/falcon/ha_falcon.cpp
per-file messages:
mysql-test/suite/falcon/r/falcon_bug_40950.result
The expected result of the test
mysql-test/suite/falcon/t/falcon_bug_40950.test
A test file testing the patch
storage/falcon/BigInt.cpp
Added a method for setting the value of a BigInt from an uint64, changed a call to BigInt::set accordingly
storage/falcon/BigInt.h
Added a method for setting the value of a BigInt from an uint64
storage/falcon/StorageDatabase.cpp
Altered StorageDatabase::getSegment value to use BigInt in the case of KEY_FORMAT_ULONGLONG
storage/falcon/Value.cpp
Specified int64, to use the correct method
storage/falcon/ha_falcon.cpp
Changed StorageInterface::encodeRecord to encode unsigned bigint (MYSQL_TYPE_LONGLONG) using BigInt instead of int64. Changed StorageInterface::decodeRecord accoringly.
=== added file 'mysql-test/suite/falcon/r/falcon_bug_40950.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_40950.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_40950.result 2009-03-23 17:30:40 +0000
@@ -0,0 +1,98 @@
+*** Bug #40950 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (s1 bigint unsigned, key (s1));
+INSERT INTO t1 VALUES (9),(10),(11),(12),(13),(14);
+SELECT * FROM t1;
+s1
+9
+10
+11
+12
+13
+14
+SELECT * FROM t1 WHERE s1 < 1.65025801745927e+19;
+s1
+9
+10
+11
+12
+13
+14
+INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF), (0x8FFFFFFFFFFFFFFF),
+(0xCFFFFFFFFFFFFFFF), (0xFFFFFFFFFFFFFFFF);
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 1;
+hex(s1)
+9
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 2;
+hex(s1)
+9
+A
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 3;
+hex(s1)
+9
+A
+B
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 4;
+hex(s1)
+9
+A
+B
+C
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 5;
+hex(s1)
+9
+A
+B
+C
+D
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 6;
+hex(s1)
+9
+A
+B
+C
+D
+E
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 7;
+hex(s1)
+9
+A
+B
+C
+D
+E
+7FFFFFFFFFFFFFFF
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 8;
+hex(s1)
+9
+A
+B
+C
+D
+E
+7FFFFFFFFFFFFFFF
+8FFFFFFFFFFFFFFF
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 9;
+hex(s1)
+9
+A
+B
+C
+D
+E
+7FFFFFFFFFFFFFFF
+8FFFFFFFFFFFFFFF
+CFFFFFFFFFFFFFFF
+SELECT hex(s1) FROM t1 WHERE s1 > 12;
+hex(s1)
+D
+E
+7FFFFFFFFFFFFFFF
+8FFFFFFFFFFFFFFF
+CFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF
+SELECT count(*) FROM t1;
+count(*)
+10
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_40950.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_40950.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_40950.test 2009-03-23 17:30:40 +0000
@@ -0,0 +1,47 @@
+--source include/have_falcon.inc
+
+#
+# Bug #40950: Falcon indexes broken for unsigned bigint
+#
+--echo *** Bug #40950 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+
+CREATE TABLE t1 (s1 bigint unsigned, key (s1));
+INSERT INTO t1 VALUES (9),(10),(11),(12),(13),(14);
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE s1 < 1.65025801745927e+19;
+INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF), (0x8FFFFFFFFFFFFFFF),
+(0xCFFFFFFFFFFFFFFF), (0xFFFFFFFFFFFFFFFF);
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 1;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 2;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 3;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 4;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 5;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 6;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 7;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 8;
+SELECT hex(s1) FROM t1 ORDER BY s1 LIMIT 9;
+SELECT hex(s1) FROM t1 WHERE s1 > 12;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
=== modified file 'storage/falcon/BigInt.cpp'
--- a/storage/falcon/BigInt.cpp 2007-09-24 10:56:44 +0000
+++ b/storage/falcon/BigInt.cpp 2009-03-23 17:30:40 +0000
@@ -112,6 +112,22 @@ void BigInt::set(int64 value, int valueS
}
}
+void BigInt::set(uint64 value, int valueScale)
+{
+ scale = valueScale;
+ neg = false;
+ length = 0;
+
+ if (value)
+ {
+ words[length++] = LOW_WORD(value);
+ BigWord highWord = HIGH_WORD(value);
+
+ if (highWord)
+ words[length++] = highWord;
+ }
+}
+
void BigInt::subtract(int index, BigWord value)
{
while (value)
@@ -728,7 +744,7 @@ int BigInt::divide(const BigInt* dividen
void BigInt::buildPowerTable()
{
BigInt* bigInt = ::new BigInt;
- bigInt->set(powersOfTen[9], 0);
+ bigInt->set((int64)powersOfTen[9], 0);
powerTable[9] = bigInt;
for (int i = 10; i < maxPowerOfTen; i++)
=== modified file 'storage/falcon/BigInt.h'
--- a/storage/falcon/BigInt.h 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/BigInt.h 2009-03-23 17:30:40 +0000
@@ -62,6 +62,7 @@ public:
void subtract(int index, BigWord value);
void set(int64 value, int scale=0);
+ void set(uint64 value, int scale=0);
void set(BigInt *bigInt);
void setString(int stringLength, const char* str);
void getString(int bufferLength, char* buffer);
=== modified file 'storage/falcon/StorageDatabase.cpp'
--- a/storage/falcon/StorageDatabase.cpp 2009-03-10 08:33:34 +0000
+++ b/storage/falcon/StorageDatabase.cpp 2009-03-23 17:30:40 +0000
@@ -1004,6 +1004,24 @@ int StorageDatabase::getSegmentValue(Sto
break;
case KEY_FORMAT_ULONGLONG:
+ {
+ uint64 temp = (uint64)
+ ((uint64)(((uint32) ((UCHAR) ptr[0])) +
+ (((uint32) ((UCHAR) ptr[1])) << 8) +
+ (((uint32) ((UCHAR) ptr[2])) << 16) +
+ (((uint32) ((UCHAR) ptr[3])) << 24)) +
+ (((uint64)(((uint32) ((UCHAR) ptr[4])) +
+ (((uint32) ((UCHAR) ptr[5])) << 8) +
+ (((uint32) ((UCHAR) ptr[6])) << 16) +
+ (((uint32) ((UCHAR) ptr[7])) << 24)))
+ << 32));
+
+ BigInt bigInt;
+ bigInt.set(temp);
+ value->setValue(&bigInt);
+ }
+ break;
+
case KEY_FORMAT_LONGLONG:
{
int64 temp = (int64)
=== modified file 'storage/falcon/Value.cpp'
--- a/storage/falcon/Value.cpp 2008-11-24 08:56:29 +0000
+++ b/storage/falcon/Value.cpp 2009-03-23 17:30:40 +0000
@@ -1853,11 +1853,11 @@ void Value::getBigInt(BigInt *bigInt)
break;
case Short:
- bigInt->set(data.smallInt, -scale);
+ bigInt->set((int64)data.smallInt, -scale);
break;
case Int32:
- bigInt->set(data.integer, -scale);
+ bigInt->set((int64)data.integer, -scale);
break;
case Int64:
=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp 2009-03-10 12:37:26 +0000
+++ b/storage/falcon/ha_falcon.cpp 2009-03-23 17:30:40 +0000
@@ -3001,7 +3001,6 @@ void StorageInterface::encodeRecord(ucha
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
@@ -3009,6 +3008,28 @@ void StorageInterface::encodeRecord(ucha
dataStream->encodeInt64(field->val_int());
break;
+ case MYSQL_TYPE_LONGLONG:
+ {
+
+ int64 temp = field->val_int();
+
+ // If this is unsigned, encode it as a BigInt
+ // to support values with the MSB set
+
+ if (((Field_num*)field)->unsigned_flag)
+ {
+ BigInt bigInt;
+ bigInt.set((uint64)temp);
+ dataStream->encodeBigInt(&bigInt);
+ }
+ else
+ {
+ dataStream->encodeInt64(temp);
+ }
+
+ }
+ break;
+
case MYSQL_TYPE_YEAR:
// Have to use the ptr directly to get the same number for
// both two and four digit YEAR
@@ -3207,7 +3228,6 @@ void StorageInterface::decodeRecord(ucha
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
@@ -3216,6 +3236,25 @@ void StorageInterface::decodeRecord(ucha
((Field_num*)field)->unsigned_flag);
break;
+ case MYSQL_TYPE_LONGLONG:
+ {
+
+ // This value is unsigned and has been handled
+ // specially in encodeRecord() to support values
+ // with the MSB set.
+ if (dataStream->type == edsTypeBigInt)
+ {
+ int64 value = dataStream->bigInt.getInt();
+ field->store(value, ((Field_num*)field)->unsigned_flag);
+ }
+ else
+ {
+ field->store(dataStream->getInt64(),
+ ((Field_num*)field)->unsigned_flag);
+ }
+ }
+ break;
+
case MYSQL_TYPE_YEAR:
// Must add 1900 to give Field_year::store the value it
// expects. See also case 'MYSQL_TYPE_YEAR' in encodeRecord()
Thread |
---|
• bzr commit into mysql-6.0-falcon-team branch (lars-erik.bjork:3069) Bug#40950 | lars-erik.bjork | 23 Mar |