summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
authorunknown <hf@deer.(none)>2005-02-09 02:50:45 +0400
committerunknown <hf@deer.(none)>2005-02-09 02:50:45 +0400
commit91db48e35a57421c00f65d5ce82e84b843ceec22 (patch)
tree9631c72d46b0fd08479ad02de00e5846cd339cda /sql/item.cc
parent63bcbfc4339ae843dc367d08fff0760da4d484c3 (diff)
downloadmariadb-git-91db48e35a57421c00f65d5ce82e84b843ceec22.tar.gz
Precision Math implementation
BitKeeper/etc/ignore: Added client/decimal.c client/my_decimal.cc client/my_decimal.h to the ignore list
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc827
1 files changed, 789 insertions, 38 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 30e03916a74..17ded05766f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -44,6 +44,34 @@ void item_init(void)
item_user_lock_init();
}
+
+/*
+TODO: make this functions class dependent
+*/
+bool Item::val_bool()
+{
+ switch(result_type())
+ {
+ case INT_RESULT:
+ return val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+}
+
+
Item::Item():
name(0), orig_name(0), name_length(0), fixed(0),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
@@ -72,7 +100,7 @@ Item::Item():
}
/*
- Constructor used by Item_field, Item_*_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_*_ref & aggregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
*/
@@ -148,7 +176,7 @@ bool Item::cleanup_processor(byte *arg)
void Item::rename(char *new_name)
{
/*
- we can compare pointers to names here, bacause if name was not changed,
+ we can compare pointers to names here, because if name was not changed,
pointer will be same
*/
if (!orig_name && new_name != name)
@@ -411,6 +439,55 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
}
+double Item_splocal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ double ret= it->val_real();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+longlong Item_splocal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ longlong ret= it->val_int();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+String *Item_splocal::val_str(String *sp)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ String *ret= it->val_str(sp);
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ my_decimal value, *val= it->val_decimal(&value);
+ Item::null_value= it->null_value;
+ return val;
+}
+
+
+bool Item_splocal::is_null()
+{
+ Item *it= this_item();
+ bool ret= it->is_null();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
Item *
Item_splocal::this_item()
{
@@ -438,12 +515,38 @@ Item_splocal::type() const
}
+bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **)
+{
+ Item *it= this_item();
+ DBUG_ASSERT(it->fixed);
+ max_length= it->max_length;
+ decimals= it->decimals;
+ fixed= 1;
+ return FALSE;
+}
+
+
+void Item_splocal::cleanup()
+{
+ fixed= 0;
+}
+
+
+void Item_splocal::print(String *str)
+{
+ str->reserve(m_name.length+8);
+ str->append(m_name.str, m_name.length);
+ str->append('@');
+ str->qs_append(m_offset);
+}
+
+
/*
Aggregate two collations together taking
into account their coercibility (aka derivation):
- 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause
+ 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause
1 == DERIVATION_NONE - a mix of two different collations
2 == DERIVATION_IMPLICIT - a column
3 == DERIVATION_COERCIBLE - a string constant
@@ -482,7 +585,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
/*
We do allow to use binary strings (like BLOBS)
together with character strings.
- Binaries have more precedance than a character
+ Binaries have more precedence than a character
string of the same derivation.
*/
if (collation == &my_charset_bin)
@@ -634,8 +737,8 @@ void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
- max_length=field_par->field_length;
decimals= field->decimals();
+ max_length= field_par->representation_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db;
@@ -743,6 +846,7 @@ String *Item_field::val_str(String *str)
return field->val_str(str,&str_value);
}
+
double Item_field::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -751,6 +855,7 @@ double Item_field::val_real()
return field->val_real();
}
+
longlong Item_field::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -760,6 +865,14 @@ longlong Item_field::val_int()
}
+my_decimal *Item_field::val_decimal(my_decimal *decimal_value)
+{
+ if ((null_value= field->is_null()))
+ return 0;
+ return field->val_decimal(decimal_value);
+}
+
+
String *Item_field::str_result(String *str)
{
if ((null_value=result_field->is_null()))
@@ -814,6 +927,40 @@ longlong Item_field::val_int_result()
}
+my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value)
+{
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+}
+
+
+bool Item_field::val_bool_result()
+{
+ if ((null_value= result_field->is_null()))
+ return FALSE;
+ switch (result_field->result_type())
+ {
+ case INT_RESULT:
+ return result_field->val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+}
+
+
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
if (item->type() != FIELD_ITEM)
@@ -872,10 +1019,17 @@ Item_int::Item_int(const char *str_arg, uint length)
value= my_strtoll10(str_arg, &end_ptr, &error);
max_length= (uint) (end_ptr - str_arg);
name= (char*) str_arg;
+ unsigned_flag= value > 0;
fixed= 1;
}
+my_decimal *Item_int::val_decimal(my_decimal *decimal_value)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
String *Item_int::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -916,7 +1070,98 @@ void Item_uint::print(String *str)
}
-String *Item_real::val_str(String *str)
+Item_decimal::Item_decimal(const char *str_arg, uint length,
+ CHARSET_INFO *charset)
+{
+ str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value);
+ name= (char*) str_arg;
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+Item_decimal::Item_decimal(longlong val, bool unsig)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(double val, int precision, int scale)
+{
+ double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length)
+{
+ my_decimal2decimal(val_arg, &decimal_value);
+ name= (char*) str;
+ decimals= (uint8) decimal_par;
+ max_length= length;
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(my_decimal *value_par)
+{
+ my_decimal2decimal(value_par, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(value_par);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(const char *bin, int precision, int scale)
+{
+ binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+longlong Item_decimal::val_int()
+{
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result);
+ return result;
+}
+
+double Item_decimal::val_real()
+{
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+}
+
+String *Item_decimal::val_str(String *result)
+{
+ result->set_charset(&my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
+ return result;
+}
+
+void Item_decimal::print(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
+ str->append(str_value);
+}
+
+
+String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -925,6 +1170,15 @@ String *Item_real::val_str(String *str)
}
+my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
+ return (decimal_value);
+}
+
+
void Item_string::print(String *str)
{
str->append('_');
@@ -934,8 +1188,20 @@ void Item_string::print(String *str)
str->append('\'');
}
+
+my_decimal *Item_string::val_decimal(my_decimal *decimal_value)
+{
+ /* following assert is redundant, because fixed=1 assigned in constructor */
+ DBUG_ASSERT(fixed == 1);
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
bool Item_null::eq(const Item *item, bool binary_cmp) const
{ return item->type() == type(); }
+
+
double Item_null::val_real()
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -959,6 +1225,11 @@ String *Item_null::val_str(String *str)
return 0;
}
+my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
+{
+ return 0;
+}
+
Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs)
{
@@ -1005,7 +1276,6 @@ void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
/* These are cleared after each execution by reset() method */
- max_length= 0;
null_value= 1;
/*
Because of NULL and string values we need to set max_length for each new
@@ -1042,6 +1312,32 @@ void Item_param::set_double(double d)
/*
+ Set decimal parameter value from string.
+
+ SYNOPSIS
+ set_decimal()
+ str - character string
+ length - string length
+
+ NOTE
+ as we use character strings to send decimal values in
+ binary protocol, we use str2my_decimal to convert it to
+ internal decimal value.
+*/
+void Item_param::set_decimal(const char *str, ulong length)
+{
+ DBUG_ENTER("Item_param::set_decimal");
+
+ str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value);
+ state= DECIMAL_VALUE;
+ decimals= decimal_value.frac;
+ max_length= decimal_value.intg + decimals + 2;
+ maybe_null= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Set parameter value from TIME value.
SYNOPSIS
@@ -1094,6 +1390,7 @@ bool Item_param::set_str(const char *str, ulong length)
&dummy_errors))
DBUG_RETURN(TRUE);
state= STRING_VALUE;
+ max_length= length;
maybe_null= 0;
/* max_length and decimals are set after charset conversion */
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
@@ -1133,7 +1430,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
RETURN
0 OK
- 1 Out of memort
+ 1 Out of memory
*/
bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
@@ -1179,6 +1476,15 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
DBUG_RETURN(1);
break;
}
+ case DECIMAL_RESULT:
+ {
+ const my_decimal *ent_value= (const my_decimal *)entry->value;
+ my_decimal2decimal(ent_value, &decimal_value);
+ state= DECIMAL_VALUE;
+ decimals= ent_value->frac;
+ max_length= ent_value->intg + decimals + 2;
+ break;
+ }
default:
DBUG_ASSERT(0);
set_null();
@@ -1210,7 +1516,7 @@ void Item_param::reset()
str_value.length(0);
str_value_ptr.length(0);
/*
- We must prevent all charset conversions untill data has been written
+ We must prevent all charset conversions until data has been written
to the binary log.
*/
str_value.set_charset(&my_charset_bin);
@@ -1238,6 +1544,8 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
return field->store(value.integer);
case REAL_VALUE:
return field->store(value.real);
+ case DECIMAL_VALUE:
+ return field->store_decimal(&decimal_value);
case TIME_VALUE:
field->store_time(&value.time, value.time.time_type);
return 0;
@@ -1288,6 +1596,12 @@ double Item_param::val_real()
return value.real;
case INT_VALUE:
return (double) value.integer;
+ case DECIMAL_VALUE:
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
{
@@ -1318,6 +1632,12 @@ longlong Item_param::val_int()
return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5));
case INT_VALUE:
return value.integer;
+ case DECIMAL_VALUE:
+ {
+ longlong i;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
+ return i;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
{
@@ -1336,6 +1656,36 @@ longlong Item_param::val_int()
}
+my_decimal *Item_param::val_decimal(my_decimal *dec)
+{
+ switch (state) {
+ case DECIMAL_VALUE:
+ return &decimal_value;
+ case REAL_VALUE:
+ double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
+ return dec;
+ case INT_VALUE:
+ int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
+ return dec;
+ case STRING_VALUE:
+ case LONG_DATA_VALUE:
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec);
+ return dec;
+ case TIME_VALUE:
+ {
+ longlong i= (longlong) TIME_to_ulonglong(&value.time);
+ int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec);
+ return dec;
+ }
+ case NULL_VALUE:
+ return 0;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
String *Item_param::val_str(String* str)
{
switch (state) {
@@ -1348,6 +1698,11 @@ String *Item_param::val_str(String* str)
case INT_VALUE:
str->set(value.integer, &my_charset_bin);
return str;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) <= 1)
+ return str;
+ return NULL;
case TIME_VALUE:
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
@@ -1380,6 +1735,11 @@ const String *Item_param::query_val_str(String* str) const
case REAL_VALUE:
str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
break;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) > 1)
+ return &my_null_string;
+ break;
case TIME_VALUE:
{
char *buf, *ptr;
@@ -1474,7 +1834,7 @@ void Item_param::print(String *str)
}
else
{
- char buffer[80];
+ char buffer[STRING_BUFFER_USUAL_SIZE];
String tmp(buffer, sizeof(buffer), &my_charset_bin);
const String *res;
res= query_val_str(&tmp);
@@ -1505,6 +1865,17 @@ String *Item_copy_string::val_str(String *str)
}
+my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
+{
+ // Item_copy_string is used without fix_fields call
+ if (null_value)
+ return 0;
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
+
int Item_copy_string::save_in_field(Field *field, bool no_conversions)
{
if (null_value)
@@ -1548,6 +1919,24 @@ longlong Item_ref_null_helper::val_int()
}
+my_decimal *Item_ref_null_helper::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *val= (*ref)->val_decimal_result(decimal_value);
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
+bool Item_ref_null_helper::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ bool val= (*ref)->val_bool_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
String* Item_ref_null_helper::val_str(String* s)
{
DBUG_ASSERT(fixed == 1);
@@ -1931,7 +2320,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
{
if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
@@ -1995,7 +2384,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
- if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
+ if (!rf->fixed &&
+ rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
return TRUE;
mark_as_dependent(thd, last, current_sel, rf);
@@ -2016,7 +2406,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
- return rf->fix_fields(thd, tables, reference) || rf->check_cols(1);
+ return (!rf->fixed &&
+ rf->fix_fields(thd, tables, reference) || rf->check_cols(1));
}
}
}
@@ -2089,7 +2480,7 @@ void Item_field::cleanup()
Item_ident::cleanup();
/*
Even if this object was created by direct link to field in setup_wild()
- it will be linked correctly next tyme by name of field and table alias.
+ it will be linked correctly next time by name of field and table alias.
I.e. we can drop 'field'.
*/
field= result_field= 0;
@@ -2263,9 +2654,17 @@ void Item_empty_string::make_field(Send_field *tmp_field)
enum_field_types Item::field_type() const
{
- return ((result_type() == STRING_RESULT) ? MYSQL_TYPE_VARCHAR :
- (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
- FIELD_TYPE_DOUBLE);
+ switch (result_type())
+ {
+ case STRING_RESULT: return MYSQL_TYPE_VARCHAR;
+ case INT_RESULT: return FIELD_TYPE_LONGLONG;
+ case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL;
+ case REAL_RESULT: return FIELD_TYPE_DOUBLE;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return FIELD_TYPE_VAR_STRING;
+ };
}
@@ -2318,6 +2717,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_DECIMAL:
return new Field_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, decimals, 0, unsigned_flag);
+ case MYSQL_TYPE_NEWDECIMAL:
+ return new Field_new_decimal((char*) 0, max_length - (decimals?1:0),
+ null_ptr, 0,
+ Field::NONE, name, table, decimals, 0,
+ unsigned_flag);
case MYSQL_TYPE_TINY:
return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, 0, unsigned_flag);
@@ -2453,7 +2857,7 @@ int Item_null::save_in_field(Field *field, bool no_conversions)
field Field where we want to store NULL
RETURN VALUES
- 0 ok
+ 0 OK
1 Field doesn't support NULL values
*/
@@ -2492,6 +2896,15 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
error=field->store(nr);
}
+ else if (result_type() == DECIMAL_RESULT)
+ {
+ my_decimal decimal_value;
+ my_decimal *value= val_decimal(&decimal_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ error=field->store_decimal(value);
+ }
else
{
longlong nr=val_int();
@@ -2533,9 +2946,18 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
return field->store(nr);
}
+
+int Item_decimal::save_in_field(Field *field, bool no_conversions)
+{
+ field->set_notnull();
+ return field->store_decimal(&decimal_value);
+}
+
+
Item_num *Item_uint::neg()
{
- return new Item_real(name, - ((double) value), 0, max_length);
+ Item_decimal *item= new Item_decimal(value, 0);
+ return item->neg();
}
@@ -2544,7 +2966,7 @@ Item_num *Item_uint::neg()
value is not a true double value (overflow)
*/
-Item_real::Item_real(const char *str_arg, uint length)
+Item_float::Item_float(const char *str_arg, uint length)
{
int error;
char *end_not_used;
@@ -2566,7 +2988,7 @@ Item_real::Item_real(const char *str_arg, uint length)
}
-int Item_real::save_in_field(Field *field, bool no_conversions)
+int Item_float::save_in_field(Field *field, bool no_conversions)
{
double nr= val_real();
if (null_value)
@@ -2576,7 +2998,7 @@ int Item_real::save_in_field(Field *field, bool no_conversions)
}
-void Item_real::print(String *str)
+void Item_float::print(String *str)
{
if (presentation)
{
@@ -2639,6 +3061,16 @@ longlong Item_hex_string::val_int()
}
+my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ ulonglong value= (ulonglong)val_int();
+ int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
+ return (decimal_value);
+}
+
+
int Item_hex_string::save_in_field(Field *field, bool no_conversions)
{
int error;
@@ -2728,6 +3160,7 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NEWDECIMAL:
{
String *res;
if ((res=val_str(buffer)))
@@ -2818,6 +3251,20 @@ bool Item_field::send(Protocol *protocol, String *buffer)
}
+Item_ref::Item_ref(Item **item, const char *table_name_par,
+ const char *field_name_par)
+ :Item_ident(NullS, table_name_par, field_name_par), result_field(0),
+ ref(item)
+{
+ /*
+ This constructor used to create some internals references over fixed items
+ */
+ DBUG_ASSERT(ref);
+ if (*ref)
+ set_properties();
+}
+
+
/*
Resolve the name of a reference to a column reference.
@@ -2888,7 +3335,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
Item **group_by_ref= NULL;
if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref == not_found_item) /* This reference was not resolved. */
{
@@ -2918,7 +3365,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
{
if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
@@ -3145,6 +3592,106 @@ String *Item_ref::str_result(String* str)
}
+my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value)
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+ }
+ return val_decimal(decimal_value);
+}
+
+
+bool Item_ref::val_bool_result()
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ switch (result_field->result_type())
+ {
+ case INT_RESULT:
+ return result_field->val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ return val_bool();
+}
+
+
+double Item_ref::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double tmp=(*ref)->val_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_ref::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong tmp=(*ref)->val_int_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::val_bool()
+{
+ DBUG_ASSERT(fixed);
+ bool tmp= (*ref)->val_bool_result();
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_ref::val_str(String* tmp)
+{
+ DBUG_ASSERT(fixed);
+ tmp=(*ref)->str_result(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::is_null()
+{
+ DBUG_ASSERT(fixed);
+ (void) (*ref)->val_int_result();
+ return (*ref)->null_value;
+}
+
+
+bool Item_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
+}
+
+
+my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *val= (*ref)->val_decimal(decimal_value);
+ null_value= (*ref)->null_value;
+ return val;
+}
+
+
void Item_ref_null_helper::print(String *str)
{
str->append("<ref_null_helper>(", 18);
@@ -3156,6 +3703,59 @@ void Item_ref_null_helper::print(String *str)
}
+double Item_direct_ref::val_real()
+{
+ double tmp=(*ref)->val_real();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_direct_ref::val_int()
+{
+ longlong tmp=(*ref)->val_int();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_direct_ref::val_str(String* tmp)
+{
+ tmp=(*ref)->val_str(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+my_decimal *Item_direct_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *tmp= (*ref)->val_decimal(decimal_value);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::val_bool()
+{
+ bool tmp= (*ref)->val_bool();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::is_null()
+{
+ (void) (*ref)->val_int();
+ return (*ref)->null_value;
+}
+
+
+bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date(ltime,fuzzydate));
+}
+
+
void Item_null_helper::print(String *str)
{
str->append("<null_helper>(", 14);
@@ -3380,6 +3980,9 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return INT_RESULT;
else if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return DECIMAL_RESULT;
return REAL_RESULT;
}
@@ -3394,7 +3997,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
item->result_type());
char *name=item->name; // Alloced by sql_alloc
- if (res_type == STRING_RESULT)
+ switch (res_type)
+ {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),&my_charset_bin),*result;
@@ -3407,22 +4012,40 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
char *tmp_str= sql_strmake(result->ptr(), length);
new_item= new Item_string(name, tmp_str, length, result->charset());
}
+ break;
}
- else if (res_type == INT_RESULT)
+ case INT_RESULT:
{
longlong result=item->val_int();
uint length=item->max_length;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) :
(Item*) new Item_int(name, result, length));
+ break;
}
- else
+ case REAL_RESULT:
{ // It must REAL_RESULT
double result= item->val_real();
uint length=item->max_length,decimals=item->decimals;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) : (Item*)
- new Item_real(name, result, decimals, length));
+ new Item_float(name, result, decimals, length));
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *result= item->val_decimal(&decimal_value);
+ uint length= item->max_length, decimals= item->decimals;
+ bool null_value= item->null_value;
+ new_item= (null_value ?
+ (Item*) new Item_null(name) :
+ (Item*) new Item_decimal(name, result, length, decimals));
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
if (new_item)
thd->change_item_tree(ref, new_item);
@@ -3453,6 +4076,16 @@ bool field_is_equal_to_item(Field *field,Item *item)
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
+ if (res_type == DECIMAL_RESULT)
+ {
+ my_decimal item_buf, *item_val,
+ field_buf, *field_val;
+ item_val= item->val_decimal(&item_buf);
+ if (item->null_value)
+ return 1; // This must be true
+ field_val= field->val_decimal(&field_buf);
+ return !my_decimal_cmp(item_val, field_val);
+ }
double result= item->val_real();
if (item->null_value)
return 1;
@@ -3467,6 +4100,8 @@ Item_cache* Item_cache::get_cache(Item_result type)
return new Item_cache_int();
case REAL_RESULT:
return new Item_cache_real();
+ case DECIMAL_RESULT:
+ return new Item_cache_decimal();
case STRING_RESULT:
return new Item_cache_str();
case ROW_RESULT:
@@ -3494,6 +4129,23 @@ void Item_cache_int::store(Item *item)
{
value= item->val_int_result();
null_value= item->null_value;
+ unsigned_flag= item->unsigned_flag;
+}
+
+
+String *Item_cache_int::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
+ return decimal_val;
}
@@ -3504,6 +4156,69 @@ void Item_cache_real::store(Item *item)
}
+longlong Item_cache_real::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) (value+(value > 0 ? 0.5 : -0.5));
+}
+
+
+String* Item_cache_real::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, decimals, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ return decimal_val;
+}
+
+
+void Item_cache_decimal::store(Item *item)
+{
+ my_decimal *val= item->val_decimal_result(&decimal_value);
+ if (val != &decimal_value)
+ my_decimal2decimal(val, &decimal_value);
+ null_value= item->null_value;
+}
+
+double Item_cache_decimal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double res;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
+ return res;
+}
+
+longlong Item_cache_decimal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong res;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
+ return res;
+}
+
+String* Item_cache_decimal::val_str(String *str)
+{
+ DBUG_ASSERT(fixed);
+ my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
+ &decimal_value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
+ return str;
+}
+
+my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed);
+ return &decimal_value;
+}
+
+
void Item_cache_str::store(Item *item)
{
value_buff.set(buffer, sizeof(buffer), item->collation.collation);
@@ -3525,7 +4240,6 @@ void Item_cache_str::store(Item *item)
}
}
-
double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -3549,6 +4263,16 @@ longlong Item_cache_str::val_int()
return (longlong)0;
}
+my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (value)
+ string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ else
+ decimal_val= 0;
+ return decimal_val;
+}
+
bool Item_cache_row::allocate(uint num)
{
@@ -3701,18 +4425,18 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table)
/*
- STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT
+ STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT DECIMAL_RESULT
ROW_RESULT should never appear in Item_type_holder::join_types,
but it is included in following table just to make table full
(there DBUG_ASSERT in function to catch ROW_RESULT)
*/
-static Item_result type_convertor[4][4]=
-{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT},
- {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT},
- {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT},
- {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}};
-
+static Item_result type_convertor[5][5]=
+{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT, STRING_RESULT},
+ {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT, REAL_RESULT},
+ {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT},
+ {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT},
+ {STRING_RESULT, REAL_RESULT, DECIMAL_RESULT, ROW_RESULT, DECIMAL_RESULT}};
/*
Values of 'from' field can be stored in 'to' field.
@@ -3730,6 +4454,12 @@ static Item_result type_convertor[4][4]=
inline bool is_attr_compatible(Item *from, Item *to)
{
return ((to->max_length >= from->max_length) &&
+ ((to->result_type() != DECIMAL_RESULT &&
+ to->result_type() != REAL_RESULT &&
+ to->result_type() != INT_RESULT) ||
+ (to->decimals >= from->decimals) &&
+ ((to->max_length - to->decimals) >=
+ (from->max_length - from->decimals))) &&
(to->maybe_null || !from->maybe_null) &&
(to->result_type() != STRING_RESULT ||
from->result_type() != STRING_RESULT ||
@@ -3778,6 +4508,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
if (use_new_field ||
(new_result_type != item_type) || (new_length > max_length) ||
(!maybe_null && item->maybe_null) ||
+ ((new_result_type == REAL_RESULT || new_result_type == DECIMAL_RESULT) &&
+ (decimals < item->decimals ||
+ (max_length - decimals) < (new_length - item->decimals))) ||
(item_type == STRING_RESULT &&
collation.collation != item->collation.collation))
{
@@ -3805,8 +4538,20 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
return 1;
}
- max_length= max(max_length, new_length);
- decimals= max(decimals, item->decimals);
+ if (new_result_type == DECIMAL_RESULT)
+ {
+ int intp1= new_length - item->decimals;
+ int intp2= max_length - decimals;
+ max_length= max(intp1, intp2);
+ decimals= max(decimals, item->decimals);
+ /* can't be overflow because it work only for decimals (no strings) */
+ max_length+= decimals;
+ }
+ else
+ {
+ max_length= max(max_length, new_length);
+ decimals= max(decimals, item->decimals);
+ }
maybe_null|= item->maybe_null;
item_type= new_result_type;
}
@@ -3823,6 +4568,7 @@ uint32 Item_type_holder::real_length(Item *item)
switch (item->result_type())
{
case STRING_RESULT:
+ case DECIMAL_RESULT:
return item->max_length;
case REAL_RESULT:
return 53;
@@ -3848,6 +4594,11 @@ longlong Item_type_holder::val_int()
return 0;
}
+my_decimal *Item_type_holder::val_decimal(my_decimal *)
+{
+ DBUG_ASSERT(0); // should never be called
+ return 0;
+}
String *Item_type_holder::val_str(String*)
{