diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2016-03-01 21:10:59 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2016-03-01 21:10:59 +0100 |
commit | 6c414fcf89510215d6d3466eb9992d444eadae89 (patch) | |
tree | 181c6b01ffe0b78d92f724d91e8315bed81e5f7e /sql/item_sum.cc | |
parent | 66832b619510f5b9724d8db1eac48bdafb9225e9 (diff) | |
download | mariadb-git-6c414fcf89510215d6d3466eb9992d444eadae89.tar.gz |
MDEV-5542: GROUP_CONCAT truncate output to 65.536 chars when using DISTINCT or ORDER BY
port of mysql fix WL#6098
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r-- | sql/item_sum.cc | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc index e44a371d264..1cfee1a9241 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -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,18 +3448,9 @@ 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 stored in the the tree used for distinct/order by. @@ -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; } |