Bug #4626 | unsigned bigint / signed bigint | ||
---|---|---|---|
Submitted: | 19 Jul 2004 14:58 | Modified: | 3 Sep 2004 16:09 |
Reporter: | Torsten Bausch | Email Updates: | |
Status: | Won't fix | Impact on me: | |
Category: | MySQL Server | Severity: | S1 (Critical) |
Version: | 4.0.20 | OS: | |
Assigned to: | Antony Curtis | CPU Architecture: | Any |
[19 Jul 2004 14:58]
Torsten Bausch
[20 Jul 2004 13:36]
Aleksey Kishkin
verified on 4.0.20-standard
[12 Aug 2004 0:27]
Antony Curtis
Problems found where comparing signed and unsigned types, ===== mysql-test/t/bigint.test 1.20 vs edited ===== --- 1.20/mysql-test/t/bigint.test 2004-02-04 08:59:14 +00:00 +++ edited/mysql-test/t/bigint.test 2004-08-11 22:36:48 +01:00 @@ -63,3 +63,13 @@ # atof() behaviour is different of different systems. to be fixed in 4.1 #SELECT '0x8000000000000001'+0; +# +# Unsigned bigint / signed bigint comparison failure +# Bug#4626 +# + +CREATE TABLE t1 ( `ID` bigint(20) unsigned NOT NULL default '0', `NAME` varchar(50) default NULL, PRIMARY KEY (`ID`) ) ENGINE=MYISAM; +insert into t1 values (12345678901234567890,'ID greater LONGLONG_MAX (0x7FFFFFFFFFFFFFFF)'), (1,'Test'); +select * from t1 where `ID` > 10; +select * from t1 where `ID` < 0; +drop table t1; ===== mysql-test/r/bigint.result 1.21 vs edited ===== --- 1.21/mysql-test/r/bigint.result 2004-02-04 08:59:14 +00:00 +++ edited/mysql-test/r/bigint.result 2004-08-11 22:37:11 +01:00 @@ -81,3 +81,11 @@ 10000000000000000000 10000000000000000000 drop table t1; +CREATE TABLE t1 ( `ID` bigint(20) unsigned NOT NULL default '0', `NAME` varchar(50) default NULL, PRIMARY KEY (`ID`) ) ENGINE=MYISAM; +insert into t1 values (12345678901234567890,'ID greater LONGLONG_MAX (0x7FFFFFFFFFFFFFFF)'), (1,'Test'); +select * from t1 where `ID` > 10; +ID NAME +12345678901234567890 ID greater LONGLONG_MAX (0x7FFFFFFFFFFFFFFF) +select * from t1 where `ID` < 0; +ID NAME +drop table t1; ===== sql/item.h 1.44 vs edited ===== --- 1.44/sql/item.h 2004-04-28 01:37:44 +01:00 +++ edited/sql/item.h 2004-08-11 22:42:15 +01:00 @@ -21,6 +21,7 @@ struct st_table_list; void item_init(void); /* Init item functions */ +int lex_ulonglong(const char *str,uint length); class Item { Item(const Item &); /* Prevent use of these */ @@ -225,7 +226,10 @@ public: Item_uint(const char *str_arg, uint length) : Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length) {} - Item_uint(uint32 i) :Item_int((longlong) i, 10) {} + Item_uint(uint32 i, uint length=10) :Item_int((longlong) i, length) {} +#ifdef HAVE_LONG_LONG + Item_uint(ulonglong i, uint length=20) :Item_int((longlong) i, length) {} +#endif double val() { return ulonglong2double(value); } String *val_str(String*); void make_field(Send_field *field); @@ -291,6 +295,7 @@ max_length=length; name=(char*) str_value.ptr(); decimals=NOT_FIXED_DEC; + unsigned_flag= lex_ulonglong(str_value.ptr(), str_value.length()); } Item_string(const char *name_par,const char *str,uint length) { @@ -298,11 +303,12 @@ max_length=length; name=(char*) name_par; decimals=NOT_FIXED_DEC; + unsigned_flag= lex_ulonglong(str_value.ptr(), str_value.length()); } ~Item_string() {} enum Type type() const { return STRING_ITEM; } double val() { return atof(str_value.ptr()); } - longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); } + longlong val_int() { return unsigned_flag ? strtoll(str_value.ptr(),(char**) 0,10) : (longlong)strtoull(str_value.ptr(),(char**) 0,10); } String *val_str(String*) { return (String*) &str_value; } bool save_in_field(Field *field, bool no_conversions); void make_field(Send_field *field); @@ -311,7 +317,7 @@ bool eq(const Item *item, bool binary_cmp) const; Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); } String *const_string() { return &str_value; } - inline void append(char *str,uint length) { str_value.append(str,length); } + inline void append(char *str,uint length) { str_value.append(str,length); unsigned_flag= lex_ulonglong(str_value.ptr(), str_value.length()); } void print(String *str); unsigned int size_of() { return sizeof(*this);} }; @@ -462,6 +468,19 @@ Item *ref; public: Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg) + {} + bool save_in_field(Field *field, bool no_conversions) + { + return ref->save_in_field(field, no_conversions); + } + unsigned int size_of() { return sizeof(*this);} +}; + +class Item_uint_with_ref :public Item_uint +{ + Item *ref; +public: + Item_uint_with_ref(ulonglong i, Item *ref_arg) :Item_uint(i), ref(ref_arg) {} bool save_in_field(Field *field, bool no_conversions) { ===== sql/item_cmpfunc.cc 1.62 vs edited ===== --- 1.62/sql/item_cmpfunc.cc 2004-06-07 11:38:32 +01:00 +++ edited/sql/item_cmpfunc.cc 2004-08-11 22:46:36 +01:00 @@ -51,8 +51,15 @@ if (!(*item)->save_in_field(field, 1) && !((*item)->null_value)) { - Item *tmp=new Item_int_with_ref(field->val_int(), *item); - if (tmp) + Item *tmp; + if ((*item)->unsigned_flag) + { + tmp= new Item_uint_with_ref((ulonglong)field->val_int(), *item); + tmp->unsigned_flag= 1; + } + else + tmp= new Item_int_with_ref(field->val_int(), *item); + if (tmp) *item=tmp; return 1; // Item was replaced } @@ -159,8 +166,17 @@ if (!args[1]->null_value) { null_value=0; - if (val1 < val2) return -1; + longlong x1=val1, x2=val2; + + if (args[0]->unsigned_flag) *((ulonglong *)&x1) >>= 1; else x1 >>= 1; + if (args[1]->unsigned_flag) *((ulonglong *)&x2) >>= 1; else x2 >>= 1; + + if (x1 < x2) return -1; + if (x2 < x1) return 1; + if (val1 == val2) return 0; + + if (val1 < val2) return -1; return 1; } } ===== sql/set_var.cc 1.57 vs edited ===== --- 1.57/sql/set_var.cc 2004-06-01 15:29:22 +01:00 +++ edited/sql/set_var.cc 2004-08-11 17:26:14 +01:00 @@ -1093,7 +1093,7 @@ } switch (type()) { case SHOW_LONG: - return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type)); + return new Item_uint((uint32) *(ulong*) value_ptr(thd, var_type)); case SHOW_LONGLONG: { longlong value; ===== sql/sql_lex.cc 1.40 vs edited ===== --- 1.40/sql/sql_lex.cc 2003-07-02 16:55:09 +01:00 +++ edited/sql/sql_lex.cc 2004-08-11 18:20:52 +01:00 @@ -414,6 +414,20 @@ return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger; } +int lex_ulonglong(const char *str,uint length) +{ + int i = 0; + if ((*str == '+') || (*str == '-')) + i++; + for (; i < length; i++) { + if ((str[i] < '0') || (str[i] > '9')) + { + length = i; + break; + } + } + return int_token(str,length) == ULONGLONG_NUM; +} // yylex remember the following states from the following yylex() // STATE_EOQ ; found end of query
[3 Sep 2004 16:09]
Sergei Golubchik
This patch is unfortunately too big and intrusive for the stable version 4.0 We fixed this bug in 4.1 instead, try 4.1.4-gamma