summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
authorpem@mysql.com <>2004-04-07 19:07:44 +0200
committerpem@mysql.com <>2004-04-07 19:07:44 +0200
commitdfd59e296e2c267a21f1ea8b3b937e07730dad0d (patch)
treee5ac1517ff3dccc42352b7bac39ecd1c093d0ae6 /sql/item_sum.cc
parent1541f2e7949416d6e172ef6406ecf140d3b26659 (diff)
parent61fd95d168b51092b7ce3ff56b2c8c8ed1a49c0f (diff)
downloadmariadb-git-dfd59e296e2c267a21f1ea8b3b937e07730dad0d.tar.gz
Merge 4.1 -> 5.0.
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc453
1 files changed, 298 insertions, 155 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 6507e826b7e..7b2b00b18c6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -24,8 +24,8 @@
#include "mysql_priv.h"
Item_sum::Item_sum(List<Item> &list)
+ :args_copy(0), arg_count(list.elements)
{
- arg_count=list.elements;
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
uint i=0;
@@ -41,20 +41,57 @@ Item_sum::Item_sum(List<Item> &list)
list.empty(); // Fields are used
}
-// Constructor used in processing select with temporary tebles
+
+/*
+ Constructor used in processing select with temporary tebles
+*/
+
Item_sum::Item_sum(THD *thd, Item_sum *item):
- Item_result_field(thd, item), quick_group(item->quick_group)
+ Item_result_field(thd, item), arg_count(item->arg_count),
+ quick_group(item->quick_group)
{
- arg_count= item->arg_count;
if (arg_count <= 2)
args=tmp_args;
else
- if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
+ if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
return;
- for (uint i= 0; i < arg_count; i++)
- args[i]= item->args[i];
+ memcpy(args, item->args, sizeof(Item*)*arg_count);
+ if (item->args_copy != 0)
+ save_args(thd);
+ else
+ args_copy= 0;
}
+
+/*
+ Save copy of arguments if we are prepare prepared statement
+ (arguments can be rewritten in get_tmp_table_item())
+
+ SYNOPSIS
+ Item_sum::save_args_for_prepared_statements()
+ thd - thread handler
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+bool Item_sum::save_args_for_prepared_statements(THD *thd)
+{
+ if (thd->current_statement)
+ return save_args(thd->current_statement);
+ return 0;
+}
+
+
+bool Item_sum::save_args(Statement* stmt)
+{
+ if (!(args_copy= (Item**) stmt->alloc(sizeof(Item*)*arg_count)))
+ return 1;
+ memcpy(args_copy, args, sizeof(Item*)*arg_count);
+ return 0;
+}
+
+
void Item_sum::mark_as_sum_func()
{
current_thd->lex->current_select->with_sum_func= 1;
@@ -62,6 +99,17 @@ void Item_sum::mark_as_sum_func()
}
+void Item_sum::cleanup()
+{
+ DBUG_ENTER("Item_sum::cleanup");
+ Item_result_field::cleanup();
+ if (args_copy != 0)
+ memcpy(args, args_copy, sizeof(Item*)*arg_count);
+ result_field=0;
+ DBUG_VOID_RETURN;
+}
+
+
void Item_sum::make_field(Send_field *tmp_field)
{
if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
@@ -137,6 +185,7 @@ bool Item_sum::walk (Item_processor processor, byte *argument)
String *
Item_sum_num::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
double nr=val();
if (null_value)
return 0;
@@ -148,6 +197,7 @@ Item_sum_num::val_str(String *str)
String *
Item_sum_int::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
longlong nr= val_int();
if (null_value)
return 0;
@@ -162,6 +212,11 @@ Item_sum_int::val_str(String *str)
bool
Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ DBUG_ASSERT(fixed == 0);
+
+ if (save_args_for_prepared_statements(thd))
+ return 1;
+
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
@@ -191,17 +246,26 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- Item *item=args[0];
+ DBUG_ASSERT(fixed == 0);
+
+ if (save_args_for_prepared_statements(thd))
+ return 1;
+
+ Item *item= args[0];
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
return 1;
}
thd->allow_sum_func=0; // No included group funcs
+
+ // 'item' can be changed during fix_fields
if (!item->fixed &&
- item->fix_fields(thd, tables, args) || item->check_cols(1))
+ item->fix_fields(thd, tables, args) ||
+ (item= args[0])->check_cols(1))
return 1;
- hybrid_type=item->result_type();
+
+ hybrid_type= item->result_type();
if (hybrid_type == INT_RESULT)
{
cmp_charset= &my_charset_bin;
@@ -261,6 +325,7 @@ bool Item_sum_sum::add()
double Item_sum_sum::val()
{
+ DBUG_ASSERT(fixed == 1);
return sum;
}
@@ -408,6 +473,7 @@ bool Item_sum_count::add()
longlong Item_sum_count::val_int()
{
+ DBUG_ASSERT(fixed == 1);
return (longlong) count;
}
@@ -440,6 +506,7 @@ bool Item_sum_avg::add()
double Item_sum_avg::val()
{
+ DBUG_ASSERT(fixed == 1);
if (!count)
{
null_value=1;
@@ -456,6 +523,7 @@ double Item_sum_avg::val()
double Item_sum_std::val()
{
+ DBUG_ASSERT(fixed == 1);
double tmp= Item_sum_variance::val();
return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
@@ -496,6 +564,7 @@ bool Item_sum_variance::add()
double Item_sum_variance::val()
{
+ DBUG_ASSERT(fixed == 1);
if (!count)
{
null_value=1;
@@ -551,6 +620,7 @@ void Item_sum_variance::update_field()
double Item_sum_hybrid::val()
{
+ DBUG_ASSERT(fixed == 1);
int err;
if (null_value)
return 0.0;
@@ -576,6 +646,7 @@ double Item_sum_hybrid::val()
longlong Item_sum_hybrid::val_int()
{
+ DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
if (hybrid_type == INT_RESULT)
@@ -587,6 +658,7 @@ longlong Item_sum_hybrid::val_int()
String *
Item_sum_hybrid::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
switch (hybrid_type) {
@@ -721,6 +793,7 @@ bool Item_sum_max::add()
longlong Item_sum_bit::val_int()
{
+ DBUG_ASSERT(fixed == 1);
return (longlong) bits;
}
@@ -1054,6 +1127,7 @@ Item_avg_field::Item_avg_field(Item_sum_avg *item)
double Item_avg_field::val()
{
+ // fix_fields() never calls for this Item
double nr;
longlong count;
float8get(nr,field->ptr);
@@ -1071,6 +1145,7 @@ double Item_avg_field::val()
String *Item_avg_field::val_str(String *str)
{
+ // fix_fields() never calls for this Item
double nr=Item_avg_field::val();
if (null_value)
return 0;
@@ -1085,6 +1160,7 @@ Item_std_field::Item_std_field(Item_sum_std *item)
double Item_std_field::val()
{
+ // fix_fields() never calls for this Item
double tmp= Item_variance_field::val();
return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
@@ -1100,6 +1176,7 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
double Item_variance_field::val()
{
+ // fix_fields() never calls for this Item
double sum,sum_sqr;
longlong count;
float8get(sum,field->ptr);
@@ -1119,6 +1196,7 @@ double Item_variance_field::val()
String *Item_variance_field::val_str(String *str)
{
+ // fix_fields() never calls for this Item
double nr=val();
if (null_value)
return 0;
@@ -1195,6 +1273,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
void Item_sum_count_distinct::cleanup()
{
+ DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup();
/*
Free table and tree if they belong to this item (if item have not pointer
@@ -1215,17 +1294,10 @@ void Item_sum_count_distinct::cleanup()
use_tree= 0;
}
}
+ DBUG_VOID_RETURN;
}
-bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
- Item **ref)
-{
- if (Item_sum_num::fix_fields(thd, tables, ref))
- return 1;
- return 0;
-}
-
/* This is used by rollup to create a separate usable copy of the function */
void Item_sum_count_distinct::make_unique()
@@ -1458,6 +1530,7 @@ bool Item_sum_count_distinct::add()
longlong Item_sum_count_distinct::val_int()
{
+ DBUG_ASSERT(fixed == 1);
if (!table) // Empty query
return LL(0);
if (use_tree)
@@ -1504,6 +1577,7 @@ Item *Item_sum_udf_float::copy_or_same(THD* thd)
double Item_sum_udf_float::val()
{
+ DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_float::val");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
@@ -1512,6 +1586,7 @@ double Item_sum_udf_float::val()
String *Item_sum_udf_float::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
@@ -1528,6 +1603,7 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd)
longlong Item_sum_udf_int::val_int()
{
+ DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_int::val_int");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
@@ -1537,6 +1613,7 @@ longlong Item_sum_udf_int::val_int()
String *Item_sum_udf_int::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
longlong nr=val_int();
if (null_value)
return 0;
@@ -1564,6 +1641,7 @@ Item *Item_sum_udf_str::copy_or_same(THD* thd)
String *Item_sum_udf_str::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_str::str");
String *res=udf.val_str(str,&str_value);
null_value = !res;
@@ -1575,10 +1653,17 @@ String *Item_sum_udf_str::val_str(String *str)
/*****************************************************************************
GROUP_CONCAT function
- Syntax:
- GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
- [SEPARATOR str_const])
+
+ SQL SYNTAX:
+ GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
+ [SEPARATOR str_const])
+
concat of values from "group by" operation
+
+ BUGS
+ DISTINCT and ORDER BY only works if ORDER BY uses all fields and only fields
+ in expression list
+ Blobs doesn't work with DISTINCT or ORDER BY
*****************************************************************************/
/*
@@ -1589,25 +1674,28 @@ String *Item_sum_udf_str::val_str(String *str)
int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
byte* key2)
{
- Item_func_group_concat* item= (Item_func_group_concat*)arg;
+ Item_func_group_concat* grp_item= (Item_func_group_concat*)arg;
+ Item **field_item, **end;
+ char *record= (char*) grp_item->table->record[0];
- for (uint i= 0; i < item->arg_count_field; i++)
+ for (field_item= grp_item->args, end= field_item + grp_item->arg_count_field;
+ field_item < end;
+ field_item++)
{
- Item *field_item= item->args[i];
- Field *field= field_item->real_item()->get_tmp_table_field();
+ /*
+ We have to use get_tmp_table_field() instead of
+ real_item()->get_tmp_table_field() because we want the field in
+ the temporary table, not the original field
+ */
+ Field *field= (*field_item)->get_tmp_table_field();
if (field)
{
- uint offset= field->abs_offset;
-
- int res= field->key_cmp(key1 + offset, key2 + offset);
- /*
- if key1 and key2 is not equal than field->key_cmp return offset. This
- function must return value 1 for this case.
- */
- if (res)
- return 1;
+ int res;
+ uint offset= (uint) (field->ptr - record);
+ if ((res= field->key_cmp(key1 + offset, key2 + offset)))
+ return res;
}
- }
+ }
return 0;
}
@@ -1619,26 +1707,34 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
{
- Item_func_group_concat* item= (Item_func_group_concat*)arg;
+ Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
+ ORDER **order_item, **end;
+ char *record= (char*) grp_item->table->record[0];
- for (uint i=0; i < item->arg_count_order; i++)
+ for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order;
+ order_item < end;
+ order_item++)
{
- ORDER *order_item= item->order[i];
- Item *item= *order_item->item;
- Field *field= item->real_item()->get_tmp_table_field();
+ Item *item= *(*order_item)->item;
+ /*
+ We have to use get_tmp_table_field() instead of
+ real_item()->get_tmp_table_field() because we want the field in
+ the temporary table, not the original field
+ */
+ Field *field= item->get_tmp_table_field();
if (field)
{
- uint offset= field->abs_offset;
-
- bool dir= order_item->asc;
- int res= field->key_cmp(key1 + offset, key2 + offset);
- if (res)
- return dir ? res : -res;
+ int res;
+ uint offset= (uint) (field->ptr - record);
+ if ((res= field->key_cmp(key1 + offset, key2 + offset)))
+ return (*order_item)->asc ? res : -res;
}
- }
+ }
/*
- We can't return 0 because tree class remove this item as double value.
- */
+ We can't return 0 because in that case the tree class would remove this
+ item as double value. This would cause problems for case-changes and
+ if the the returned values are not the same we do the sort on.
+ */
return 1;
}
@@ -1646,6 +1742,11 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
/*
function of sort for syntax:
GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
+
+ BUG:
+ This doesn't work in the case when the order by contains data that
+ is not part of the field list because tree-insert will not notice
+ the duplicated values when inserting things sorted by ORDER BY
*/
int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
@@ -1658,58 +1759,61 @@ int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
/*
- create result
- item is pointer to Item_func_group_concat
+ Append data from current leaf to item->result
*/
int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
- Item_func_group_concat *group_concat_item)
+ Item_func_group_concat *item)
{
char buff[MAX_FIELD_WIDTH];
- String tmp((char *)&buff,sizeof(buff),default_charset_info);
- String tmp2((char *)&buff,sizeof(buff),default_charset_info);
-
+ String tmp((char*) &buff, sizeof(buff), default_charset_info);
+ String tmp2((char *) &buff, sizeof(buff), default_charset_info);
+ char *record= (char*) item->table->record[0];
+
tmp.length(0);
- for (uint i= 0; i < group_concat_item->arg_show_fields; i++)
+ for (uint i= 0; i < item->arg_count_field; i++)
{
- Item *show_item= group_concat_item->args[i];
+ Item *show_item= item->args[i];
if (!show_item->const_item())
{
- Field *f= show_item->real_item()->get_tmp_table_field();
- char *sv= f->ptr;
- f->ptr= (char *)key + f->abs_offset;
- String *res= f->val_str(&tmp,&tmp2);
- group_concat_item->result.append(*res);
- f->ptr= sv;
+ /*
+ We have to use get_tmp_table_field() instead of
+ real_item()->get_tmp_table_field() because we want the field in
+ the temporary table, not the original field
+ */
+ Field *field= show_item->get_tmp_table_field();
+ String *res;
+ char *save_ptr= field->ptr;
+ uint offset= (uint) (save_ptr - record);
+ DBUG_ASSERT(offset < item->table->reclength);
+ field->ptr= (char *) key + offset;
+ res= field->val_str(&tmp,&tmp2);
+ item->result.append(*res);
+ field->ptr= save_ptr;
}
else
{
String *res= show_item->val_str(&tmp);
if (res)
- group_concat_item->result.append(*res);
+ item->result.append(*res);
}
}
- if (group_concat_item->tree_mode) // Last item of tree
+ if (item->tree_mode) // Last item of tree
{
- group_concat_item->show_elements++;
- if (group_concat_item->show_elements <
- group_concat_item->tree->elements_in_tree)
- group_concat_item->result.append(*group_concat_item->separator);
+ item->show_elements++;
+ if (item->show_elements < item->tree->elements_in_tree)
+ item->result.append(*item->separator);
}
else
+ item->result.append(*item->separator);
+
+ /* stop if length of result more than group_concat_max_len */
+ if (item->result.length() > item->group_concat_max_len)
{
- group_concat_item->result.append(*group_concat_item->separator);
- }
- /*
- if length of result more than group_concat_max_len - stop !
- */
- if (group_concat_item->result.length() >
- group_concat_item->group_concat_max_len)
- {
- group_concat_item->count_cut_values++;
- group_concat_item->result.length(group_concat_item->group_concat_max_len);
- group_concat_item->warning_for_row= TRUE;
+ item->count_cut_values++;
+ item->result.length(item->group_concat_max_len);
+ item->warning_for_row= TRUE;
return 1;
}
return 0;
@@ -1729,60 +1833,97 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
SQL_LIST *is_order,
String *is_separator)
:Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0),
- warning_available(0), key_length(0), rec_offset(0),
+ warning_available(0), key_length(0),
tree_mode(0), distinct(is_distinct), warning_for_row(0),
separator(is_separator), tree(&tree_base), table(0),
order(0), tables_list(0),
show_elements(0), arg_count_order(0), arg_count_field(0),
- arg_show_fields(0), count_cut_values(0)
-
+ count_cut_values(0)
{
+ Item *item_select;
+ Item **arg_ptr;
+
original= 0;
quick_group= 0;
mark_as_sum_func();
order= 0;
group_concat_max_len= current_thd->variables.group_concat_max_len;
-
- arg_show_fields= arg_count_field= is_select->elements;
+ arg_count_field= is_select->elements;
arg_count_order= is_order ? is_order->elements : 0;
- arg_count= arg_count_field;
+ arg_count= arg_count_field + arg_count_order;
/*
We need to allocate:
- args - arg_count+arg_count_order (for possible order items in temporare
- tables)
+ args - arg_count_field+arg_count_order
+ (for possible order items in temporare tables)
order - arg_count_order
*/
- args= (Item**) sql_alloc(sizeof(Item*)*(arg_count+arg_count_order)+
- sizeof(ORDER*)*arg_count_order);
- if (!args)
+ if (!(args= (Item**) sql_alloc(sizeof(Item*) * arg_count +
+ sizeof(ORDER*)*arg_count_order)))
return;
+ order= (ORDER**)(args + arg_count);
+
/* fill args items of show and sort */
- int i= 0;
List_iterator_fast<Item> li(*is_select);
- Item *item_select;
- for ( ; (item_select= li++) ; i++)
- args[i]= item_select;
+ for (arg_ptr=args ; (item_select= li++) ; arg_ptr++)
+ *arg_ptr= item_select;
if (arg_count_order)
{
- i= 0;
- order= (ORDER**)(args + arg_count + arg_count_order);
+ ORDER **order_ptr= order;
for (ORDER *order_item= (ORDER*) is_order->first;
- order_item != NULL;
- order_item= order_item->next)
+ order_item != NULL;
+ order_item= order_item->next)
{
- order[i++]= order_item;
+ (*order_ptr++)= order_item;
+ *arg_ptr= *order_item->item;
+ order_item->item= arg_ptr++;
}
}
}
+
+
+Item_func_group_concat::Item_func_group_concat(THD *thd,
+ Item_func_group_concat *item)
+ :Item_sum(thd, item),item_thd(thd),
+ tmp_table_param(item->tmp_table_param),
+ max_elements_in_tree(item->max_elements_in_tree),
+ warning(item->warning),
+ warning_available(item->warning_available),
+ key_length(item->key_length),
+ tree_mode(item->tree_mode),
+ distinct(item->distinct),
+ warning_for_row(item->warning_for_row),
+ separator(item->separator),
+ tree(item->tree),
+ table(item->table),
+ order(item->order),
+ tables_list(item->tables_list),
+ group_concat_max_len(item->group_concat_max_len),
+ show_elements(item->show_elements),
+ arg_count_order(item->arg_count_order),
+ arg_count_field(item->arg_count_field),
+ field_list_offset(item->field_list_offset),
+ count_cut_values(item->count_cut_values),
+ original(item)
+{
+ quick_group= item->quick_group;
+}
+
void Item_func_group_concat::cleanup()
{
+ DBUG_ENTER("Item_func_group_concat::cleanup");
+ Item_sum::cleanup();
+
+ /* fix order list */
+ for (uint i= 0; i < arg_count_order ; i++)
+ order[i]->item= &order[i]->item_ptr;
+
/*
Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects )
@@ -1803,6 +1944,7 @@ void Item_func_group_concat::cleanup()
delete_tree(tree);
}
}
+ DBUG_VOID_RETURN;
}
@@ -1814,12 +1956,11 @@ Item_func_group_concat::~Item_func_group_concat()
*/
if (!original)
{
- THD *thd= current_thd;
if (warning_available)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
- warning->set_msg(thd, warn_buff);
+ warning->set_msg(current_thd, warn_buff);
}
}
}
@@ -1836,7 +1977,7 @@ void Item_func_group_concat::clear()
result.length(0);
result.copy();
null_value= TRUE;
- warning_for_row= false;
+ warning_for_row= FALSE;
if (table)
{
table->file->extra(HA_EXTRA_NO_CACHE);
@@ -1855,33 +1996,31 @@ bool Item_func_group_concat::add()
copy_fields(tmp_table_param);
copy_funcs(tmp_table_param->items_to_copy);
- bool record_is_null= TRUE;
- for (uint i= 0; i < arg_show_fields; i++)
+ for (uint i= 0; i < arg_count_field; i++)
{
Item *show_item= args[i];
if (!show_item->const_item())
{
+ /*
+ Here we use real_item as we want the original field data that should
+ be written to table->record[0]
+ */
Field *f= show_item->real_item()->get_tmp_table_field();
- if (!f->is_null())
- {
- record_is_null= FALSE;
- break;
- }
+ if (f->is_null())
+ return 0; // Skip row if it contains null
}
}
- if (record_is_null)
- return 0;
+
null_value= FALSE;
if (tree_mode)
{
- if (!tree_insert(tree, table->record[0] + rec_offset, 0, tree->custom_arg))
+ if (!tree_insert(tree, table->record[0], 0, tree->custom_arg))
return 1;
}
else
{
if (result.length() <= group_concat_max_len && !warning_for_row)
- dump_leaf_key(table->record[0] + rec_offset, 1,
- (Item_func_group_concat*)this);
+ dump_leaf_key(table->record[0], 1, this);
}
return 0;
}
@@ -1897,6 +2036,11 @@ void Item_func_group_concat::reset_field()
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ DBUG_ASSERT(fixed == 0);
+
+ if (save_args_for_prepared_statements(thd))
+ return 1;
+
uint i; /* for loop variable */
if (!thd->allow_sum_func)
@@ -1908,24 +2052,19 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
thd->allow_sum_func= 0;
maybe_null= 0;
item_thd= thd;
- for (i= 0 ; i < arg_count ; i++)
- {
- if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
- return 1;
- maybe_null |= args[i]->maybe_null;
- }
+
/*
- Fix fields for order clause in function:
- GROUP_CONCAT(expr,... ORDER BY col,... )
+ Fix fields for select list and ORDER clause
*/
- for (i= 0 ; i < arg_count_order ; i++)
+
+ for (i= 0 ; i < arg_count ; i++)
{
- // order_item->item can be changed by fix_fields() call
- ORDER *order_item= order[i];
- if ((*order_item->item)->fix_fields(thd, tables, order_item->item) ||
- (*order_item->item)->check_cols(1))
+ if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
return 1;
+ if (i < arg_count_field && args[i]->maybe_null)
+ maybe_null= 0;
}
+
result_field= 0;
null_value= 1;
max_length= group_concat_max_len;
@@ -1940,23 +2079,29 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bool Item_func_group_concat::setup(THD *thd)
{
- DBUG_ENTER("Item_func_group_concat::setup");
List<Item> list;
SELECT_LEX *select_lex= thd->lex->current_select;
+ uint const_fields;
+ byte *record;
+ qsort_cmp2 compare_key;
+ DBUG_ENTER("Item_func_group_concat::setup");
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
DBUG_RETURN(1);
+
/*
push all not constant fields to list and create temp table
*/
+ const_fields= 0;
always_null= 0;
- for (uint i= 0; i < arg_count; i++)
+ for (uint i= 0; i < arg_count_field; i++)
{
Item *item= args[i];
if (list.push_back(item))
DBUG_RETURN(1);
if (item->const_item())
{
+ const_fields++;
(void) item->val_int();
if (item->null_value)
always_null= 1;
@@ -1976,12 +2121,19 @@ bool Item_func_group_concat::setup(THD *thd)
count_field_types(tmp_table_param,all_fields,0);
if (table)
{
+ /*
+ We come here when we are getting the result from a temporary table,
+ not the original tables used in the query
+ */
free_tmp_table(thd, table);
tmp_table_param->cleanup();
}
/*
- We have to create a temporary table for that we get descriptions of fields
+ We have to create a temporary table to get descriptions of fields
(types, sizes and so on).
+
+ Note that in the table, we first have the ORDER BY fields, then the
+ field list.
*/
if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
0, 0, 0,select_lex->options | thd->options,
@@ -1990,27 +2142,17 @@ bool Item_func_group_concat::setup(THD *thd)
table->file->extra(HA_EXTRA_NO_ROWS);
table->no_rows= 1;
+ key_length= table->reclength;
+ record= table->record[0];
- Field** field, **field_end;
- field_end = (field = table->field) + table->fields;
- uint offset = 0;
- for (key_length = 0; field < field_end; ++field)
- {
- uint32 length= (*field)->pack_length();
- (*field)->abs_offset= offset;
- offset+= length;
- key_length += length;
- }
- rec_offset = table->reclength - key_length;
-
+ /* Offset to first result field in table */
+ field_list_offset= table->fields - (list.elements - const_fields);
if (tree_mode)
delete_tree(tree);
- /*
- choise function of sort
- */
+
+ /* choose function of sort */
tree_mode= distinct || arg_count_order;
- qsort_cmp2 compare_key;
if (tree_mode)
{
if (arg_count_order)
@@ -2022,21 +2164,20 @@ bool Item_func_group_concat::setup(THD *thd)
}
else
{
+ compare_key= NULL;
if (distinct)
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
- else
- compare_key= NULL;
}
/*
- Create a tree of sort. Tree is used for a sort and a remove dubl
- values (according with syntax of the function). If function does't
+ Create a tree of sort. Tree is used for a sort and a remove double
+ values (according with syntax of the function). If function doesn't
contain DISTINCT and ORDER BY clauses, we don't create this tree.
*/
init_tree(tree, min(thd->variables.max_heap_table_size,
- thd->variables.sortbuff_size/16), 0,
+ thd->variables.sortbuff_size/16), 0,
key_length, compare_key, 0, NULL, (void*) this);
- max_elements_in_tree= ((key_length) ?
- thd->variables.max_heap_table_size/key_length : 1);
+ max_elements_in_tree= (key_length ?
+ thd->variables.max_heap_table_size/key_length : 1);
};
/*
@@ -2051,6 +2192,7 @@ bool Item_func_group_concat::setup(THD *thd)
DBUG_RETURN(0);
}
+
/* This is used by rollup to create a separate usable copy of the function */
void Item_func_group_concat::make_unique()
@@ -2064,6 +2206,7 @@ void Item_func_group_concat::make_unique()
String* Item_func_group_concat::val_str(String* str)
{
+ DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
if (tree_mode)
@@ -2092,7 +2235,7 @@ void Item_func_group_concat::print(String *str)
str->append("group_concat(", 13);
if (distinct)
str->append("distinct ", 9);
- for (uint i= 0; i < arg_count; i++)
+ for (uint i= 0; i < arg_count_field; i++)
{
if (i)
str->append(',');