summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc299
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);