Commit 12f1cb55 authored by wax@kishkin.ru's avatar wax@kishkin.ru

This is full commit of group_concat with support subselects

parent 0e22b88a
......@@ -104,6 +104,7 @@ vva@eagle.mysql.r18.ru
vva@genie.(none)
walrus@kishkin.ru
walrus@mysql.com
wax@kishkin.ru
wax@mysql.com
worm@altair.is.lan
zak@balfor.local
......
......@@ -266,4 +266,5 @@
#define ER_SELECT_REDUCED 1247
#define ER_TABLENAME_NOT_ALLOWED_HERE 1248
#define ER_NOT_SUPPORTED_AUTH_MODE 1249
#define ER_ERROR_MESSAGES 250
#define ER_CUT_VALUE_GROUP_CONCAT 1250
#define ER_ERROR_MESSAGES 251
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 if exists 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");
select grp,group_concat(c order by c) from t1 group by grp;
grp group_concat(c order by c)
1
2 b
3 D D E
set group_concat_max_len = 5;
select grp,group_concat(c) from t1 group by grp;
grp group_concat(c)
1
2 b
3 E D
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;
#
# 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 if exists 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");
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;
......@@ -221,6 +221,7 @@ public:
friend class Item_sum_std;
friend class Item_sum_min;
friend class Item_sum_max;
friend class Item_func_group_concat;
};
......
This diff is collapsed.
......@@ -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;
......@@ -628,3 +628,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);
};
......@@ -330,6 +330,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},
......@@ -490,6 +491,7 @@ static SYMBOL sql_functions[] = {
{ "GEOMFROMTEXT", SYM(GEOMFROMTEXT),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)},
......
......@@ -544,8 +544,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);
......
......@@ -3465,7 +3465,8 @@ enum options
OPT_ERROR_LOG_FILE,
OPT_ENABLE_SHARED_MEMORY,
OPT_SHARED_MEMORY_BASE_NAME,
OPT_OLD_PASSWORDS
OPT_OLD_PASSWORDS,
OPT_GROUP_CONCAT_MAX_LEN
};
......@@ -3581,6 +3582,11 @@ struct my_option my_long_options[] =
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"flush", OPT_FLUSH, "Flush tables to disk between SQL commands", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ "group_concat_max_len", OPT_GROUP_CONCAT_MAX_LEN,
"The maximum length of the result of function group_concat.",
(gptr*) &global_system_variables.group_concat_max_len,
(gptr*) &max_system_variables.group_concat_max_len, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0},
/* We must always support the next option to make scripts like mysqltest
easier to do */
{"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role", 0, 0, 0,
......
......@@ -311,6 +311,8 @@ static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter
static sys_var_rand_seed1 sys_rand_seed1("rand_seed1");
static sys_var_rand_seed2 sys_rand_seed2("rand_seed2");
sys_var_thd_ulong sys_group_concat_max_len("group_concat_max_len",
&SV::group_concat_max_len);
/*
List of all variables for initialisation and storage in hash
......@@ -340,6 +342,7 @@ sys_var *sys_variables[]=
&sys_flush,
&sys_flush_time,
&sys_foreign_key_checks,
&sys_group_concat_max_len,
&sys_identity,
&sys_insert_id,
&sys_interactive_timeout,
......
......@@ -250,4 +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"
\ No newline at end of file
"Client does not support authentication protocol requested by server. Consider upgrading MySQL client",
"%d line(s) was(were) cut by group_concat()"
......@@ -327,7 +327,12 @@ public:
const char *msg_arg)
:code(code_arg), level(level_arg)
{
msg=sql_strdup(msg_arg);
set_msg(msg_arg);
}
inline void set_msg(const char *msg_arg)
{
if (msg_arg)
msg=sql_strdup(msg_arg);
}
};
......@@ -391,7 +396,7 @@ struct system_variables
ulong tmp_table_size;
ulong tx_isolation;
ulong sql_mode;
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
......
......@@ -79,14 +79,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)
{
/*
......@@ -95,13 +100,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;
}
/*
......
......@@ -477,6 +477,7 @@ typedef struct st_lex
uint slave_thd_opt;
CHARSET_INFO *charset;
char *help_arg;
SQL_LIST *gorder_list;
inline void uncacheable()
{
......
......@@ -332,6 +332,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
......@@ -457,6 +458,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token GEOMCOLLFROMTEXT
%token GEOMFROMTEXT
%token GEOMETRYCOLLECTION
%token GROUP_CONCAT_SYM
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
......@@ -567,13 +569,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
......@@ -2466,7 +2468,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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment