summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc211
1 files changed, 131 insertions, 80 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 224b6c279f3..e8731cb0ea5 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1199,7 +1199,7 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
This is used for printing bit_fields as numbers while debugging
*/
-String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_flag)
+String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
{
CHARSET_INFO *cs= &my_charset_bin;
uint length= 21;
@@ -1208,7 +1208,7 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_flag)
return 0;
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
length,
- unsigned_flag ? 10 : -10,
+ unsigned_val ? 10 : -10,
value);
val_buffer->length(length);
return val_buffer;
@@ -1360,7 +1360,7 @@ int Field_num::store_decimal(const my_decimal *val)
{
int err= 0;
longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
- return test(err | store(i));
+ return test(err | store(i, unsigned_flag));
}
@@ -2122,36 +2122,37 @@ int Field_decimal::store(double nr)
}
-int Field_decimal::store(longlong nr)
+int Field_decimal::store(longlong nr, bool unsigned_val)
{
- if (unsigned_flag && nr < 0)
+ char buff[22];
+ uint length, int_part;
+ char fyllchar, *to;
+
+ if (nr < 0 && unsigned_flag && !unsigned_val)
{
overflow(1);
return 1;
}
- char buff[22];
- uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff);
- uint int_part=field_length- (dec ? dec+1 : 0);
+ length= (uint) (longlong10_to_str(nr,buff,unsigned_val ? 10 : -10) - buff);
+ int_part= field_length- (dec ? dec+1 : 0);
if (length > int_part)
{
- overflow(test(nr < 0L)); /* purecov: inspected */
+ overflow(!unsigned_val && nr < 0L); /* purecov: inspected */
return 1;
}
- else
+
+ fyllchar = zerofill ? (char) '0' : (char) ' ';
+ to= ptr;
+ for (uint i=int_part-length ; i-- > 0 ;)
+ *to++ = fyllchar;
+ memcpy(to,buff,length);
+ if (dec)
{
- char fyllchar = zerofill ? (char) '0' : (char) ' ';
- char *to=ptr;
- for (uint i=int_part-length ; i-- > 0 ;)
- *to++ = fyllchar;
- memcpy(to,buff,length);
- if (dec)
- {
- to[length]='.';
- bfill(to+length+1,dec,'0');
- }
- return 0;
+ to[length]='.';
+ bfill(to+length+1,dec,'0');
}
+ return 0;
}
@@ -2482,13 +2483,13 @@ int Field_new_decimal::store(double nr)
}
-int Field_new_decimal::store(longlong nr)
+int Field_new_decimal::store(longlong nr, bool unsigned_val)
{
my_decimal decimal_value;
int err;
if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
- nr, FALSE, &decimal_value)))
+ nr, unsigned_val, &decimal_value)))
{
if (check_overflow(err))
set_value_on_overflow(&decimal_value, decimal_value.sign());
@@ -2663,18 +2664,20 @@ int Field_tiny::store(double nr)
return error;
}
-int Field_tiny::store(longlong nr)
+
+int Field_tiny::store(longlong nr, bool unsigned_val)
{
int error= 0;
+
if (unsigned_flag)
{
- if (nr < 0L)
+ if (nr < 0 && !unsigned_val)
{
- *ptr=0;
+ *ptr= 0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > 255L)
+ else if ((ulonglong) nr > (ulonglong) 255)
{
*ptr= (char) 255;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -2685,13 +2688,15 @@ int Field_tiny::store(longlong nr)
}
else
{
- if (nr < -128L)
+ if (nr < 0 && unsigned_val)
+ nr= 256; // Generate overflow
+ if (nr < -128)
{
*ptr= (char) -128;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > 127L)
+ else if (nr > 127)
{
*ptr=127;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -2711,6 +2716,7 @@ double Field_tiny::val_real(void)
return (double) tmp;
}
+
longlong Field_tiny::val_int(void)
{
int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
@@ -2718,6 +2724,7 @@ longlong Field_tiny::val_int(void)
return (longlong) tmp;
}
+
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -2877,19 +2884,21 @@ int Field_short::store(double nr)
return error;
}
-int Field_short::store(longlong nr)
+
+int Field_short::store(longlong nr, bool unsigned_val)
{
int error= 0;
int16 res;
+
if (unsigned_flag)
{
- if (nr < 0L)
+ if (nr < 0L && !unsigned_val)
{
res=0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > (longlong) UINT_MAX16)
+ else if ((ulonglong) nr > (ulonglong) UINT_MAX16)
{
res=(int16) UINT_MAX16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -2900,13 +2909,16 @@ int Field_short::store(longlong nr)
}
else
{
+ if (nr < 0 && unsigned_val)
+ nr= UINT_MAX16+1; // Generate overflow
+
if (nr < INT_MIN16)
{
res=INT_MIN16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > INT_MAX16)
+ else if (nr > (longlong) INT_MAX16)
{
res=INT_MAX16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -3134,20 +3146,22 @@ int Field_medium::store(double nr)
return error;
}
-int Field_medium::store(longlong nr)
+
+int Field_medium::store(longlong nr, bool unsigned_val)
{
int error= 0;
+
if (unsigned_flag)
{
- if (nr < 0L)
+ if (nr < 0 && !unsigned_val)
{
int3store(ptr,0);
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr >= (longlong) (long) (1L << 24))
+ else if ((ulonglong) nr >= (ulonglong) (long) (1L << 24))
{
- long tmp=(long) (1L << 24)-1L;;
+ long tmp= (long) (1L << 24)-1L;
int3store(ptr,tmp);
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
@@ -3157,9 +3171,12 @@ int Field_medium::store(longlong nr)
}
else
{
+ if (nr < 0 && unsigned_val)
+ nr= (ulonglong) (long) (1L << 24); // Generate overflow
+
if (nr < (longlong) INT_MIN24)
{
- long tmp=(long) INT_MIN24;
+ long tmp= (long) INT_MIN24;
int3store(ptr,tmp);
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
@@ -3397,7 +3414,7 @@ int Field_long::store(double nr)
}
-int Field_long::store(longlong nr)
+int Field_long::store(longlong nr, bool unsigned_val)
{
int error= 0;
int32 res;
@@ -3405,12 +3422,12 @@ int Field_long::store(longlong nr)
if (unsigned_flag)
{
- if (nr < 0)
+ if (nr < 0 && !unsigned_val)
{
res=0;
error= 1;
}
- else if (nr >= (LL(1) << 32))
+ else if ((ulonglong) nr >= (LL(1) << 32))
{
res=(int32) (uint32) ~0L;
error= 1;
@@ -3420,7 +3437,9 @@ int Field_long::store(longlong nr)
}
else
{
- if (nr < (longlong) INT_MIN32)
+ if (nr < 0 && unsigned_val)
+ nr= INT_MAX32+1; // Generate overflow
+ if (nr < (longlong) INT_MIN32)
{
res=(int32) INT_MIN32;
error= 1;
@@ -3657,8 +3676,24 @@ int Field_longlong::store(double nr)
}
-int Field_longlong::store(longlong nr)
+int Field_longlong::store(longlong nr, bool unsigned_val)
{
+ int error= 0;
+
+ if (nr < 0) // Only possible error
+ {
+ /*
+ if field is unsigned and value is signed (< 0) or
+ if field is signed and value is unsigned we have an overflow
+ */
+ if (unsigned_flag != unsigned_val)
+ {
+ nr= unsigned_flag ? (ulonglong) 0 : (ulonglong) LONGLONG_MAX;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ error= 1;
+ }
+ }
+
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
@@ -3667,7 +3702,7 @@ int Field_longlong::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
- return 0;
+ return error;
}
@@ -3886,11 +3921,12 @@ int Field_float::store(double nr)
}
-int Field_float::store(longlong nr)
+int Field_float::store(longlong nr, bool unsigned_val)
{
- return store((double)nr);
+ return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
}
+
double Field_float::val_real(void)
{
float j;
@@ -4166,11 +4202,12 @@ int Field_double::store(double nr)
}
-int Field_double::store(longlong nr)
+int Field_double::store(longlong nr, bool unsigned_val)
{
- return store((double)nr);
+ return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
}
+
int Field_real::store_decimal(const my_decimal *dm)
{
double dbl;
@@ -4529,12 +4566,12 @@ int Field_timestamp::store(double nr)
nr= 0; // Avoid overflow on buff
error= 1;
}
- error|= Field_timestamp::store((longlong) rint(nr));
+ error|= Field_timestamp::store((longlong) rint(nr), FALSE);
return error;
}
-int Field_timestamp::store(longlong nr)
+int Field_timestamp::store(longlong nr, bool unsigned_val)
{
TIME l_time;
my_time_t timestamp= 0;
@@ -4829,7 +4866,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
if (ltime.neg)
tmp= -tmp;
- error |= Field_time::store((longlong) tmp);
+ error |= Field_time::store((longlong) tmp, FALSE);
return error;
}
@@ -4881,21 +4918,21 @@ int Field_time::store(double nr)
}
-int Field_time::store(longlong nr)
+int Field_time::store(longlong nr, bool unsigned_val)
{
long tmp;
int error= 0;
- if (nr > (longlong) 8385959L)
+ if (nr < (longlong) -8385959L && !unsigned_val)
{
- tmp=8385959L;
+ tmp= -8385959L;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr,
MYSQL_TIMESTAMP_TIME, 1);
error= 1;
}
- else if (nr < (longlong) -8385959L)
+ else if (nr > (longlong) 8385959 || nr < 0 && unsigned_val)
{
- tmp= -8385959L;
+ tmp=8385959L;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr,
MYSQL_TIMESTAMP_TIME, 1);
@@ -5076,18 +5113,18 @@ int Field_year::store(double nr)
{
if (nr < 0.0 || nr >= 2155.0)
{
- (void) Field_year::store((longlong) -1);
+ (void) Field_year::store((longlong) -1, FALSE);
return 1;
}
- else
- return Field_year::store((longlong) nr);
+ return Field_year::store((longlong) nr, FALSE);
}
-int Field_year::store(longlong nr)
+
+int Field_year::store(longlong nr, bool unsigned_val)
{
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
- *ptr=0;
+ *ptr= 0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
@@ -5102,17 +5139,20 @@ int Field_year::store(longlong nr)
return 0;
}
+
bool Field_year::send_binary(Protocol *protocol)
{
ulonglong tmp= Field_year::val_int();
return protocol->store_short(tmp);
}
+
double Field_year::val_real(void)
{
return (double) Field_year::val_int();
}
+
longlong Field_year::val_int(void)
{
int tmp= (int) ((uchar*) ptr)[0];
@@ -5123,6 +5163,7 @@ longlong Field_year::val_int(void)
return (longlong) tmp;
}
+
String *Field_year::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -5133,6 +5174,7 @@ String *Field_year::val_str(String *val_buffer,
return val_buffer;
}
+
void Field_year::sql_type(String &res) const
{
CHARSET_INFO *cs=res.charset();
@@ -5203,7 +5245,7 @@ int Field_date::store(double nr)
}
-int Field_date::store(longlong nr)
+int Field_date::store(longlong nr, bool unsigned_val)
{
TIME not_used;
int error;
@@ -5262,6 +5304,7 @@ double Field_date::val_real(void)
return (double) (uint32) j;
}
+
longlong Field_date::val_int(void)
{
int32 j;
@@ -5274,6 +5317,7 @@ longlong Field_date::val_int(void)
return (longlong) (uint32) j;
}
+
String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -5382,11 +5426,11 @@ int Field_newdate::store(double nr)
WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
return 1;
}
- return Field_newdate::store((longlong) rint(nr));
+ return Field_newdate::store((longlong) rint(nr), FALSE);
}
-int Field_newdate::store(longlong nr)
+int Field_newdate::store(longlong nr, bool unsigned_val)
{
TIME l_time;
longlong tmp;
@@ -5576,12 +5620,12 @@ int Field_datetime::store(double nr)
nr= 0.0;
error= 1;
}
- error|= Field_datetime::store((longlong) rint(nr));
+ error|= Field_datetime::store((longlong) rint(nr), FALSE);
return error;
}
-int Field_datetime::store(longlong nr)
+int Field_datetime::store(longlong nr, bool unsigned_val)
{
TIME not_used;
int error;
@@ -5905,12 +5949,13 @@ int Field_str::store(double nr)
}
-int Field_string::store(longlong nr)
+int Field_string::store(longlong nr, bool unsigned_val)
{
char buff[64];
int l;
CHARSET_INFO *cs=charset();
- l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
+ l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),
+ unsigned_val ? 10 : -10, nr);
return Field_string::store(buff,(uint)l,cs);
}
@@ -6234,14 +6279,16 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
}
-int Field_varstring::store(longlong nr)
+int Field_varstring::store(longlong nr, bool unsigned_val)
{
char buff[64];
uint length;
length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
buff,
sizeof(buff),
- -10,nr);
+ (unsigned_val ? 10:
+ -10),
+ nr);
return Field_varstring::store(buff, length, field_charset);
}
@@ -6859,13 +6906,17 @@ int Field_blob::store(double nr)
}
-int Field_blob::store(longlong nr)
+int Field_blob::store(longlong nr, bool unsigned_val)
{
CHARSET_INFO *cs=charset();
- value.set(nr, cs);
+ if (unsigned_val)
+ value.set((ulonglong) nr, cs);
+ else
+ value.set(nr, cs);
return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
+
double Field_blob::val_real(void)
{
int not_used;
@@ -7330,7 +7381,7 @@ int Field_geom::store(double nr)
}
-int Field_geom::store(longlong nr)
+int Field_geom::store(longlong nr, bool unsigned_val)
{
my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
@@ -7483,14 +7534,14 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
int Field_enum::store(double nr)
{
- return Field_enum::store((longlong) nr);
+ return Field_enum::store((longlong) nr, FALSE);
}
-int Field_enum::store(longlong nr)
+int Field_enum::store(longlong nr, bool unsigned_val)
{
int error= 0;
- if ((uint) nr > typelib->count || nr == 0)
+ if ((ulonglong) nr > typelib->count || nr == 0)
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
nr=0;
@@ -7661,7 +7712,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
}
-int Field_set::store(longlong nr)
+int Field_set::store(longlong nr, bool unsigned_val)
{
int error= 0;
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
@@ -7881,11 +7932,11 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
int Field_bit::store(double nr)
{
- return store((longlong) nr);
+ return store((longlong) nr, FALSE);
}
-int Field_bit::store(longlong nr)
+int Field_bit::store(longlong nr, bool unsigned_val)
{
char buf[8];
@@ -8466,8 +8517,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
else
interval=0;
def=0;
+
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
- !old_field->is_real_null() &&
old_field->ptr && orig_field &&
(sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */
old_field->table->timestamp_field != old_field || /* timestamp field */