Partial backporting of 7b50447aa6

(MDEV-9407, MDEV-9408) from 10.1

Needed to fix MDEV-10317 easier.
This commit is contained in:
Alexander Barkov 2016-07-03 11:20:46 +04:00
commit 3ccf8218bc
11 changed files with 87 additions and 127 deletions

View file

@ -657,6 +657,8 @@ protected:
SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length);
public: public:
/* /*
Cache val_str() into the own buffer, e.g. to evaluate constant Cache val_str() into the own buffer, e.g. to evaluate constant
@ -1021,8 +1023,6 @@ public:
int save_str_value_in_field(Field *field, String *result); int save_str_value_in_field(Field *field, String *result);
virtual Field *get_tmp_table_field() { return 0; } virtual Field *get_tmp_table_field() { return 0; }
/* This is also used to create fields in CREATE ... SELECT: */
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual Field *create_field_for_create_select(TABLE *table); virtual Field *create_field_for_create_select(TABLE *table);
virtual Field *create_field_for_schema(THD *thd, TABLE *table); virtual Field *create_field_for_schema(THD *thd, TABLE *table);
virtual const char *full_name() const { return name ? name : "???"; } virtual const char *full_name() const { return name ? name : "???"; }
@ -1630,6 +1630,15 @@ public:
// used in row subselects to get value of elements // used in row subselects to get value of elements
virtual void bring_value() {} virtual void bring_value() {}
virtual Field *create_tmp_field(bool group, TABLE *table)
{
/*
Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
Field_long : make them Field_longlong.
*/
return create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS - 2);
}
Field *tmp_table_field_from_field_type(TABLE *table, Field *tmp_table_field_from_field_type(TABLE *table,
bool fixed_length, bool fixed_length,
bool set_blob_packlength); bool set_blob_packlength);
@ -2224,7 +2233,6 @@ public:
{} {}
~Item_result_field() {} /* Required with gcc 2.95 */ ~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; } Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
/* /*
This implementation of used_tables() used by Item_avg_field and This implementation of used_tables() used by Item_avg_field and
Item_variance_field which work when only temporary table left, so theu Item_variance_field which work when only temporary table left, so theu
@ -3397,8 +3405,6 @@ public:
{ return val_real_from_date(); } { return val_real_from_date(); }
my_decimal *val_decimal(my_decimal *decimal_value) my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); } { return val_decimal_from_date(decimal_value); }
Field *tmp_table_field(TABLE *table)
{ return tmp_table_field_from_field_type(table, false, false); }
int save_in_field(Field *field, bool no_conversions) int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field); } { return save_date_in_field(field); }
}; };
@ -3903,7 +3909,6 @@ public:
enum_field_types field_type() const { return (*ref)->field_type(); } enum_field_types field_type() const { return (*ref)->field_type(); }
Field *get_tmp_table_field() Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); } { return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Field *tmp_table_field(TABLE *t_arg) { return 0; }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
table_map used_tables() const; table_map used_tables() const;
void update_used_tables(); void update_used_tables();

View file

@ -2263,11 +2263,6 @@ uint Item_func_case_abbreviation2::decimal_precision2(Item **args) const
} }
Field *Item_func_ifnull::tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, false, false);
}
double double
Item_func_ifnull::real_op() Item_func_ifnull::real_op()
{ {

View file

@ -951,7 +951,9 @@ public:
maybe_null= args[1]->maybe_null; maybe_null= args[1]->maybe_null;
} }
const char *func_name() const { return "ifnull"; } const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table); Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table, false, false); }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
uint decimal_precision() const uint decimal_precision() const
{ {

View file

@ -509,43 +509,6 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
} }
Field *Item_func::tmp_table_field(TABLE *table)
{
Field *field= NULL;
MEM_ROOT *mem_root= table->in_use->mem_root;
switch (result_type()) {
case INT_RESULT:
if (max_char_length() > MY_INT32_NUM_DECIMAL_DIGITS)
field= new (mem_root)
Field_longlong(max_char_length(), maybe_null, name,
unsigned_flag);
else
field= new (mem_root)
Field_long(max_char_length(), maybe_null, name,
unsigned_flag);
break;
case REAL_RESULT:
field= new (mem_root)
Field_double(max_char_length(), maybe_null, name, decimals);
break;
case STRING_RESULT:
return make_string_field(table);
case DECIMAL_RESULT:
field= Field_new_decimal::create_from_item(mem_root, this);
break;
case ROW_RESULT:
case TIME_RESULT:
// This case should never be chosen
DBUG_ASSERT(0);
field= 0;
break;
}
if (field)
field->init(table);
return field;
}
/* /*
bool Item_func::is_expensive_processor(uchar *arg) bool Item_func::is_expensive_processor(uchar *arg)
{ {
@ -2910,10 +2873,10 @@ void Item_func_min_max::fix_length_and_dec()
collation.set_numeric(); collation.set_numeric();
fix_char_length(float_length(decimals)); fix_char_length(float_length(decimals));
/* /*
Set type to DOUBLE, as Item_func::tmp_table_field() does not Set type to DOUBLE, as Item_func::create_tmp_field() does not
distinguish between DOUBLE and FLOAT and always creates Field_double. distinguish between DOUBLE and FLOAT and always creates Field_double.
Perhaps we should eventually change this to use agg_field_type() here, Perhaps we should eventually change this to use agg_field_type() here,
and fix Item_func::tmp_table_field() to create Field_float when possible. and fix Item_func::create_tmp_field() to create Field_float when possible.
*/ */
set_handler_by_field_type(MYSQL_TYPE_DOUBLE); set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
break; break;
@ -6805,16 +6768,6 @@ longlong Item_func_found_rows::val_int()
} }
Field *
Item_func_sp::tmp_table_field(TABLE *t_arg)
{
DBUG_ENTER("Item_func_sp::tmp_table_field");
DBUG_ASSERT(sp_result_field);
DBUG_RETURN(sp_result_field);
}
/** /**
@brief Checks if requested access to function can be granted to user. @brief Checks if requested access to function can be granted to user.
If function isn't found yet, it searches function first. If function isn't found yet, it searches function first.

View file

@ -173,12 +173,10 @@ public:
} }
void signal_divide_by_null(); void signal_divide_by_null();
friend class udf_handler; friend class udf_handler;
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
Field *create_field_for_create_select(TABLE *table) Field *create_field_for_create_select(TABLE *table)
{ {
return result_type() != STRING_RESULT ? return result_type() != STRING_RESULT ?
tmp_table_field(table) : create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) :
tmp_table_field_from_field_type(table, false, false); tmp_table_field_from_field_type(table, false, false);
} }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
@ -1765,7 +1763,7 @@ public:
Field *create_field_for_create_select(TABLE *table) Field *create_field_for_create_select(TABLE *table)
{ {
return result_type() != STRING_RESULT ? return result_type() != STRING_RESULT ?
tmp_table_field(table) : create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) :
tmp_table_field_from_field_type(table, false, true); tmp_table_field_from_field_type(table, false, true);
} }
table_map used_tables() const table_map used_tables() const
@ -2106,8 +2104,12 @@ public:
enum enum_field_types field_type() const; enum enum_field_types field_type() const;
Field *tmp_table_field(TABLE *t_arg); Field *create_field_for_create_select(TABLE *table)
{
return result_type() != STRING_RESULT ?
sp_result_field :
tmp_table_field_from_field_type(table, false, false);
}
void make_field(Send_field *tmp_field); void make_field(Send_field *tmp_field);
Item_result result_type() const; Item_result result_type() const;

View file

@ -40,7 +40,7 @@
#include "opt_range.h" #include "opt_range.h"
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg) Field *Item_geometry_func::create_field_for_create_select(TABLE *t_arg)
{ {
Field *result; Field *result;
if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s, if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s,

View file

@ -40,7 +40,7 @@ public:
Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {} Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
void fix_length_and_dec(); void fix_length_and_dec();
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
Field *tmp_table_field(TABLE *t_arg); Field *create_field_for_create_select(TABLE *table);
}; };
class Item_func_geometry_from_text: public Item_geometry_func class Item_func_geometry_from_text: public Item_geometry_func

View file

@ -481,7 +481,7 @@ public:
} }
virtual void make_unique() { force_copy_fields= TRUE; } virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table); Field *create_tmp_field(bool group, TABLE *table);
virtual bool collect_outer_ref_processor(uchar *param); virtual bool collect_outer_ref_processor(uchar *param);
bool init_sum_func_check(THD *thd); bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref); bool check_sum_func(THD *thd, Item **ref);
@ -1084,7 +1084,6 @@ public:
fixed= true; fixed= true;
} }
table_map used_tables() const { return (table_map) 1L; } table_map used_tables() const { return (table_map) 1L; }
Field *tmp_table_field(TABLE *) { DBUG_ASSERT(0); return NULL; }
void set_result_field(Field *) { DBUG_ASSERT(0); } void set_result_field(Field *) { DBUG_ASSERT(0); }
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); } void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
}; };

View file

@ -500,7 +500,7 @@ public:
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
my_decimal *val_decimal(my_decimal *decimal_value) my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); } { return val_decimal_from_date(decimal_value); }
Field *tmp_table_field(TABLE *table) Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table, false, false); } { return tmp_table_field_from_field_type(table, false, false); }
int save_in_field(Field *field, bool no_conversions) int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field); } { return save_date_in_field(field); }

View file

@ -3927,7 +3927,7 @@ void select_insert::abort_result_set() {
Field *Item::create_field_for_create_select(TABLE *table) Field *Item::create_field_for_create_select(TABLE *table)
{ {
Field *def_field, *tmp_field; Field *def_field, *tmp_field;
return create_tmp_field(table->in_use, table, this, type(), return ::create_tmp_field(table->in_use, table, this, type(),
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0); (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0);
} }

View file

@ -15837,6 +15837,60 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
return new_field; return new_field;
} }
Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length)
{
Field *UNINIT_VAR(new_field);
MEM_ROOT *mem_root= table->in_use->mem_root;
switch (cmp_type()) {
case REAL_RESULT:
new_field= new (mem_root)
Field_double(max_length, maybe_null, name, decimals, TRUE);
break;
case INT_RESULT:
/*
Select an integer type with the minimal fit precision.
convert_int_length is sign inclusive, don't consider the sign.
*/
if (max_char_length() > convert_int_length)
new_field= new (mem_root)
Field_longlong(max_char_length(), maybe_null, name, unsigned_flag);
else
new_field= new (mem_root)
Field_long(max_char_length(), maybe_null, name, unsigned_flag);
break;
case TIME_RESULT:
new_field= tmp_table_field_from_field_type(table, true, false);
break;
case STRING_RESULT:
DBUG_ASSERT(collation.collation);
/*
GEOMETRY fields have STRING_RESULT result type.
To preserve type they needed to be handled separately.
*/
if (field_type() == MYSQL_TYPE_GEOMETRY)
new_field= tmp_table_field_from_field_type(table, true, false);
else
new_field= make_string_field(table);
new_field->set_derivation(collation.derivation, collation.repertoire);
break;
case DECIMAL_RESULT:
new_field= Field_new_decimal::create_from_item(mem_root, this);
break;
case ROW_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
new_field= 0;
break;
}
if (new_field)
new_field->init(table);
return new_field;
}
/** /**
Create field for temporary table using type of given item. Create field for temporary table using type of given item.
@ -15862,58 +15916,9 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
Item ***copy_func, bool modify_item) Item ***copy_func, bool modify_item)
{ {
bool maybe_null= item->maybe_null;
Field *UNINIT_VAR(new_field); Field *UNINIT_VAR(new_field);
MEM_ROOT *mem_root= thd->mem_root; DBUG_ASSERT(thd == table->in_use);
new_field= item->Item::create_tmp_field(false, table);
/*
To preserve type or DATE/TIME and GEOMETRY fields,
they need to be handled separately.
*/
if (item->cmp_type() == TIME_RESULT ||
item->field_type() == MYSQL_TYPE_GEOMETRY)
new_field= item->tmp_table_field_from_field_type(table, true, false);
else
switch (item->result_type()) {
case REAL_RESULT:
new_field= new (mem_root)
Field_double(item->max_length, maybe_null,
item->name, item->decimals, TRUE);
break;
case INT_RESULT:
/*
Select an integer type with the minimal fit precision.
MY_INT32_NUM_DECIMAL_DIGITS is sign inclusive, don't consider the sign.
Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
Field_long : make them Field_longlong.
*/
if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1))
new_field=new (mem_root)
Field_longlong(item->max_length, maybe_null,
item->name, item->unsigned_flag);
else
new_field=new (mem_root)
Field_long(item->max_length, maybe_null, item->name,
item->unsigned_flag);
break;
case STRING_RESULT:
DBUG_ASSERT(item->collation.collation);
new_field= item->make_string_field(table);
new_field->set_derivation(item->collation.derivation,
item->collation.repertoire);
break;
case DECIMAL_RESULT:
new_field= Field_new_decimal::create_from_item(mem_root, item);
break;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
new_field= 0;
break;
}
if (new_field)
new_field->init(table);
if (copy_func && item->real_item()->is_result_field()) if (copy_func && item->real_item()->is_result_field())
*((*copy_func)++) = item; // Save for copy_funcs *((*copy_func)++) = item; // Save for copy_funcs
@ -16005,8 +16010,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
switch (type) { switch (type) {
case Item::SUM_FUNC_ITEM: case Item::SUM_FUNC_ITEM:
{ {
Item_sum *item_sum=(Item_sum*) item; result= item->create_tmp_field(group, table);
result= item_sum->create_tmp_field(group, table);
if (!result) if (!result)
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
return result; return result;