mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
SCRUM
correct sql_alloc, ORDER BY and NULL value in group_concat add comments move test msg_arg add test on NULL
This commit is contained in:
@ -121,7 +121,7 @@ grp ROUND(group_concat(a separator ""))
|
|||||||
1 1
|
1 1
|
||||||
2 23
|
2 23
|
||||||
3 456789
|
3 456789
|
||||||
drop table if exists t1;
|
drop table t1;
|
||||||
create table t1 (grp int, c char(10));
|
create table t1 (grp int, c char(10));
|
||||||
insert into t1 values (1,NULL);
|
insert into t1 values (1,NULL);
|
||||||
insert into t1 values (2,"b");
|
insert into t1 values (2,"b");
|
||||||
@ -132,17 +132,23 @@ insert into t1 values (3,"D");
|
|||||||
insert into t1 values (3,NULL);
|
insert into t1 values (3,NULL);
|
||||||
insert into t1 values (3,NULL);
|
insert into t1 values (3,NULL);
|
||||||
insert into t1 values (3,"D");
|
insert into t1 values (3,"D");
|
||||||
|
insert into t1 values (4,"");
|
||||||
|
insert into t1 values (5,NULL);
|
||||||
select grp,group_concat(c order by c) from t1 group by grp;
|
select grp,group_concat(c order by c) from t1 group by grp;
|
||||||
grp group_concat(c order by c)
|
grp group_concat(c order by c)
|
||||||
1
|
1 NULL
|
||||||
2 b
|
2 b
|
||||||
3 D D E
|
3 D D E
|
||||||
|
4
|
||||||
|
5 NULL
|
||||||
set group_concat_max_len = 5;
|
set group_concat_max_len = 5;
|
||||||
select grp,group_concat(c) from t1 group by grp;
|
select grp,group_concat(c) from t1 group by grp;
|
||||||
grp group_concat(c)
|
grp group_concat(c)
|
||||||
1
|
1 NULL
|
||||||
2 b
|
2 b
|
||||||
3 E D
|
3 E D D
|
||||||
|
4
|
||||||
|
5 NULL
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1250 1 line(s) was(were) cut by group_concat()
|
Warning 1250 1 line(s) was(were) cut by group_concat()
|
||||||
show warnings;
|
show warnings;
|
||||||
|
@ -48,7 +48,7 @@ select grp, ROUND(group_concat(a separator "")) from t1 group by grp;
|
|||||||
|
|
||||||
# Test NULL values
|
# Test NULL values
|
||||||
|
|
||||||
drop table if exists t1;
|
drop table t1;
|
||||||
create table t1 (grp int, c char(10));
|
create table t1 (grp int, c char(10));
|
||||||
insert into t1 values (1,NULL);
|
insert into t1 values (1,NULL);
|
||||||
insert into t1 values (2,"b");
|
insert into t1 values (2,"b");
|
||||||
@ -59,6 +59,8 @@ insert into t1 values (3,"D");
|
|||||||
insert into t1 values (3,NULL);
|
insert into t1 values (3,NULL);
|
||||||
insert into t1 values (3,NULL);
|
insert into t1 values (3,NULL);
|
||||||
insert into t1 values (3,"D");
|
insert into t1 values (3,"D");
|
||||||
|
insert into t1 values (4,"");
|
||||||
|
insert into t1 values (5,NULL);
|
||||||
select grp,group_concat(c order by c) from t1 group by grp;
|
select grp,group_concat(c order by c) from t1 group by grp;
|
||||||
|
|
||||||
# Test warnings
|
# Test warnings
|
||||||
|
376
sql/item_sum.cc
376
sql/item_sum.cc
@ -1331,25 +1331,26 @@ String *Item_sum_udf_str::val_str(String *str)
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function of sort for syntax:
|
function of sort for syntax:
|
||||||
GROUP_CONCAT(DISTINCT expr,...)
|
GROUP_CONCAT(DISTINCT expr,...)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2)
|
static 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* item= (Item_func_group_concat*)arg;
|
||||||
/*
|
for (int i= 0; i<item->arg_count_field; i++)
|
||||||
DISTINCT
|
|
||||||
*/
|
|
||||||
for (int i=0; i<item->arg_count_field; i++)
|
|
||||||
{
|
{
|
||||||
Item *field_item=item->expr[i];
|
Item *field_item= item->expr[i];
|
||||||
Field *field = field_item->tmp_table_field();
|
Field *field= field_item->tmp_table_field();
|
||||||
if (field)
|
if (field)
|
||||||
{
|
{
|
||||||
uint offset = field->offset();
|
uint offset= field->offset();
|
||||||
|
|
||||||
int res = field->key_cmp(key1 + offset, key2 + 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)
|
if (res)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1358,60 +1359,54 @@ static int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function of sort for syntax:
|
function of sort for syntax:
|
||||||
GROUP_CONCAT(expr,... ORDER BY col,... )
|
GROUP_CONCAT(expr,... ORDER BY col,... )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
|
static 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* item= (Item_func_group_concat*)arg;
|
||||||
/*
|
|
||||||
ORDER
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (int i=0; i<item->arg_count_order; i++)
|
for (int i=0; i<item->arg_count_order; i++)
|
||||||
{
|
{
|
||||||
ORDER *order_item = item->order[i];
|
ORDER *order_item= item->order[i];
|
||||||
Item *item=*order_item->item;
|
Item *item= *order_item->item;
|
||||||
Field *field = item->tmp_table_field();
|
Field *field= item->tmp_table_field();
|
||||||
if (field)
|
if (field)
|
||||||
{
|
{
|
||||||
uint offset = field->offset();
|
uint offset= field->offset();
|
||||||
|
|
||||||
bool dir = order_item->asc;
|
bool dir= order_item->asc;
|
||||||
int res = field->key_cmp(key1 + offset, key2 + offset);
|
int res= field->key_cmp(key1 + offset, key2 + offset);
|
||||||
if (res)
|
if (res)
|
||||||
return dir ? res : -res;
|
return dir ? res : -res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
We can't return 0 becouse tree class remove this item as dubl value.
|
||||||
|
*/
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function of sort for syntax:
|
function of sort for syntax:
|
||||||
GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
|
GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
|
||||||
*/
|
|
||||||
static int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2)
|
|
||||||
{
|
|
||||||
Item_func_group_concat* item = (Item_func_group_concat*)arg;
|
|
||||||
/*
|
|
||||||
DISTINCT
|
|
||||||
*/
|
|
||||||
if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
|
|
||||||
return 0;
|
|
||||||
/*
|
|
||||||
ORDER
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2)
|
||||||
|
{
|
||||||
|
Item_func_group_concat* item= (Item_func_group_concat*)arg;
|
||||||
|
if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
|
||||||
|
return 0;
|
||||||
return(group_concat_key_cmp_with_order(arg,key1,key2));
|
return(group_concat_key_cmp_with_order(arg,key1,key2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
create result
|
create result
|
||||||
item is pointer to Item_func_group_concat
|
item is pointer to Item_func_group_concat
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
|
static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
|
||||||
Item_func_group_concat *item)
|
Item_func_group_concat *group_concat_item)
|
||||||
{
|
{
|
||||||
char buff[MAX_FIELD_WIDTH];
|
char buff[MAX_FIELD_WIDTH];
|
||||||
String tmp((char *)&buff,sizeof(buff),default_charset_info);
|
String tmp((char *)&buff,sizeof(buff),default_charset_info);
|
||||||
@ -1419,65 +1414,59 @@ static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
|
|||||||
|
|
||||||
tmp.length(0);
|
tmp.length(0);
|
||||||
|
|
||||||
for (int i=0; i < item->arg_show_fields; i++)
|
for (int i= 0; i < group_concat_item->arg_show_fields; i++)
|
||||||
{
|
{
|
||||||
Item *show_item = item->expr[i];
|
Item *show_item= group_concat_item->expr[i];
|
||||||
if (!show_item->const_item())
|
if (!show_item->const_item())
|
||||||
{
|
{
|
||||||
Field *f = show_item->tmp_table_field();
|
Field *f= show_item->tmp_table_field();
|
||||||
uint offset = f->offset();
|
uint offset= f->offset();
|
||||||
char *sv = f->ptr;
|
char *sv= f->ptr;
|
||||||
f->ptr = (char *)key + offset;
|
f->ptr= (char *)key + offset;
|
||||||
/*
|
String *res= f->val_str(&tmp,&tmp2);
|
||||||
We can't check this field on NULL, becouse if f->is_null() return that the
|
group_concat_item->result.append(*res);
|
||||||
first field is NULL than it return and that all fields are NULL too. Maybe
|
f->ptr= sv;
|
||||||
is it bag?
|
|
||||||
*/
|
|
||||||
String *res = f->val_str(&tmp,&tmp2);
|
|
||||||
if (res)
|
|
||||||
item->result.append(*res);
|
|
||||||
f->ptr = sv;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String *res = show_item->val_str(&tmp);
|
String *res= show_item->val_str(&tmp);
|
||||||
if (res)
|
if (res)
|
||||||
item->result.append(*res);
|
group_concat_item->result.append(*res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item->show_elements++;
|
if (group_concat_item->tree_mode) // Last item of tree
|
||||||
if (item->tree_mode)
|
|
||||||
{
|
{
|
||||||
/*
|
group_concat_item->show_elements++;
|
||||||
Last item of tree
|
if (group_concat_item->show_elements <
|
||||||
*/
|
group_concat_item->tree->elements_in_tree)
|
||||||
if (item->show_elements < item->tree->elements_in_tree)
|
group_concat_item->result.append(*group_concat_item->separator);
|
||||||
item->result.append(*item->separator);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->result.append(*item->separator);
|
group_concat_item->result.append(*group_concat_item->separator);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if length of result more than group_concat_max_len - stop !
|
if length of result more than group_concat_max_len - stop !
|
||||||
*/
|
*/
|
||||||
if (item->result.length() > item->group_concat_max_len)
|
if (group_concat_item->result.length() >
|
||||||
|
group_concat_item->group_concat_max_len)
|
||||||
{
|
{
|
||||||
item->count_cut_values++;
|
group_concat_item->count_cut_values++;
|
||||||
item->result.length(item->group_concat_max_len);
|
group_concat_item->result.length(group_concat_item->group_concat_max_len);
|
||||||
item->warning_for_row = TRUE;
|
group_concat_item->warning_for_row= TRUE;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Constructor of Item_func_group_concat
|
Constructor of Item_func_group_concat
|
||||||
is_distinct - distinct
|
is_distinct - distinct
|
||||||
is_select - list of expression for show values
|
is_select - list of expression for show values
|
||||||
is_order - list of sort columns
|
is_order - list of sort columns
|
||||||
is_separator - string value of separator
|
is_separator - string value of separator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item_func_group_concat::Item_func_group_concat(int is_distinct,List<Item> *is_select,
|
Item_func_group_concat::Item_func_group_concat(int is_distinct,List<Item> *is_select,
|
||||||
SQL_LIST *is_order,String *is_separator):
|
SQL_LIST *is_order,String *is_separator):
|
||||||
Item_sum(),
|
Item_sum(),
|
||||||
@ -1486,67 +1475,71 @@ Item_func_group_concat::Item_func_group_concat(int is_distinct,List<Item> *is_se
|
|||||||
separator(is_separator),
|
separator(is_separator),
|
||||||
tree(&tree_base),
|
tree(&tree_base),
|
||||||
table(0),
|
table(0),
|
||||||
distinct(is_distinct),
|
distinct(is_distinct),
|
||||||
tree_mode(0),
|
tree_mode(0),
|
||||||
count_cut_values(0)
|
count_cut_values(0)
|
||||||
{
|
{
|
||||||
original = 0;
|
original= 0;
|
||||||
quick_group = 0;
|
quick_group= 0;
|
||||||
mark_as_sum_func();
|
mark_as_sum_func();
|
||||||
SELECT_LEX *select_lex= current_lex->current_select->select_lex();
|
SELECT_LEX *select_lex= current_lex->current_select->select_lex();
|
||||||
|
order= 0;
|
||||||
|
|
||||||
arg_show_fields = arg_count_field = is_select->elements;
|
arg_show_fields= arg_count_field= is_select->elements;
|
||||||
arg_count_order = is_order ? is_order->elements : 0;
|
arg_count_order= is_order ? is_order->elements : 0;
|
||||||
arg_count = arg_count_field;
|
arg_count= arg_count_field;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fill args items of show and sort
|
We need to allocate:
|
||||||
*/
|
args - arg_count+arg_count_order (for possible order items in temporare
|
||||||
int i = 0;
|
tables)
|
||||||
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))&&
|
expr - arg_count_field
|
||||||
(expr=(Item**)sql_alloc(sizeof(Item*)*arg_count_field)))
|
order - arg_count_order
|
||||||
{
|
*/
|
||||||
List_iterator_fast<Item> li(*is_select);
|
args= (Item**)sql_alloc(sizeof(Item*)*(arg_count+arg_count_order+arg_count_field)+
|
||||||
Item *item_select;
|
sizeof(ORDER*)*arg_count_order);
|
||||||
|
if (!args)
|
||||||
while ((item_select=li++))
|
|
||||||
{
|
|
||||||
args[i] = item_select;
|
|
||||||
expr[i] = item_select;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_count_order)
|
|
||||||
{
|
|
||||||
order=(ORDER**)sql_alloc(sizeof(ORDER*)*arg_count_order);
|
|
||||||
if (order)
|
|
||||||
{
|
|
||||||
uint j = 0;
|
|
||||||
for (ORDER *order_item = (ORDER*)is_order->first;
|
|
||||||
order_item != NULL;
|
|
||||||
order_item = order_item->next)
|
|
||||||
{
|
|
||||||
order[j++] = order_item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
my_error(ER_OUTOFMEMORY,MYF(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
order = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
my_error(ER_OUTOFMEMORY,MYF(0));
|
my_error(ER_OUTOFMEMORY,MYF(0));
|
||||||
|
}
|
||||||
|
expr= args;
|
||||||
|
expr+= arg_count+arg_count_order;
|
||||||
|
if (arg_count_order)
|
||||||
|
{
|
||||||
|
order= (ORDER**)(expr + arg_count_field);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
fill args items of show and sort
|
||||||
|
*/
|
||||||
|
int i= 0;
|
||||||
|
List_iterator_fast<Item> li(*is_select);
|
||||||
|
Item *item_select;
|
||||||
|
|
||||||
|
while ((item_select= li++))
|
||||||
|
{
|
||||||
|
args[i]= expr[i]= item_select;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order)
|
||||||
|
{
|
||||||
|
uint j= 0;
|
||||||
|
for (ORDER *order_item= (ORDER*)is_order->first;
|
||||||
|
order_item != NULL;
|
||||||
|
order_item= order_item->next)
|
||||||
|
{
|
||||||
|
order[j++]= order_item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item_func_group_concat::~Item_func_group_concat()
|
Item_func_group_concat::~Item_func_group_concat()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
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 )
|
||||||
|
*/
|
||||||
if (!original)
|
if (!original)
|
||||||
{
|
{
|
||||||
if (warning_available)
|
if (warning_available)
|
||||||
@ -1569,7 +1562,8 @@ void Item_func_group_concat::reset()
|
|||||||
{
|
{
|
||||||
result.length(0);
|
result.length(0);
|
||||||
result.copy();
|
result.copy();
|
||||||
warning_for_row = false;
|
null_value= TRUE;
|
||||||
|
warning_for_row= false;
|
||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||||
@ -1581,20 +1575,30 @@ void Item_func_group_concat::reset()
|
|||||||
add();
|
add();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_func_group_concat::add()
|
bool Item_func_group_concat::add()
|
||||||
{
|
{
|
||||||
copy_fields(tmp_table_param);
|
copy_fields(tmp_table_param);
|
||||||
copy_funcs(tmp_table_param->items_to_copy);
|
copy_funcs(tmp_table_param->items_to_copy);
|
||||||
|
|
||||||
|
bool record_is_null= TRUE;
|
||||||
|
for (int i= 0; i < arg_show_fields; i++)
|
||||||
|
{
|
||||||
|
Item *show_item= expr[i];
|
||||||
|
if (!show_item->const_item())
|
||||||
|
{
|
||||||
|
Field *f= show_item->tmp_table_field();
|
||||||
|
if (!f->is_null())
|
||||||
|
record_is_null= FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (record_is_null)
|
||||||
|
return 0;
|
||||||
|
null_value= FALSE;
|
||||||
if (tree_mode)
|
if (tree_mode)
|
||||||
{
|
{
|
||||||
if (tree->elements_in_tree > max_elements_in_tree)
|
if (!tree_insert(tree, table->record[0], 0,tree->custom_arg))
|
||||||
return 1;
|
return 1;
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!tree_insert(tree, table->record[0], 0,tree->custom_arg))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1605,13 +1609,14 @@ bool Item_func_group_concat::add()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func_group_concat::reset_field()
|
void Item_func_group_concat::reset_field()
|
||||||
{
|
{
|
||||||
if (tree_mode)
|
if (tree_mode)
|
||||||
reset_tree(tree);
|
reset_tree(tree);
|
||||||
(void) add();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
||||||
{
|
{
|
||||||
@ -1621,38 +1626,43 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->allow_sum_func=0;
|
thd->allow_sum_func= 0;
|
||||||
maybe_null=0;
|
maybe_null= 0;
|
||||||
for (uint i=0 ; i < arg_count ; i++)
|
for (uint i= 0 ; i < arg_count ; i++)
|
||||||
{
|
{
|
||||||
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
|
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
|
||||||
return 1;
|
return 1;
|
||||||
maybe_null |= args[i]->maybe_null;
|
maybe_null |= args[i]->maybe_null;
|
||||||
}
|
}
|
||||||
for (int i=0 ; i < arg_count_field ; i++)
|
for (int i= 0 ; i < arg_count_field ; i++)
|
||||||
{
|
{
|
||||||
if (expr[i]->fix_fields(thd, tables, expr + i) || expr[i]->check_cols(1))
|
if (expr[i]->fix_fields(thd, tables, expr + i) || expr[i]->check_cols(1))
|
||||||
return 1;
|
return 1;
|
||||||
maybe_null |= expr[i]->maybe_null;
|
maybe_null |= expr[i]->maybe_null;
|
||||||
}
|
}
|
||||||
for (int i=0 ; i < arg_count_order ; i++)
|
/*
|
||||||
|
Fix fields for order clause in function:
|
||||||
|
GROUP_CONCAT(expr,... ORDER BY col,... )
|
||||||
|
*/
|
||||||
|
for (int i= 0 ; i < arg_count_order ; i++)
|
||||||
{
|
{
|
||||||
ORDER *order_item = order[i];
|
ORDER *order_item= order[i];
|
||||||
Item *item=*order_item->item;
|
Item *item=*order_item->item;
|
||||||
if (item->fix_fields(thd, tables, &item) || item->check_cols(1))
|
if (item->fix_fields(thd, tables, &item) || item->check_cols(1))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
result_field=0;
|
result_field= 0;
|
||||||
null_value=1;
|
null_value= 1;
|
||||||
fix_length_and_dec();
|
fix_length_and_dec();
|
||||||
thd->allow_sum_func=1;
|
thd->allow_sum_func= 1;
|
||||||
if (!(tmp_table_param= new TMP_TABLE_PARAM))
|
if (!(tmp_table_param= new TMP_TABLE_PARAM))
|
||||||
return 1;
|
return 1;
|
||||||
tables_list = tables;
|
tables_list= tables;
|
||||||
fixed= 1;
|
fixed= 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_func_group_concat::setup(THD *thd)
|
bool Item_func_group_concat::setup(THD *thd)
|
||||||
{
|
{
|
||||||
List<Item> list;
|
List<Item> list;
|
||||||
@ -1660,19 +1670,19 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||||||
|
|
||||||
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
|
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
|
||||||
return 1;
|
return 1;
|
||||||
/*
|
/*
|
||||||
all not constant fields are push to list and create temp table
|
all not constant fields are push to list and create temp table
|
||||||
*/
|
*/
|
||||||
for (uint i=0; i < arg_count; i++)
|
for (uint i= 0; i < arg_count; i++)
|
||||||
{
|
{
|
||||||
Item *item=args[i];
|
Item *item= args[i];
|
||||||
if (list.push_back(item))
|
if (list.push_back(item))
|
||||||
return 1;
|
return 1;
|
||||||
if (item->const_item())
|
if (item->const_item())
|
||||||
{
|
{
|
||||||
(void) item->val_int();
|
(void) item->val_int();
|
||||||
if (item->null_value)
|
if (item->null_value)
|
||||||
always_null=1;
|
always_null= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,63 +1692,59 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||||||
bool hidden_group_fields;
|
bool hidden_group_fields;
|
||||||
setup_group(thd, args, tables_list, list, all_fields, *order,
|
setup_group(thd, args, tables_list, list, all_fields, *order,
|
||||||
&hidden_group_fields);
|
&hidden_group_fields);
|
||||||
/*
|
|
||||||
check wrong cols in order list (incorrect number of coloum or value of name)
|
|
||||||
*/
|
|
||||||
for (int i=0; i<arg_count_order; i++)
|
|
||||||
{
|
|
||||||
ORDER *order_item = order[i];
|
|
||||||
Item *item=*order_item->item;
|
|
||||||
if (item->const_item())
|
|
||||||
{
|
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
|
||||||
MYF(0),item->full_name(),thd->where);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count_field_types(tmp_table_param,all_fields,0);
|
count_field_types(tmp_table_param,all_fields,0);
|
||||||
if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, order?*order:0,
|
/*
|
||||||
0, 0, 0,select_lex->options | thd->options/*, select_lex->master_unit()*/)))
|
We have to create a temporary table for that we get descriptions of fields
|
||||||
|
(types, sizes and so on).
|
||||||
|
*/
|
||||||
|
if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
|
||||||
|
0, 0, 0,select_lex->options | thd->options)))
|
||||||
return 1;
|
return 1;
|
||||||
table->file->extra(HA_EXTRA_NO_ROWS);
|
table->file->extra(HA_EXTRA_NO_ROWS);
|
||||||
table->no_rows=1;
|
table->no_rows= 1;
|
||||||
qsort_cmp2 compare_key;
|
qsort_cmp2 compare_key;
|
||||||
|
|
||||||
tree_mode = distinct || arg_count_order;
|
tree_mode= distinct || arg_count_order;
|
||||||
/*
|
/*
|
||||||
choise function of sort
|
choise function of sort
|
||||||
*/
|
*/
|
||||||
if (tree_mode)
|
if (tree_mode)
|
||||||
{
|
{
|
||||||
if (arg_count_order)
|
if (arg_count_order)
|
||||||
{
|
{
|
||||||
if (distinct)
|
if (distinct)
|
||||||
compare_key = (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
|
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
|
||||||
else
|
else
|
||||||
compare_key = (qsort_cmp2) group_concat_key_cmp_with_order;
|
compare_key= (qsort_cmp2) group_concat_key_cmp_with_order;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (distinct)
|
if (distinct)
|
||||||
compare_key = (qsort_cmp2) group_concat_key_cmp_with_distinct;
|
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
|
||||||
else
|
else
|
||||||
compare_key = NULL;
|
compare_key= NULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Create tree of sort
|
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
|
||||||
|
contain DISTINCT and ORDER BY clauses, we don't create this tree.
|
||||||
|
*/
|
||||||
init_tree(tree, min(thd->variables.max_heap_table_size,
|
init_tree(tree, min(thd->variables.max_heap_table_size,
|
||||||
thd->variables.sortbuff_size/16), 0,
|
thd->variables.sortbuff_size/16), 0,
|
||||||
table->reclength, compare_key, 0, NULL, (void*) this);
|
table->reclength, compare_key, 0, NULL, (void*) this);
|
||||||
max_elements_in_tree = ((table->reclength) ?
|
max_elements_in_tree= ((table->reclength) ?
|
||||||
thd->variables.max_heap_table_size/table->reclength : 1);
|
thd->variables.max_heap_table_size/table->reclength : 1);
|
||||||
};
|
};
|
||||||
item_thd = thd;
|
item_thd= thd;
|
||||||
|
|
||||||
group_concat_max_len = thd->variables.group_concat_max_len;
|
group_concat_max_len= thd->variables.group_concat_max_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy table and tree_mode if they belong to this item (if item have not
|
||||||
|
pointer to original item from which was made copy => it own its objects)
|
||||||
|
*/
|
||||||
if (original)
|
if (original)
|
||||||
{
|
{
|
||||||
original->table= table;
|
original->table= table;
|
||||||
@ -1749,9 +1755,11 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||||||
|
|
||||||
String* Item_func_group_concat::val_str(String* str)
|
String* Item_func_group_concat::val_str(String* str)
|
||||||
{
|
{
|
||||||
|
if (null_value)
|
||||||
|
return 0;
|
||||||
if (tree_mode)
|
if (tree_mode)
|
||||||
{
|
{
|
||||||
show_elements = 0;
|
show_elements= 0;
|
||||||
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
|
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
|
||||||
left_root_right);
|
left_root_right);
|
||||||
}
|
}
|
||||||
@ -1760,12 +1768,10 @@ String* Item_func_group_concat::val_str(String* str)
|
|||||||
if (!warning_for_row)
|
if (!warning_for_row)
|
||||||
result.length(result.length()-separator->length());
|
result.length(result.length()-separator->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
null_value = result.length() == 0;
|
|
||||||
if (count_cut_values && !warning_available)
|
if (count_cut_values && !warning_available)
|
||||||
{
|
{
|
||||||
warning_available=TRUE;
|
warning_available= TRUE;
|
||||||
warning = push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
ER_CUT_VALUE_GROUP_CONCAT, NULL);
|
ER_CUT_VALUE_GROUP_CONCAT, NULL);
|
||||||
}
|
}
|
||||||
return &result;
|
return &result;
|
||||||
|
@ -327,12 +327,12 @@ public:
|
|||||||
const char *msg_arg)
|
const char *msg_arg)
|
||||||
:code(code_arg), level(level_arg)
|
:code(code_arg), level(level_arg)
|
||||||
{
|
{
|
||||||
set_msg(msg_arg);
|
if (msg_arg)
|
||||||
|
msg=sql_strdup(msg_arg);
|
||||||
}
|
}
|
||||||
inline void set_msg(const char *msg_arg)
|
inline void set_msg(const char *msg_arg)
|
||||||
{
|
{
|
||||||
if (msg_arg)
|
msg=sql_strdup(msg_arg);
|
||||||
msg=sql_strdup(msg_arg);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user