mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
MDEV-9407 Illegal mix of collation when using GROUP_CONCAT in a VIEW
MDEV-9408 CREATE TABLE SELECT MAX(int_column) creates different columns for table vs view There were three almost identical pieces of the code: - Field *Item_func::tmp_table_field(); - Field *Item_sum::create_tmp_field(); - Field *create_tmp_field_from_item(); with a difference in very small details (hence the bugs): Only Item_func::tmp_table_field() was correct, the other two were not. Removing the two incorrect pieces of the redundant code. Joining these three functions/methods into a single virtual method Item::create_tmp_field(). Additionally, moving Item::make_string_field() and Item::tmp_table_field_from_field_type() from the public into the protected section of the class declaration, as they are now not needed outside of Item.
This commit is contained in:
@@ -15681,6 +15681,73 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
|
||||
return new_field;
|
||||
}
|
||||
|
||||
|
||||
Field *Item::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_length,
|
||||
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);
|
||||
/*
|
||||
Make sure that the blob fits into a Field_varstring which has
|
||||
2-byte lenght.
|
||||
*/
|
||||
else if (max_length / collation.collation->mbmaxlen > 255 &&
|
||||
convert_blob_length <= Field_varstring::MAX_SIZE &&
|
||||
convert_blob_length)
|
||||
new_field= new (mem_root)
|
||||
Field_varstring(convert_blob_length, maybe_null,
|
||||
name, table->s, collation.collation);
|
||||
else
|
||||
new_field= make_string_field(table);
|
||||
new_field->set_derivation(collation.derivation);
|
||||
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.
|
||||
|
||||
@@ -15709,69 +15776,9 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
|
||||
Item ***copy_func, bool modify_item,
|
||||
uint convert_blob_length)
|
||||
{
|
||||
bool maybe_null= item->maybe_null;
|
||||
Field *UNINIT_VAR(new_field);
|
||||
MEM_ROOT *mem_root= thd->mem_root;
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
DATE/TIME and GEOMETRY fields have STRING_RESULT result type.
|
||||
To preserve type they needed 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);
|
||||
/*
|
||||
Make sure that the blob fits into a Field_varstring which has
|
||||
2-byte lenght.
|
||||
*/
|
||||
else if (item->max_length/item->collation.collation->mbmaxlen > 255 &&
|
||||
convert_blob_length <= Field_varstring::MAX_SIZE &&
|
||||
convert_blob_length)
|
||||
new_field= new (mem_root)
|
||||
Field_varstring(convert_blob_length, maybe_null,
|
||||
item->name, table->s,
|
||||
item->collation.collation);
|
||||
else
|
||||
new_field= item->make_string_field(table);
|
||||
new_field->set_derivation(item->collation.derivation);
|
||||
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);
|
||||
DBUG_ASSERT(thd == table->in_use);
|
||||
new_field= item->Item::create_tmp_field(false, table, convert_blob_length);
|
||||
|
||||
if (copy_func && item->real_item()->is_result_field())
|
||||
*((*copy_func)++) = item; // Save for copy_funcs
|
||||
@@ -15866,8 +15873,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
||||
switch (type) {
|
||||
case Item::SUM_FUNC_ITEM:
|
||||
{
|
||||
Item_sum *item_sum=(Item_sum*) item;
|
||||
result= item_sum->create_tmp_field(group, table, convert_blob_length);
|
||||
result= item->create_tmp_field(group, table, convert_blob_length);
|
||||
if (!result)
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user