Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
74e32241
Commit
74e32241
authored
Apr 02, 2003
by
wax@kishkin.ru
Browse files
Options
Browse Files
Download
Plain Diff
Auto merged
parents
87ee144f
77eb790e
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
879 additions
and
43 deletions
+879
-43
include/mysqld_error.h
include/mysqld_error.h
+2
-5
mysql-test/r/func_gconcat.result
mysql-test/r/func_gconcat.result
+161
-0
mysql-test/t/func_gconcat.test
mysql-test/t/func_gconcat.test
+79
-0
sql/field.h
sql/field.h
+1
-0
sql/item_sum.cc
sql/item_sum.cc
+456
-0
sql/item_sum.h
sql/item_sum.h
+85
-1
sql/lex.h
sql/lex.h
+2
-0
sql/mysql_priv.h
sql/mysql_priv.h
+2
-2
sql/share/english/errmsg.txt
sql/share/english/errmsg.txt
+4
-7
sql/sql_class.h
sql/sql_class.h
+44
-22
sql/sql_error.cc
sql/sql_error.cc
+9
-3
sql/sql_lex.h
sql/sql_lex.h
+1
-0
sql/sql_yacc.yy
sql/sql_yacc.yy
+33
-3
No files found.
include/mysqld_error.h
View file @
74e32241
...
...
@@ -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
mysql-test/r/func_gconcat.result
0 → 100644
View file @
74e32241
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;
mysql-test/t/func_gconcat.test
0 → 100644
View file @
74e32241
#
# 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
;
sql/field.h
View file @
74e32241
...
...
@@ -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
;
};
...
...
sql/item_sum.cc
View file @
74e32241
...
...
@@ -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
;
}
sql/item_sum.h
View file @
74e32241
...
...
@@ -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
);
};
sql/lex.h
View file @
74e32241
...
...
@@ -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
)},
...
...
sql/mysql_priv.h
View file @
74e32241
...
...
@@ -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
);
...
...
sql/share/english/errmsg.txt
View file @
74e32241
...
...
@@ -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()"
sql/sql_class.h
View file @
74e32241
...
...
@@ -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
;
...
...
sql/sql_error.cc
View file @
74e32241
...
...
@@ -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
;
}
/*
...
...
sql/sql_lex.h
View file @
74e32241
...
...
@@ -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
()
{
...
...
sql/sql_yacc.yy
View file @
74e32241
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment