diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 299 |
1 files changed, 262 insertions, 37 deletions
diff --git a/sql/item.cc b/sql/item.cc index d190fbdade8..68a091de3ef 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -80,7 +80,7 @@ Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const { item->decimals= arg->decimals; item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS, - DECIMAL_MAX_LENGTH); + DECIMAL_MAX_STR_LENGTH); } @@ -348,6 +348,17 @@ Item::Item(THD *thd, Item *item): } +uint Item::decimal_precision() const +{ + Item_result restype= result_type(); + + if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) + return min(my_decimal_length_to_precision(max_length, decimals, unsigned_flag), + DECIMAL_MAX_PRECISION); + return min(max_length, DECIMAL_MAX_PRECISION); +} + + void Item::print_item_w_name(String *str) { print(str); @@ -454,6 +465,7 @@ void Item_ident::cleanup() db_name= orig_db_name; table_name= orig_table_name; field_name= orig_field_name; + depended_from= 0; DBUG_VOID_RETURN; } @@ -557,6 +569,11 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) bool Item::eq(const Item *item, bool binary_cmp) const { + /* + Note, that this is never TRUE if item is a Item_param: + for all basic constants we have special checks, and Item_param's + type() can be only among basic constant types. + */ return type() == item->type() && name && item->name && !my_strcasecmp(system_charset_info,name,item->name); } @@ -601,7 +618,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) bool Item_string::eq(const Item *item, bool binary_cmp) const { - if (type() == item->type()) + if (type() == item->type() && item->basic_const_item()) { if (binary_cmp) return !stringcmp(&str_value, &item->str_value); @@ -937,10 +954,8 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) return 1; } if (collation->state & MY_CS_BINSORT) - { return 0; - } - else if (dt.collation->state & MY_CS_BINSORT) + if (dt.collation->state & MY_CS_BINSORT) { set(dt); return 0; @@ -1020,7 +1035,7 @@ void Item_field::set_field(Field *field_par) field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); decimals= field->decimals(); - max_length= field_par->representation_length(); + max_length= field_par->field_length; table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db; @@ -1335,6 +1350,13 @@ Item_uint::Item_uint(const char *str_arg, uint length): } +Item_uint::Item_uint(const char *str_arg, longlong i, uint length): + Item_int(str_arg, i, length) +{ + unsigned_flag= 1; +} + + String *Item_uint::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor @@ -1358,18 +1380,18 @@ Item_decimal::Item_decimal(const char *str_arg, uint length, 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(); + max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, + decimals, unsigned_flag); } 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(); + max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, + decimals, unsigned_flag); } @@ -1377,9 +1399,9 @@ 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(); + max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, + decimals, unsigned_flag); } @@ -1391,7 +1413,6 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, decimals= (uint8) decimal_par; max_length= length; fixed= 1; - unsigned_flag= !decimal_value.sign(); } @@ -1399,19 +1420,20 @@ 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(); + max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, + decimals, !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); + 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(); + max_length= my_decimal_precision_to_length(precision, decimals, + !decimal_value.sign()); } @@ -1443,6 +1465,24 @@ void Item_decimal::print(String *str) } +bool Item_decimal::eq(const Item *item, bool binary_cmp) const +{ + if (type() == item->type() && item->basic_const_item()) + { + /* + We need to cast off const to call val_decimal(). This should + be OK for a basic constant. Additionally, we can pass 0 as + a true decimal constant will return its internal decimal + storage and ignore the argument. + */ + Item *arg= (Item*) item; + my_decimal *value= arg->val_decimal(0); + return !my_decimal_cmp(&decimal_value, value); + } + return 0; +} + + String *Item_float::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor @@ -1671,7 +1711,8 @@ void Item_param::set_decimal(const char *str, ulong length) str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end); state= DECIMAL_VALUE; decimals= decimal_value.frac; - max_length= decimal_value.intg + decimals + 2; + max_length= my_decimal_precision_to_length(decimal_value.precision(), + decimals, unsigned_flag); maybe_null= 0; DBUG_VOID_RETURN; } @@ -1822,7 +1863,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) my_decimal2decimal(ent_value, &decimal_value); state= DECIMAL_VALUE; decimals= ent_value->frac; - max_length= ent_value->intg + decimals + 2; + max_length= my_decimal_precision_to_length(ent_value->precision(), + decimals, unsigned_flag); break; } default: @@ -2194,6 +2236,74 @@ bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } +bool Item_param::basic_const_item() const +{ + if (state == NO_VALUE || state == TIME_VALUE) + return FALSE; + return TRUE; +} + + +Item * +Item_param::new_item() +{ + /* see comments in the header file */ + switch (state) { + case NULL_VALUE: + return new Item_null(name); + case INT_VALUE: + return (unsigned_flag ? + new Item_uint(name, value.integer, max_length) : + new Item_int(name, value.integer, max_length)); + case REAL_VALUE: + return new Item_float(name, value.real, decimals, max_length); + case STRING_VALUE: + case LONG_DATA_VALUE: + return new Item_string(name, str_value.c_ptr_quick(), str_value.length(), + str_value.charset()); + case TIME_VALUE: + break; + case NO_VALUE: + default: + DBUG_ASSERT(0); + }; + return 0; +} + + +bool +Item_param::eq(const Item *arg, bool binary_cmp) const +{ + Item *item; + if (!basic_const_item() || !arg->basic_const_item() || arg->type() != type()) + return FALSE; + /* + We need to cast off const to call val_int(). This should be OK for + a basic constant. + */ + item= (Item*) arg; + + switch (state) { + case NULL_VALUE: + return TRUE; + case INT_VALUE: + return value.integer == item->val_int() && + unsigned_flag == item->unsigned_flag; + case REAL_VALUE: + return value.real == item->val_real(); + case STRING_VALUE: + case LONG_DATA_VALUE: + if (binary_cmp) + return !stringcmp(&str_value, &item->str_value); + return !sortcmp(&str_value, &item->str_value, collation.collation); + default: + break; + } + return FALSE; +} + +/* End of Item_param related */ + void Item_param::print(String *str) { if (state == NO_VALUE) @@ -2334,7 +2444,7 @@ bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate) */ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, - Item_ident *resolved_item, + Item_ident *resolved_item, Item_ident *mark_item) { const char *db_name= (resolved_item->db_name ? @@ -2359,6 +2469,71 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, } +/* + Mark range of selects and resolved identifier (field/reference) item as + dependent + + SYNOPSIS + mark_select_range_as_dependent() + thd - thread handler + last_select - select where resolved_item was resolved + current_sel - current select (select where resolved_item was placed) + found_field - field which was found during resolving + found_item - Item which was found during resolving (if resolved + identifier belongs to VIEW) + resolved_item - Identifier which was resolved + + NOTE: + We have to mark all items between current_sel (including) and + last_select (excluding) as dependend (select before last_select should + be marked with actual table mask used by resolved item, all other with + OUTER_REF_TABLE_BIT) and also write dependence information to Item of + resolved identifier. +*/ + +void mark_select_range_as_dependent(THD *thd, + SELECT_LEX *last_select, + SELECT_LEX *current_sel, + Field *found_field, Item *found_item, + Item_ident *resolved_item) +{ + /* + Go from current SELECT to SELECT where field was resolved (it + have to be reachable from current SELECT, because it was already + done once when we resolved this field and cached result of + resolving) + */ + SELECT_LEX *previous_select= current_sel; + for(; + previous_select->outer_select() != last_select; + previous_select= previous_select->outer_select()) + { + Item_subselect *prev_subselect_item= + previous_select->master_unit()->item; + prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; + prev_subselect_item->const_item_cache= 0; + } + { + Item_subselect *prev_subselect_item= + previous_select->master_unit()->item; + Item_ident *dependent= resolved_item; + if (found_field == view_ref_found) + { + Item::Type type= found_item->type(); + prev_subselect_item->used_tables_cache|= + found_item->used_tables(); + dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ? + (Item_ident*) found_item : + 0); + } + else + prev_subselect_item->used_tables_cache|= + found_field->table->map; + prev_subselect_item->const_item_cache= 0; + mark_as_dependent(thd, last_select, current_sel, resolved_item, + dependent); + } +} /* @@ -3107,11 +3282,8 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) switch (field_type()) { 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, + return new Field_new_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table, decimals, 0, unsigned_flag); case MYSQL_TYPE_TINY: @@ -3346,6 +3518,35 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions) } +bool Item_int::eq(const Item *arg, bool binary_cmp) const +{ + /* No need to check for null value as basic constant can't be NULL */ + if (arg->basic_const_item() && arg->type() == type()) + { + /* + We need to cast off const to call val_int(). This should be OK for + a basic constant. + */ + Item *item= (Item*) arg; + return item->val_int() == value && item->unsigned_flag == unsigned_flag; + } + return FALSE; +} + + +Item *Item_int_with_ref::new_item() +{ + DBUG_ASSERT(ref->basic_const_item()); + /* + We need to evaluate the constant to make sure it works with + parameter markers. + */ + return (ref->unsigned_flag ? + new Item_uint(ref->name, ref->val_int(), ref->max_length) : + new Item_int(ref->name, ref->val_int(), ref->max_length)); +} + + Item_num *Item_uint::neg() { Item_decimal *item= new Item_decimal(value, 0); @@ -3433,6 +3634,21 @@ void Item_float::print(String *str) In number context this is a longlong value. */ +bool Item_float::eq(const Item *arg, bool binary_cmp) const +{ + if (arg->basic_const_item() && arg->type() == type()) + { + /* + We need to cast off const to call val_int(). This should be OK for + a basic constant. + */ + Item *item= (Item*) arg; + return item->val_real() == value; + } + return FALSE; +} + + inline uint char_val(char X) { return (uint) (X >= '0' && X <= '9' ? X-'0' : @@ -3503,6 +3719,17 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions) } +bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const +{ + if (arg->basic_const_item() && arg->type() == type()) + { + if (binary_cmp) + return !stringcmp(&str_value, &arg->str_value); + return !sortcmp(&str_value, &arg->str_value, collation.collation); + } + return FALSE; +} + /* bin item. In string context this is a binary string. @@ -4812,6 +5039,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) /* fix variable decimals which always is NOT_FIXED_DEC */ if (Field::result_merge_type(fld_type) == INT_RESULT) decimals= 0; + prev_decimal_int_part= item->decimal_int_part(); } @@ -4934,18 +5162,12 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) { - int item_length= display_length(item); - int intp1= item_length - min(item->decimals, NOT_FIXED_DEC - 1); - int intp2= max_length - min(decimals, NOT_FIXED_DEC - 1); - /* can't be overflow because it work only for decimals (no strings) */ - int dec_length= max(intp1, intp2) + decimals; - max_length= max(max_length, (uint) max(item_length, dec_length)); - /* - we can't allow decimals to be NOT_FIXED_DEC, to prevent creation - decimal with max precision (see Field_new_decimal constcuctor) - */ - if (decimals >= NOT_FIXED_DEC) - decimals= NOT_FIXED_DEC - 1; + decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE); + int precision= min(max(prev_decimal_int_part, item->decimal_int_part()) + + decimals, DECIMAL_MAX_PRECISION); + unsigned_flag&= item->unsigned_flag; + max_length= my_decimal_precision_to_length(precision, decimals, + unsigned_flag); } else max_length= max(max_length, display_length(item)); @@ -4966,6 +5188,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } maybe_null|= item->maybe_null; get_full_info(item); + + /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ + prev_decimal_int_part= decimal_int_part(); DBUG_PRINT("info", ("become type: %d len: %u dec: %u", (int) fld_type, max_length, (uint) decimals)); DBUG_RETURN(FALSE); |