Commit afbd28ae authored by Alexander Barkov's avatar Alexander Barkov

Preparing the CAST(..AS [UN]SIGNED) related code to fix a number

of bugs easier (MDEV-8919, MDEV-10304, MDEV-10305, MDEV-10307)

- Adding Item::push_note_converted_to_negative_complement() and
  Item::push_note_converted_to_positive_complement()
- Adding virtual methods Item::val_int_signed_typecast() and
  Item::val_int_unsigned_typecast()
- Moving COLUMN_GET() related code from
  Item_func_signed::val_int() and Item_func_unsigned::val_int() to
  Item_dyncol_get::val_int_signed_typecast() and
  Item_dyncol_get::val_int_unsigned_typecast()
- Moving Item_func_signed::val_int_from_str() to Item::val_int_from_str()
  and changing it to get the value from "this" instead of args[0].

The patch does not change behaviour. It's only to simplify fixing of the
mentioned bugs. It will also simplify switching the CAST related code to
use the type handler infrastructure easier (soon).
parent 8bec9746
......@@ -72,6 +72,22 @@ void item_init(void)
}
void Item::push_note_converted_to_negative_complement(THD *thd)
{
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
"Cast to signed converted positive out-of-range integer to "
"it's negative complement");
}
void Item::push_note_converted_to_positive_complement(THD *thd)
{
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
"Cast to unsigned converted negative integer to it's "
"positive complement");
}
/**
@todo
Make this functions class dependent
......
......@@ -665,6 +665,8 @@ class Item: public Value_source,
bool set_blob_packlength);
Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length);
void push_note_converted_to_negative_complement(THD *thd);
void push_note_converted_to_positive_complement(THD *thd);
public:
/*
Cache val_str() into the own buffer, e.g. to evaluate constant
......@@ -875,6 +877,20 @@ class Item: public Value_source,
If value is not null null_value flag will be reset to FALSE.
*/
virtual longlong val_int()=0;
/**
Get a value for CAST(x AS SIGNED).
Too large positive unsigned integer values are converted
to negative complements.
Values of non-integer data types are adjusted to the SIGNED range.
*/
virtual longlong val_int_signed_typecast();
/**
Get a value for CAST(x AS UNSIGNED).
Negative signed integer values are converted
to positive complements.
Values of non-integer data types are adjusted to the UNSIGNED range.
*/
virtual longlong val_int_unsigned_typecast();
/*
This is just a shortcut to avoid the cast. You should still use
unsigned_flag to check the sign of the item.
......@@ -1042,6 +1058,7 @@ class Item: public Value_source,
longlong val_int_from_decimal();
longlong val_int_from_date();
longlong val_int_from_real();
longlong val_int_from_str(int *error);
double val_real_from_decimal();
double val_real_from_date();
......
......@@ -1073,7 +1073,7 @@ void Item_func_signed::print(String *str, enum_query_type query_type)
}
longlong Item_func_signed::val_int_from_str(int *error)
longlong Item::val_int_from_str(int *error)
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), &my_charset_bin), *res;
......@@ -1083,13 +1083,11 @@ longlong Item_func_signed::val_int_from_str(int *error)
to a longlong
*/
if (!(res= args[0]->val_str(&tmp)))
if (!(res= val_str(&tmp)))
{
null_value= 1;
*error= 0;
return 0;
}
null_value= 0;
Converter_strtoll10_with_warn cnv(NULL, Warn_filter_all(),
res->charset(), res->ptr(), res->length());
*error= cnv.error();
......@@ -1097,37 +1095,15 @@ longlong Item_func_signed::val_int_from_str(int *error)
}
longlong Item_func_signed::val_int()
longlong Item::val_int_signed_typecast()
{
longlong value;
int error;
if (args[0]->cast_to_int_type() != STRING_RESULT)
{
value= args[0]->val_int();
null_value= args[0]->null_value;
return value;
}
else if (args[0]->dynamic_result())
{
/* We come here when argument has an unknown type */
args[0]->unsigned_flag= 0; // Mark that we want to have a signed value
value= args[0]->val_int();
null_value= args[0]->null_value;
if (!null_value && args[0]->unsigned_flag && value < 0)
goto err; // Warn about overflow
return value;
}
if (cast_to_int_type() != STRING_RESULT)
return val_int();
value= val_int_from_str(&error);
if (value < 0 && error == 0)
goto err;
return value;
err:
push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
"Cast to signed converted positive out-of-range integer to "
"it's negative complement");
int error;
longlong value= val_int_from_str(&error);
if (!null_value && value < 0 && error == 0)
push_note_converted_to_negative_complement(current_thd);
return value;
}
......@@ -1141,49 +1117,30 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type)
}
longlong Item_func_unsigned::val_int()
longlong Item::val_int_unsigned_typecast()
{
longlong value;
int error;
if (args[0]->cast_to_int_type() == DECIMAL_RESULT)
if (cast_to_int_type() == DECIMAL_RESULT)
{
my_decimal tmp, *dec= args[0]->val_decimal(&tmp);
if (!(null_value= args[0]->null_value))
longlong value;
my_decimal tmp, *dec= val_decimal(&tmp);
if (!null_value)
my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &value);
else
value= 0;
return value;
}
else if (args[0]->dynamic_result())
{
/* We come here when argument has an unknown type */
args[0]->unsigned_flag= 1; // Mark that we want to have an unsigned value
value= args[0]->val_int();
null_value= args[0]->null_value;
if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
goto err; // Warn about overflow
return value;
}
else if (args[0]->cast_to_int_type() != STRING_RESULT)
else if (cast_to_int_type() != STRING_RESULT)
{
value= args[0]->val_int();
null_value= args[0]->null_value;
if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
goto err; // Warn about overflow
longlong value= val_int();
if (!null_value && unsigned_flag == 0 && value < 0)
push_note_converted_to_positive_complement(current_thd);
return value;
}
value= val_int_from_str(&error);
if (error < 0)
goto err;
return value;
err:
push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
"Cast to unsigned converted negative integer to it's "
"positive complement");
int error;
longlong value= val_int_from_str(&error);
if (!null_value && error < 0)
push_note_converted_to_positive_complement(current_thd);
return value;
}
......
......@@ -624,8 +624,12 @@ class Item_func_signed :public Item_int_func
unsigned_flag= 0;
}
const char *func_name() const { return "cast_as_signed"; }
longlong val_int();
longlong val_int_from_str(int *error);
longlong val_int()
{
longlong value= args[0]->val_int_signed_typecast();
null_value= args[0]->null_value;
return value;
}
void fix_length_and_dec()
{
fix_char_length(MY_MIN(args[0]->max_char_length(),
......@@ -644,7 +648,12 @@ class Item_func_unsigned :public Item_func_signed
unsigned_flag= 1;
}
const char *func_name() const { return "cast_as_unsigned"; }
longlong val_int();
longlong val_int()
{
longlong value= args[0]->val_int_unsigned_typecast();
null_value= args[0]->null_value;
return value;
}
virtual void print(String *str, enum_query_type query_type);
};
......
......@@ -1254,6 +1254,22 @@ class Item_dyncol_get: public Item_str_func
const char *func_name() const { return "column_get"; }
String *val_str(String *);
longlong val_int();
longlong val_int_signed_typecast()
{
unsigned_flag= false; // Mark that we want to have a signed value
longlong value= val_int(); // val_int() can change unsigned_flag
if (!null_value && unsigned_flag && value < 0)
push_note_converted_to_negative_complement(current_thd);
return value;
}
longlong val_int_unsigned_typecast()
{
unsigned_flag= true; // Mark that we want to have an unsigned value
longlong value= val_int(); // val_int() can change unsigned_flag
if (!null_value && unsigned_flag == 0 && value < 0)
push_note_converted_to_positive_complement(current_thd);
return value;
}
double val_real();
my_decimal *val_decimal(my_decimal *);
bool get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val, String *tmp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment