diff options
author | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
---|---|---|
committer | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
commit | 91db48e35a57421c00f65d5ce82e84b843ceec22 (patch) | |
tree | 9631c72d46b0fd08479ad02de00e5846cd339cda /sql/item.cc | |
parent | 63bcbfc4339ae843dc367d08fff0760da4d484c3 (diff) | |
download | mariadb-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.cc | 827 |
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*) { |