mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Auto merged
BitKeeper/etc/logging_ok: auto-union
This commit is contained in:
commit
aee0d02abd
13 changed files with 879 additions and 43 deletions
|
@ -266,8 +266,5 @@
|
|||
#define ER_SELECT_REDUCED 1247
|
||||
#define ER_TABLENAME_NOT_ALLOWED_HERE 1248
|
||||
#define ER_NOT_SUPPORTED_AUTH_MODE 1249
|
||||
#define ER_SPATIAL_CANT_HAVE_NULL 1250
|
||||
#define ER_COLLATION_CHARSET_MISMATCH 1251
|
||||
#define ER_SLAVE_WAS_RUNNING 1252
|
||||
#define ER_SLAVE_WAS_NOT_RUNNING 1253
|
||||
#define ER_ERROR_MESSAGES 254
|
||||
#define ER_CUT_VALUE_GROUP_CONCAT 1250
|
||||
#define ER_ERROR_MESSAGES 251
|
||||
|
|
161
mysql-test/r/func_gconcat.result
Normal file
161
mysql-test/r/func_gconcat.result
Normal file
|
@ -0,0 +1,161 @@
|
|||
drop table if exists t1;
|
||||
Warnings:
|
||||
Note 1051 Unknown table 't1'
|
||||
create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null);
|
||||
insert into t1 values (1,1,"a","a");
|
||||
insert into t1 values (2,2,"b","a");
|
||||
insert into t1 values (2,3,"c","b");
|
||||
insert into t1 values (3,4,"E","a");
|
||||
insert into t1 values (3,5,"C","b");
|
||||
insert into t1 values (3,6,"D","b");
|
||||
insert into t1 values (3,7,"d","d");
|
||||
insert into t1 values (3,8,"d","d");
|
||||
insert into t1 values (3,9,"D","c");
|
||||
select grp,group_concat(c) from t1 group by grp;
|
||||
grp group_concat(c)
|
||||
1 a
|
||||
2 b c
|
||||
3 E C D d d D
|
||||
select grp,group_concat(a,c) from t1 group by grp;
|
||||
grp group_concat(a,c)
|
||||
1 1a
|
||||
2 2b 3c
|
||||
3 4E 5C 6D 7d 8d 9D
|
||||
select grp,group_concat("(",a,":",c,")") from t1 group by grp;
|
||||
grp group_concat("(",a,":",c,")")
|
||||
1 (1:a)
|
||||
2 (2:b) (3:c)
|
||||
3 (4:E) (5:C) (6:D) (7:d) (8:d) (9:D)
|
||||
select grp,group_concat(c separator ",") from t1 group by grp;
|
||||
grp group_concat(c separator ",")
|
||||
1 a
|
||||
2 b,c
|
||||
3 E,C,D,d,d,D
|
||||
select grp,group_concat(c separator "---->") from t1 group by grp;
|
||||
grp group_concat(c separator "---->")
|
||||
1 a
|
||||
2 b---->c
|
||||
3 E---->C---->D---->d---->d---->D
|
||||
select grp,group_concat(c order by c) from t1 group by grp;
|
||||
grp group_concat(c order by c)
|
||||
1 a
|
||||
2 b c
|
||||
3 C D d d D E
|
||||
select grp,group_concat(c order by c desc) from t1 group by grp;
|
||||
grp group_concat(c order by c desc)
|
||||
1 a
|
||||
2 c b
|
||||
3 E D d d D C
|
||||
select grp,group_concat(d order by a) from t1 group by grp;
|
||||
grp group_concat(d order by a)
|
||||
1 a
|
||||
2 a b
|
||||
3 a b b d d c
|
||||
select grp,group_concat(d order by a desc) from t1 group by grp;
|
||||
grp group_concat(d order by a desc)
|
||||
1 a
|
||||
2 b a
|
||||
3 c d d b b a
|
||||
select grp,group_concat(a order by a,d+c) from t1 group by grp;
|
||||
grp group_concat(a order by a,d+c)
|
||||
1 1
|
||||
2 2 3
|
||||
3 4 5 6 7 8 9
|
||||
select grp,group_concat(c order by 1) from t1 group by grp;
|
||||
grp group_concat(c order by 1)
|
||||
1 a
|
||||
2 b c
|
||||
3 C D d d D E
|
||||
select grp,group_concat(c order by "c") from t1 group by grp;
|
||||
grp group_concat(c order by "c")
|
||||
1 a
|
||||
2 b c
|
||||
3 C D d d D E
|
||||
select grp,group_concat(distinct c order by c) from t1 group by grp;
|
||||
grp group_concat(distinct c order by c)
|
||||
1 a
|
||||
2 b c
|
||||
3 C D E
|
||||
select grp,group_concat(distinct c order by c desc) from t1 group by grp;
|
||||
grp group_concat(distinct c order by c desc)
|
||||
1 a
|
||||
2 c b
|
||||
3 E D C
|
||||
select grp,group_concat(c order by c separator ",") from t1 group by grp;
|
||||
grp group_concat(c order by c separator ",")
|
||||
1 a
|
||||
2 b,c
|
||||
3 C,D,d,d,D,E
|
||||
select grp,group_concat(c order by c desc separator ",") from t1 group by grp;
|
||||
grp group_concat(c order by c desc separator ",")
|
||||
1 a
|
||||
2 c,b
|
||||
3 E,D,d,d,D,C
|
||||
select grp,group_concat(distinct c order by c separator ",") from t1 group by grp;
|
||||
grp group_concat(distinct c order by c separator ",")
|
||||
1 a
|
||||
2 b,c
|
||||
3 C,D,E
|
||||
select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp;
|
||||
grp group_concat(distinct c order by c desc separator ",")
|
||||
1 a
|
||||
2 c,b
|
||||
3 E,D,C
|
||||
select grp,group_concat(c order by grp desc) from t1 group by grp order by grp;
|
||||
grp group_concat(c order by grp desc)
|
||||
1 a
|
||||
2 c b
|
||||
3 D d d D C E
|
||||
select grp, group_concat(a separator "")+0 from t1 group by grp;
|
||||
grp group_concat(a separator "")+0
|
||||
1 1
|
||||
2 23
|
||||
3 456789
|
||||
select grp, group_concat(a separator "")+0.0 from t1 group by grp;
|
||||
grp group_concat(a separator "")+0.0
|
||||
1 1.0
|
||||
2 23.0
|
||||
3 456789.0
|
||||
select grp, ROUND(group_concat(a separator "")) from t1 group by grp;
|
||||
grp ROUND(group_concat(a separator ""))
|
||||
1 1
|
||||
2 23
|
||||
3 456789
|
||||
drop table t1;
|
||||
create table t1 (grp int, c char(10));
|
||||
insert into t1 values (1,NULL);
|
||||
insert into t1 values (2,"b");
|
||||
insert into t1 values (2,NULL);
|
||||
insert into t1 values (3,"E");
|
||||
insert into t1 values (3,NULL);
|
||||
insert into t1 values (3,"D");
|
||||
insert into t1 values (3,NULL);
|
||||
insert into t1 values (3,NULL);
|
||||
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;
|
||||
grp group_concat(c order by c)
|
||||
1 NULL
|
||||
2 b
|
||||
3 D D E
|
||||
4
|
||||
5 NULL
|
||||
set group_concat_max_len = 5;
|
||||
select grp,group_concat(c) from t1 group by grp;
|
||||
grp group_concat(c)
|
||||
1 NULL
|
||||
2 b
|
||||
3 E D D
|
||||
4
|
||||
5 NULL
|
||||
Warnings:
|
||||
Warning 1250 1 line(s) was(were) cut by group_concat()
|
||||
show warnings;
|
||||
Level Code Message
|
||||
Warning 1250 1 line(s) was(were) cut by group_concat()
|
||||
select group_concat(sum(a)) from t1 group by grp;
|
||||
Invalid use of group function
|
||||
select grp,group_concat(c order by 2) from t1 group by grp;
|
||||
Unknown column '2' in 'group statement'
|
||||
drop table if exists t1;
|
79
mysql-test/t/func_gconcat.test
Normal file
79
mysql-test/t/func_gconcat.test
Normal file
|
@ -0,0 +1,79 @@
|
|||
#
|
||||
# simple test of group_concat function
|
||||
#
|
||||
|
||||
drop table if exists t1;
|
||||
create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null);
|
||||
insert into t1 values (1,1,"a","a");
|
||||
insert into t1 values (2,2,"b","a");
|
||||
insert into t1 values (2,3,"c","b");
|
||||
insert into t1 values (3,4,"E","a");
|
||||
insert into t1 values (3,5,"C","b");
|
||||
insert into t1 values (3,6,"D","b");
|
||||
insert into t1 values (3,7,"d","d");
|
||||
insert into t1 values (3,8,"d","d");
|
||||
insert into t1 values (3,9,"D","c");
|
||||
|
||||
# Test of MySQL simple request
|
||||
select grp,group_concat(c) from t1 group by grp;
|
||||
select grp,group_concat(a,c) from t1 group by grp;
|
||||
select grp,group_concat("(",a,":",c,")") from t1 group by grp;
|
||||
|
||||
# Test of MySQL with options
|
||||
select grp,group_concat(c separator ",") from t1 group by grp;
|
||||
select grp,group_concat(c separator "---->") from t1 group by grp;
|
||||
select grp,group_concat(c order by c) from t1 group by grp;
|
||||
select grp,group_concat(c order by c desc) from t1 group by grp;
|
||||
select grp,group_concat(d order by a) from t1 group by grp;
|
||||
select grp,group_concat(d order by a desc) from t1 group by grp;
|
||||
select grp,group_concat(a order by a,d+c) from t1 group by grp;
|
||||
select grp,group_concat(c order by 1) from t1 group by grp;
|
||||
select grp,group_concat(c order by "c") from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c) from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c desc) from t1 group by grp;
|
||||
select grp,group_concat(c order by c separator ",") from t1 group by grp;
|
||||
select grp,group_concat(c order by c desc separator ",") from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c separator ",") from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp;
|
||||
|
||||
# Test of SQL_LIST objects
|
||||
select grp,group_concat(c order by grp desc) from t1 group by grp order by grp;
|
||||
|
||||
|
||||
# Test transfer to real values
|
||||
|
||||
select grp, group_concat(a separator "")+0 from t1 group by grp;
|
||||
select grp, group_concat(a separator "")+0.0 from t1 group by grp;
|
||||
select grp, ROUND(group_concat(a separator "")) from t1 group by grp;
|
||||
|
||||
# Test NULL values
|
||||
|
||||
drop table t1;
|
||||
create table t1 (grp int, c char(10));
|
||||
insert into t1 values (1,NULL);
|
||||
insert into t1 values (2,"b");
|
||||
insert into t1 values (2,NULL);
|
||||
insert into t1 values (3,"E");
|
||||
insert into t1 values (3,NULL);
|
||||
insert into t1 values (3,"D");
|
||||
insert into t1 values (3,NULL);
|
||||
insert into t1 values (3,NULL);
|
||||
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;
|
||||
|
||||
# Test warnings
|
||||
|
||||
set group_concat_max_len = 5;
|
||||
select grp,group_concat(c) from t1 group by grp;
|
||||
show warnings;
|
||||
|
||||
# Test errors
|
||||
|
||||
--error 1111
|
||||
select group_concat(sum(a)) from t1 group by grp;
|
||||
--error 1054
|
||||
select grp,group_concat(c order by 2) from t1 group by grp;
|
||||
|
||||
drop table if exists t1;
|
|
@ -224,6 +224,7 @@ public:
|
|||
friend class Item_sum_std;
|
||||
friend class Item_sum_min;
|
||||
friend class Item_sum_max;
|
||||
friend class Item_func_group_concat;
|
||||
};
|
||||
|
||||
|
||||
|
|
456
sql/item_sum.cc
456
sql/item_sum.cc
|
@ -1329,3 +1329,459 @@ String *Item_sum_udf_str::val_str(String *str)
|
|||
}
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
GROUP_CONCAT function
|
||||
Syntax:
|
||||
GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
|
||||
[SEPARATOR str_const])
|
||||
concat of values from "group by" operation
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
function of sort for syntax:
|
||||
GROUP_CONCAT(DISTINCT expr,...)
|
||||
*/
|
||||
|
||||
static int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2)
|
||||
{
|
||||
Item_func_group_concat* item= (Item_func_group_concat*)arg;
|
||||
for (int i= 0; i<item->arg_count_field; i++)
|
||||
{
|
||||
Item *field_item= item->expr[i];
|
||||
Field *field= field_item->tmp_table_field();
|
||||
if (field)
|
||||
{
|
||||
uint offset= field->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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
function of sort for syntax:
|
||||
GROUP_CONCAT(expr,... ORDER BY col,... )
|
||||
*/
|
||||
|
||||
static int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
|
||||
{
|
||||
Item_func_group_concat* item= (Item_func_group_concat*)arg;
|
||||
for (int i=0; i<item->arg_count_order; i++)
|
||||
{
|
||||
ORDER *order_item= item->order[i];
|
||||
Item *item= *order_item->item;
|
||||
Field *field= item->tmp_table_field();
|
||||
if (field)
|
||||
{
|
||||
uint offset= field->offset();
|
||||
|
||||
bool dir= order_item->asc;
|
||||
int res= field->key_cmp(key1 + offset, key2 + offset);
|
||||
if (res)
|
||||
return dir ? res : -res;
|
||||
}
|
||||
}
|
||||
/*
|
||||
We can't return 0 becouse tree class remove this item as dubl value.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
function of sort for syntax:
|
||||
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;
|
||||
if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
|
||||
return 0;
|
||||
return(group_concat_key_cmp_with_order(arg,key1,key2));
|
||||
}
|
||||
|
||||
/*
|
||||
create result
|
||||
item is pointer to Item_func_group_concat
|
||||
*/
|
||||
|
||||
static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
|
||||
Item_func_group_concat *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);
|
||||
|
||||
tmp.length(0);
|
||||
|
||||
for (int i= 0; i < group_concat_item->arg_show_fields; i++)
|
||||
{
|
||||
Item *show_item= group_concat_item->expr[i];
|
||||
if (!show_item->const_item())
|
||||
{
|
||||
Field *f= show_item->tmp_table_field();
|
||||
uint offset= f->offset();
|
||||
char *sv= f->ptr;
|
||||
f->ptr= (char *)key + offset;
|
||||
String *res= f->val_str(&tmp,&tmp2);
|
||||
group_concat_item->result.append(*res);
|
||||
f->ptr= sv;
|
||||
}
|
||||
else
|
||||
{
|
||||
String *res= show_item->val_str(&tmp);
|
||||
if (res)
|
||||
group_concat_item->result.append(*res);
|
||||
}
|
||||
}
|
||||
if (group_concat_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);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Constructor of Item_func_group_concat
|
||||
is_distinct - distinct
|
||||
is_select - list of expression for show values
|
||||
is_order - list of sort columns
|
||||
is_separator - string value of separator
|
||||
*/
|
||||
|
||||
Item_func_group_concat::Item_func_group_concat(int is_distinct,List<Item> *is_select,
|
||||
SQL_LIST *is_order,String *is_separator):
|
||||
Item_sum(),
|
||||
tmp_table_param(0),
|
||||
warning_available(false),
|
||||
separator(is_separator),
|
||||
tree(&tree_base),
|
||||
table(0),
|
||||
distinct(is_distinct),
|
||||
tree_mode(0),
|
||||
count_cut_values(0)
|
||||
{
|
||||
original= 0;
|
||||
quick_group= 0;
|
||||
mark_as_sum_func();
|
||||
SELECT_LEX *select_lex= current_lex->current_select->select_lex();
|
||||
order= 0;
|
||||
|
||||
arg_show_fields= arg_count_field= is_select->elements;
|
||||
arg_count_order= is_order ? is_order->elements : 0;
|
||||
arg_count= arg_count_field;
|
||||
|
||||
/*
|
||||
We need to allocate:
|
||||
args - arg_count+arg_count_order (for possible order items in temporare
|
||||
tables)
|
||||
expr - arg_count_field
|
||||
order - arg_count_order
|
||||
*/
|
||||
args= (Item**)sql_alloc(sizeof(Item*)*(arg_count+arg_count_order+arg_count_field)+
|
||||
sizeof(ORDER*)*arg_count_order);
|
||||
if (!args)
|
||||
{
|
||||
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()
|
||||
{
|
||||
/*
|
||||
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 (warning_available)
|
||||
{
|
||||
char warn_buff[MYSQL_ERRMSG_SIZE];
|
||||
sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
|
||||
((MYSQL_ERROR *)warning)->set_msg((char *)&warn_buff);
|
||||
}
|
||||
if (table)
|
||||
free_tmp_table(current_thd, table);
|
||||
if (tmp_table_param)
|
||||
delete tmp_table_param;
|
||||
if (tree_mode)
|
||||
delete_tree(tree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Item_func_group_concat::reset()
|
||||
{
|
||||
result.length(0);
|
||||
result.copy();
|
||||
null_value= TRUE;
|
||||
warning_for_row= false;
|
||||
if (table)
|
||||
{
|
||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||
table->file->delete_all_rows();
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
}
|
||||
if (tree_mode)
|
||||
reset_tree(tree);
|
||||
add();
|
||||
}
|
||||
|
||||
|
||||
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 (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_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],1,
|
||||
(Item_func_group_concat*)this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Item_func_group_concat::reset_field()
|
||||
{
|
||||
if (tree_mode)
|
||||
reset_tree(tree);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
||||
{
|
||||
if (!thd->allow_sum_func)
|
||||
{
|
||||
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
thd->allow_sum_func= 0;
|
||||
maybe_null= 0;
|
||||
for (uint 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;
|
||||
}
|
||||
for (int i= 0 ; i < arg_count_field ; i++)
|
||||
{
|
||||
if (expr[i]->fix_fields(thd, tables, expr + i) || expr[i]->check_cols(1))
|
||||
return 1;
|
||||
maybe_null |= expr[i]->maybe_null;
|
||||
}
|
||||
/*
|
||||
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];
|
||||
Item *item=*order_item->item;
|
||||
if (item->fix_fields(thd, tables, &item) || item->check_cols(1))
|
||||
return 1;
|
||||
}
|
||||
result_field= 0;
|
||||
null_value= 1;
|
||||
fix_length_and_dec();
|
||||
thd->allow_sum_func= 1;
|
||||
if (!(tmp_table_param= new TMP_TABLE_PARAM))
|
||||
return 1;
|
||||
tables_list= tables;
|
||||
fixed= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_group_concat::setup(THD *thd)
|
||||
{
|
||||
List<Item> list;
|
||||
SELECT_LEX *select_lex= current_lex->current_select->select_lex();
|
||||
|
||||
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
|
||||
return 1;
|
||||
/*
|
||||
all not constant fields are push to list and create temp table
|
||||
*/
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
{
|
||||
Item *item= args[i];
|
||||
if (list.push_back(item))
|
||||
return 1;
|
||||
if (item->const_item())
|
||||
{
|
||||
(void) item->val_int();
|
||||
if (item->null_value)
|
||||
always_null= 1;
|
||||
}
|
||||
}
|
||||
|
||||
List<Item> all_fields(list);
|
||||
if (arg_count_order)
|
||||
{
|
||||
bool hidden_group_fields;
|
||||
setup_group(thd, args, tables_list, list, all_fields, *order,
|
||||
&hidden_group_fields);
|
||||
}
|
||||
|
||||
count_field_types(tmp_table_param,all_fields,0);
|
||||
/*
|
||||
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;
|
||||
table->file->extra(HA_EXTRA_NO_ROWS);
|
||||
table->no_rows= 1;
|
||||
qsort_cmp2 compare_key;
|
||||
|
||||
tree_mode= distinct || arg_count_order;
|
||||
/*
|
||||
choise function of sort
|
||||
*/
|
||||
if (tree_mode)
|
||||
{
|
||||
if (arg_count_order)
|
||||
{
|
||||
if (distinct)
|
||||
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
|
||||
else
|
||||
compare_key= (qsort_cmp2) group_concat_key_cmp_with_order;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
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,
|
||||
table->reclength, compare_key, 0, NULL, (void*) this);
|
||||
max_elements_in_tree= ((table->reclength) ?
|
||||
thd->variables.max_heap_table_size/table->reclength : 1);
|
||||
};
|
||||
item_thd= thd;
|
||||
|
||||
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)
|
||||
{
|
||||
original->table= table;
|
||||
original->tree_mode= tree_mode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String* Item_func_group_concat::val_str(String* str)
|
||||
{
|
||||
if (null_value)
|
||||
return 0;
|
||||
if (tree_mode)
|
||||
{
|
||||
show_elements= 0;
|
||||
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
|
||||
left_root_right);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!warning_for_row)
|
||||
result.length(result.length()-separator->length());
|
||||
}
|
||||
if (count_cut_values && !warning_available)
|
||||
{
|
||||
warning_available= TRUE;
|
||||
warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_CUT_VALUE_GROUP_CONCAT, NULL);
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class Item_sum :public Item_result_field
|
|||
public:
|
||||
enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
|
||||
MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
|
||||
UDF_SUM_FUNC };
|
||||
UDF_SUM_FUNC, GROUP_CONCAT_FUNC };
|
||||
|
||||
Item **args,*tmp_args[2];
|
||||
uint arg_count;
|
||||
|
@ -630,3 +630,87 @@ public:
|
|||
};
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
|
||||
class Item_func_group_concat : public Item_sum
|
||||
{
|
||||
THD *item_thd;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
uint max_elements_in_tree;
|
||||
void *warning;
|
||||
bool warning_available;
|
||||
public:
|
||||
String result;
|
||||
String *separator;
|
||||
uint show_elements;
|
||||
TREE tree_base;
|
||||
TREE *tree;
|
||||
TABLE *table;
|
||||
int arg_count_order;
|
||||
int arg_count_field;
|
||||
int arg_show_fields;
|
||||
int distinct;
|
||||
Item **expr;
|
||||
ORDER **order;
|
||||
bool tree_mode;
|
||||
int count_cut_values;
|
||||
ulong group_concat_max_len;
|
||||
bool warning_for_row;
|
||||
TABLE_LIST *tables_list;
|
||||
bool always_null;
|
||||
/*
|
||||
Following is 0 normal object and pointer to original one for copy
|
||||
(to correctly free resources)
|
||||
*/
|
||||
Item_func_group_concat *original;
|
||||
|
||||
Item_func_group_concat(int is_distinct,List<Item> *is_select,
|
||||
SQL_LIST *is_order,String *is_separator);
|
||||
|
||||
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),
|
||||
separator(item.separator),
|
||||
show_elements(item.show_elements),
|
||||
tree(item.tree),
|
||||
table(item.table),
|
||||
arg_count_order(item.arg_count_order),
|
||||
arg_count_field(item.arg_count_field),
|
||||
arg_show_fields(item.arg_show_fields),
|
||||
distinct(item.distinct),
|
||||
expr(item.expr),
|
||||
order(item.order),
|
||||
tree_mode(0),
|
||||
count_cut_values(item.count_cut_values),
|
||||
group_concat_max_len(item.group_concat_max_len),
|
||||
warning_for_row(item.warning_for_row),
|
||||
tables_list(item.tables_list),
|
||||
original(&item)
|
||||
{
|
||||
quick_group = 0;
|
||||
};
|
||||
~Item_func_group_concat();
|
||||
enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;}
|
||||
const char *func_name() const { return "group_concat"; }
|
||||
enum Type type() const { return SUM_FUNC_ITEM; }
|
||||
virtual Item_result result_type () const { return STRING_RESULT; }
|
||||
void reset();
|
||||
bool add();
|
||||
void reset_field();
|
||||
bool fix_fields(THD *, TABLE_LIST *, Item **);
|
||||
bool setup(THD *thd);
|
||||
virtual void update_field(int offset) {};
|
||||
double val()
|
||||
{
|
||||
String *res; res=val_str(&str_value);
|
||||
return res ? atof(res->c_ptr()) : 0.0;
|
||||
}
|
||||
longlong val_int()
|
||||
{
|
||||
String *res; res=val_str(&str_value);
|
||||
return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
|
||||
}
|
||||
String* val_str(String* str);
|
||||
};
|
||||
|
|
|
@ -335,6 +335,7 @@ static SYMBOL symbols[] = {
|
|||
{ "ROWS", SYM(ROWS_SYM),0,0},
|
||||
{ "RTREE", SYM(RTREE_SYM),0,0},
|
||||
{ "SECOND", SYM(SECOND_SYM),0,0},
|
||||
{ "SEPARATOR", SYM(SEPARATOR_SYM),0,0},
|
||||
{ "SELECT", SYM(SELECT_SYM),0,0},
|
||||
{ "SERIAL", SYM(SERIAL_SYM),0,0},
|
||||
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
|
||||
|
@ -503,6 +504,7 @@ static SYMBOL sql_functions[] = {
|
|||
{ "GEOMFROMWKB", SYM(GEOMFROMWKB),0,0},
|
||||
{ "GLENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_glength)},
|
||||
{ "GREATEST", SYM(GREATEST_SYM),0,0},
|
||||
{ "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM),0,0},
|
||||
{ "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
|
||||
{ "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
|
||||
{ "IFNULL", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_ifnull)},
|
||||
|
|
|
@ -547,8 +547,8 @@ int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
|||
List<Item> &values, ulong counter);
|
||||
|
||||
/* sql_error.cc */
|
||||
void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
|
||||
const char *msg);
|
||||
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
|
||||
const char *msg);
|
||||
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
||||
uint code, const char *format, ...);
|
||||
void mysql_reset_errors(THD *thd);
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
"Result string is longer than max_allowed_packet",
|
||||
"The used table type doesn't support BLOB/TEXT columns",
|
||||
"The used table type doesn't support AUTO_INCREMENT columns",
|
||||
"INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES",
|
||||
"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
|
||||
"Incorrect column name '%-.100s'",
|
||||
"The used table handler can't index column '%-.64s'",
|
||||
"All tables in the MERGE table are not identically defined",
|
||||
|
@ -198,7 +198,7 @@
|
|||
"Table '%-.64s' is marked as crashed and should be repaired",
|
||||
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
|
||||
"Some non-transactional changed tables couldn't be rolled back",
|
||||
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again",
|
||||
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
|
||||
"This operation cannot be performed with a running slave, run STOP SLAVE first",
|
||||
"This operation requires a running slave, configure slave and do START SLAVE",
|
||||
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
|
||||
|
@ -250,8 +250,5 @@
|
|||
"Every derived table must have it's own alias",
|
||||
"Select %u was reduced during optimisation",
|
||||
"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
|
||||
"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
|
||||
"All parts of a SPATIAL KEY must be NOT NULL"
|
||||
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
|
||||
"The slave was already running"
|
||||
"The slave was already stopped"
|
||||
"Client does not support authentication protocol requested by server. Consider upgrading MySQL client",
|
||||
"%d line(s) was(were) cut by group_concat()"
|
||||
|
|
|
@ -34,8 +34,6 @@ enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
|
|||
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
|
||||
DELAY_KEY_WRITE_ALL };
|
||||
|
||||
extern char internal_table_name[2];
|
||||
|
||||
// log info errors
|
||||
#define LOG_INFO_EOF -1
|
||||
#define LOG_INFO_IO -2
|
||||
|
@ -145,9 +143,7 @@ public:
|
|||
int generate_new_name(char *new_name,const char *old_name);
|
||||
void make_log_name(char* buf, const char* log_ident);
|
||||
bool is_active(const char* log_file_name);
|
||||
int update_log_index(LOG_INFO* linfo);
|
||||
int purge_logs(THD* thd, const char* to_log);
|
||||
int purge_logs_before_date(THD* thd, time_t purge_time);
|
||||
int purge_first_log(struct st_relay_log_info* rli);
|
||||
bool reset_logs(THD* thd);
|
||||
// if we are exiting, we also want to close the index file
|
||||
|
@ -174,6 +170,32 @@ public:
|
|||
|
||||
/* character conversion tables */
|
||||
|
||||
class CONVERT;
|
||||
CONVERT *get_convert_set(const char *name_ptr);
|
||||
|
||||
class CONVERT
|
||||
{
|
||||
const uchar *from_map,*to_map;
|
||||
void convert_array(const uchar *mapping,uchar *buff,uint length);
|
||||
public:
|
||||
const char *name;
|
||||
uint numb;
|
||||
CONVERT(const char *name_par,uchar *from_par,uchar *to_par, uint number)
|
||||
:from_map(from_par),to_map(to_par),name(name_par),numb(number) {}
|
||||
friend CONVERT *get_convert_set(const char *name_ptr);
|
||||
inline void convert(char *a,uint length)
|
||||
{
|
||||
convert_array(from_map, (uchar*) a,length);
|
||||
}
|
||||
char *store_dest(char *to, const char *from, uint length)
|
||||
{
|
||||
for (const char *end=from+length ; from != end ; from++)
|
||||
*to++= to_map[(uchar) *from];
|
||||
return to;
|
||||
}
|
||||
bool store(String *, const char *,uint);
|
||||
inline uint number() { return numb; }
|
||||
};
|
||||
|
||||
typedef struct st_copy_info {
|
||||
ha_rows records;
|
||||
|
@ -305,7 +327,12 @@ public:
|
|||
const char *msg_arg)
|
||||
:code(code_arg), level(level_arg)
|
||||
{
|
||||
msg=sql_strdup(msg_arg);
|
||||
if (msg_arg)
|
||||
msg=sql_strdup(msg_arg);
|
||||
}
|
||||
inline void set_msg(const char *msg_arg)
|
||||
{
|
||||
msg=sql_strdup(msg_arg);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -333,6 +360,10 @@ class select_result;
|
|||
#define THD_SENTRY_MAGIC 0xfeedd1ff
|
||||
#define THD_SENTRY_GONE 0xdeadbeef
|
||||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
typedef struct st_mysql;
|
||||
#endif
|
||||
|
||||
#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
|
||||
|
||||
struct system_variables
|
||||
|
@ -365,8 +396,7 @@ struct system_variables
|
|||
ulong tmp_table_size;
|
||||
ulong tx_isolation;
|
||||
ulong sql_mode;
|
||||
ulong default_week_format;
|
||||
|
||||
ulong group_concat_max_len;
|
||||
/*
|
||||
In slave thread we need to know in behalf of which
|
||||
thread the query is being run to replicate temp tables properly
|
||||
|
@ -374,10 +404,9 @@ struct system_variables
|
|||
ulong pseudo_thread_id;
|
||||
|
||||
my_bool log_warnings;
|
||||
my_bool low_priority_updates;
|
||||
my_bool new_mode;
|
||||
my_bool convert_result_charset;
|
||||
my_bool low_priority_updates;
|
||||
|
||||
CONVERT *convert_set;
|
||||
CHARSET_INFO *thd_charset;
|
||||
};
|
||||
|
||||
|
@ -424,9 +453,8 @@ public:
|
|||
db - currently selected database
|
||||
ip - client IP
|
||||
*/
|
||||
|
||||
char *host,*user,*priv_user,*db,*ip;
|
||||
/* remote (peer) port */
|
||||
uint16 peer_port;
|
||||
/* Points to info-string that will show in SHOW PROCESSLIST */
|
||||
const char *proc_info;
|
||||
/* points to host if host is available, otherwise points to ip */
|
||||
|
@ -549,7 +577,6 @@ public:
|
|||
|
||||
void init(void);
|
||||
void change_user(void);
|
||||
void init_for_queries();
|
||||
void cleanup(void);
|
||||
bool store_globals();
|
||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||
|
@ -657,9 +684,7 @@ public:
|
|||
{
|
||||
is_fatal_error= 1;
|
||||
net.report_error= 1;
|
||||
DBUG_PRINT("error",("Fatal error set"));
|
||||
}
|
||||
inline CHARSET_INFO *charset() { return variables.thd_charset; }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -885,11 +910,10 @@ class Table_ident :public Sql_alloc
|
|||
LEX_STRING db;
|
||||
LEX_STRING table;
|
||||
SELECT_LEX_UNIT *sel;
|
||||
inline Table_ident(THD *thd, LEX_STRING db_arg, LEX_STRING table_arg,
|
||||
bool force)
|
||||
inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force)
|
||||
:table(table_arg), sel((SELECT_LEX_UNIT *)0)
|
||||
{
|
||||
if (!force && (thd->client_capabilities & CLIENT_NO_SCHEMA))
|
||||
if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
|
||||
db.str=0;
|
||||
else
|
||||
db= db_arg;
|
||||
|
@ -901,8 +925,7 @@ class Table_ident :public Sql_alloc
|
|||
}
|
||||
inline Table_ident(SELECT_LEX_UNIT *s) : sel(s)
|
||||
{
|
||||
/* We must have a table name here as this is used with add_table_to_list */
|
||||
db.str=0; table.str= internal_table_name; table.length=1;
|
||||
db.str=0; table.str=(char *)""; table.length=0;
|
||||
}
|
||||
inline void change_db(char *db_name)
|
||||
{
|
||||
|
@ -919,7 +942,6 @@ class user_var_entry
|
|||
ulong length, update_query_id, used_query_id;
|
||||
Item_result type;
|
||||
CHARSET_INFO *var_charset;
|
||||
enum Item::coercion var_coercibility;
|
||||
};
|
||||
|
||||
/* Class for unique (removing of duplicates) */
|
||||
|
@ -978,7 +1000,7 @@ class multi_update : public select_result
|
|||
{
|
||||
TABLE_LIST *all_tables, *update_tables, *table_being_updated;
|
||||
THD *thd;
|
||||
TABLE **tmp_tables, *main_table, *table_to_update;
|
||||
TABLE **tmp_tables, *main_table;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
ha_rows updated, found;
|
||||
List <Item> *fields, *values;
|
||||
|
|
|
@ -80,14 +80,19 @@ void mysql_reset_errors(THD *thd)
|
|||
level Severity of warning (note, warning, error ...)
|
||||
code Error number
|
||||
msg Clear error message
|
||||
|
||||
RETURN
|
||||
pointer on MYSQL_ERROR object
|
||||
*/
|
||||
|
||||
void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
|
||||
const char *msg)
|
||||
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
||||
uint code, const char *msg)
|
||||
{
|
||||
if (thd->query_id != thd->warn_id)
|
||||
mysql_reset_errors(thd);
|
||||
|
||||
MYSQL_ERROR *err = NULL;
|
||||
|
||||
if (thd->warn_list.elements < thd->variables.max_error_count)
|
||||
{
|
||||
/*
|
||||
|
@ -96,13 +101,14 @@ void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
|
|||
*/
|
||||
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
||||
my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
|
||||
MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg);
|
||||
err = new MYSQL_ERROR(code, level, msg);
|
||||
if (err)
|
||||
thd->warn_list.push_back(err);
|
||||
my_pthread_setspecific_ptr(THR_MALLOC, old_root);
|
||||
}
|
||||
thd->warn_count[(uint) level]++;
|
||||
thd->total_warn_count++;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -478,6 +478,7 @@ typedef struct st_lex
|
|||
uint slave_thd_opt;
|
||||
CHARSET_INFO *charset;
|
||||
char *help_arg;
|
||||
SQL_LIST *gorder_list;
|
||||
|
||||
inline void uncacheable()
|
||||
{
|
||||
|
|
|
@ -336,6 +336,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token ROW_SYM
|
||||
%token RTREE_SYM
|
||||
%token SET
|
||||
%token SEPARATOR_SYM
|
||||
%token SERIAL_SYM
|
||||
%token SERIALIZABLE_SYM
|
||||
%token SESSION_SYM
|
||||
|
@ -462,6 +463,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token GEOMFROMTEXT
|
||||
%token GEOMFROMWKB
|
||||
%token GEOMETRYCOLLECTION
|
||||
%token GROUP_CONCAT_SYM
|
||||
%token GROUP_UNIQUE_USERS
|
||||
%token HOUR_MINUTE_SYM
|
||||
%token HOUR_SECOND_SYM
|
||||
|
@ -575,13 +577,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
opt_escape
|
||||
|
||||
%type <string>
|
||||
text_string
|
||||
text_string opt_gconcat_separator
|
||||
|
||||
%type <num>
|
||||
type int_type real_type order_dir opt_field_spec lock_option
|
||||
udf_type if_exists opt_local opt_table_options table_options
|
||||
table_option opt_if_not_exists opt_var_type opt_var_ident_type
|
||||
delete_option opt_temporary all_or_any
|
||||
delete_option opt_temporary all_or_any opt_distinct
|
||||
|
||||
%type <ulong_num>
|
||||
ULONG_NUM raid_types merge_insert_types
|
||||
|
@ -2554,7 +2556,35 @@ sum_expr:
|
|||
| VARIANCE_SYM '(' in_sum_expr ')'
|
||||
{ $$=new Item_sum_variance($3); }
|
||||
| SUM_SYM '(' in_sum_expr ')'
|
||||
{ $$=new Item_sum_sum($3); };
|
||||
{ $$=new Item_sum_sum($3); }
|
||||
| GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause opt_gconcat_separator ')'
|
||||
{
|
||||
$$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6);
|
||||
$4->empty();
|
||||
};
|
||||
|
||||
opt_distinct:
|
||||
/* empty */ { $$ = 0; }
|
||||
|DISTINCT { $$ = 1; };
|
||||
|
||||
opt_gconcat_separator:
|
||||
/* empty */ { $$ = new String(" ",1,default_charset_info); }
|
||||
|SEPARATOR_SYM text_string { $$ = $2; };
|
||||
|
||||
|
||||
opt_gorder_clause:
|
||||
/* empty */
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->gorder_list = NULL;
|
||||
}
|
||||
| order_clause
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list));
|
||||
lex->current_select->order_list.empty();
|
||||
};
|
||||
|
||||
|
||||
in_sum_expr:
|
||||
opt_all
|
||||
|
|
Loading…
Reference in a new issue