mirror of
https://github.com/MariaDB/server.git
synced 2026-04-28 11:15:33 +02:00
MDEV-5542: GROUP_CONCAT truncate output to 65.536 chars when using DISTINCT or ORDER BY
port of mysql fix WL#6098
This commit is contained in:
parent
66832b6195
commit
6c414fcf89
13 changed files with 312 additions and 101 deletions
|
|
@ -496,8 +496,7 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
|
|||
}
|
||||
|
||||
|
||||
Field *Item_sum::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_length)
|
||||
Field *Item_sum::create_tmp_field(bool group, TABLE *table)
|
||||
{
|
||||
Field *UNINIT_VAR(field);
|
||||
MEM_ROOT *mem_root= table->in_use->mem_root;
|
||||
|
|
@ -512,13 +511,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
|
|||
Field_longlong(max_length, maybe_null, name, unsigned_flag);
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
if (max_length/collation.collation->mbmaxlen <= 255 ||
|
||||
convert_blob_length > Field_varstring::MAX_SIZE ||
|
||||
!convert_blob_length)
|
||||
return make_string_field(table);
|
||||
field= new (mem_root) Field_varstring(convert_blob_length, maybe_null,
|
||||
name, table->s, collation.collation);
|
||||
break;
|
||||
return make_string_field(table);
|
||||
case DECIMAL_RESULT:
|
||||
field= Field_new_decimal::create_from_item(mem_root, this);
|
||||
break;
|
||||
|
|
@ -1264,8 +1257,7 @@ void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg)
|
|||
}
|
||||
|
||||
|
||||
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_length)
|
||||
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
|
||||
{
|
||||
Field *field;
|
||||
MEM_ROOT *mem_root;
|
||||
|
|
@ -1273,9 +1265,9 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
|
|||
if (args[0]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
field= ((Item_field*) args[0])->field;
|
||||
|
||||
|
||||
if ((field= create_tmp_field_from_field(table->in_use, field, name, table,
|
||||
NULL, convert_blob_length)))
|
||||
NULL)))
|
||||
field->flags&= ~NOT_NULL_FLAG;
|
||||
return field;
|
||||
}
|
||||
|
|
@ -1301,7 +1293,7 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
|
|||
Field::NONE, name, decimals);
|
||||
break;
|
||||
default:
|
||||
return Item_sum::create_tmp_field(group, table, convert_blob_length);
|
||||
return Item_sum::create_tmp_field(group, table);
|
||||
}
|
||||
if (field)
|
||||
field->init(table);
|
||||
|
|
@ -1658,8 +1650,7 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
|
|||
}
|
||||
|
||||
|
||||
Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_len)
|
||||
Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
|
||||
{
|
||||
Field *field;
|
||||
MEM_ROOT *mem_root= table->in_use->mem_root;
|
||||
|
|
@ -1885,8 +1876,7 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
|
|||
If we're grouping, then we need some space to serialize variables into, to
|
||||
pass around.
|
||||
*/
|
||||
Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_len)
|
||||
Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table)
|
||||
{
|
||||
Field *field;
|
||||
if (group)
|
||||
|
|
@ -3067,6 +3057,11 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
|
|||
ER_THD(thd, ER_CUT_VALUE_GROUP_CONCAT),
|
||||
item->row_count);
|
||||
|
||||
/**
|
||||
To avoid duplicated warnings in Item_func_group_concat::val_str()
|
||||
*/
|
||||
if (table && table->blob_storage)
|
||||
table->blob_storage->set_truncated_value(false);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -3204,6 +3199,8 @@ void Item_func_group_concat::cleanup()
|
|||
if (table)
|
||||
{
|
||||
THD *thd= table->in_use;
|
||||
if (table->blob_storage)
|
||||
delete table->blob_storage;
|
||||
free_tmp_table(thd, table);
|
||||
table= 0;
|
||||
if (tree)
|
||||
|
|
@ -3271,6 +3268,8 @@ void Item_func_group_concat::clear()
|
|||
reset_tree(tree);
|
||||
if (unique_filter)
|
||||
unique_filter->reset();
|
||||
if (table && table->blob_storage)
|
||||
table->blob_storage->reset();
|
||||
/* No need to reset the table as we never call write_row */
|
||||
}
|
||||
|
||||
|
|
@ -3397,6 +3396,7 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||
{
|
||||
List<Item> list;
|
||||
SELECT_LEX *select_lex= thd->lex->current_select;
|
||||
const bool order_or_distinct= MY_TEST(arg_count_order > 0 || distinct);
|
||||
DBUG_ENTER("Item_func_group_concat::setup");
|
||||
|
||||
/*
|
||||
|
|
@ -3409,9 +3409,6 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||
if (!(tmp_table_param= new TMP_TABLE_PARAM))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/* We'll convert all blobs to varchar fields in the temporary table */
|
||||
tmp_table_param->convert_blob_length= max_length *
|
||||
collation.collation->mbmaxlen;
|
||||
/* Push all not constant fields to the list and create a temp table */
|
||||
always_null= 0;
|
||||
for (uint i= 0; i < arg_count_field; i++)
|
||||
|
|
@ -3451,17 +3448,8 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||
count_field_types(select_lex, tmp_table_param, all_fields, 0);
|
||||
tmp_table_param->force_copy_fields= force_copy_fields;
|
||||
DBUG_ASSERT(table == 0);
|
||||
if (arg_count_order > 0 || distinct)
|
||||
if (order_or_distinct)
|
||||
{
|
||||
/*
|
||||
Currently we have to force conversion of BLOB values to VARCHAR's
|
||||
if we are to store them in TREE objects used for ORDER BY and
|
||||
DISTINCT. This leads to truncation if the BLOB's size exceeds
|
||||
Field_varstring::MAX_SIZE.
|
||||
*/
|
||||
set_if_smaller(tmp_table_param->convert_blob_length,
|
||||
Field_varstring::MAX_SIZE);
|
||||
|
||||
/*
|
||||
Force the create_tmp_table() to convert BIT columns to INT
|
||||
as we cannot compare two table records containg BIT fields
|
||||
|
|
@ -3495,6 +3483,13 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||
table->file->extra(HA_EXTRA_NO_ROWS);
|
||||
table->no_rows= 1;
|
||||
|
||||
/**
|
||||
Initialize blob_storage if GROUP_CONCAT is used
|
||||
with ORDER BY | DISTINCT and BLOB field count > 0.
|
||||
*/
|
||||
if (order_or_distinct && table->s->blob_fields)
|
||||
table->blob_storage= new Blob_mem_storage();
|
||||
|
||||
/*
|
||||
Need sorting or uniqueness: init tree and choose a function to sort.
|
||||
Don't reserve space for NULLs: if any of gconcat arguments is NULL,
|
||||
|
|
@ -3547,6 +3542,16 @@ String* Item_func_group_concat::val_str(String* str)
|
|||
if (no_appended && tree)
|
||||
/* Tree is used for sorting as in ORDER BY */
|
||||
tree_walk(tree, &dump_leaf_key, this, left_root_right);
|
||||
|
||||
if (table && table->blob_storage &&
|
||||
table->blob_storage->is_truncated_value())
|
||||
{
|
||||
warning_for_row= true;
|
||||
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT),
|
||||
row_count);
|
||||
}
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue