List:Commits« Previous MessageNext Message »
From:lars-erik.bjork Date:March 24 2009 1:31pm
Subject:bzr commit into mysql-6.0-falcon-team branch (lars-erik.bjork:3073) Bug#40950
View as plain text  
#At file:///home/lb200670/mysql/40950/ based on revid:vvaintroub@stripped

 3073 lars-erik.bjork@stripped	2009-03-24
      This is a new 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), with the MSB set, 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, based on the bug report
  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, if the MSB is set
  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, if the MSB is set. 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-24 13:31:43 +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-24 13:31:43 +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-24 13:31:43 +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-24 13:31:43 +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-24 13:31:43 +0000
@@ -1004,6 +1004,36 @@ 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));
+
+			// If the MSB is set, we have to set the
+			// value as a BigInt, if it is not set, we 
+			// can use int64
+
+			if (temp & 0x8000000000000000)
+				{
+				BigInt bigInt;
+				bigInt.set(temp);
+				value->setValue(&bigInt);
+				}
+			else
+				{
+				value->setValue((int64)temp);
+				}
+
+			}
+			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-24 13:31:43 +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-24 13:31:43 +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 the field is unsigned and the MSB is set, 
+					// encode it as a BigInt to support unsigned values 
+					// with the MSB set in the index
+
+					if (((Field_num*)field)->unsigned_flag && (temp & 0x8000000000000000))
+						{
+						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,27 @@ void StorageInterface::decodeRecord(ucha
 								((Field_num*)field)->unsigned_flag);
 					break;
 
+				case MYSQL_TYPE_LONGLONG:
+					{
+					// If the type is edsTypeBigInt, the value is
+					// unsigned and has the MSB set. This case has 
+					// been handled specially in encodeRecord() to 
+					// support unsigned values with the MSB set in
+					// the index
+
+					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:3073) Bug#40950lars-erik.bjork24 Mar