Commit 9684140f authored by Michael Widenius's avatar Michael Widenius

Fixed crashing bug in GROUP_CONCAT with ROLLUP

Fixed MDEV-4002: Server crash or valgrind errors in Item_func_group_concat::setup and Item_func_group_concat::add

mysql-test/r/group_by.result:
  Added test case for failing GROUP_CONCAT ... ROLLUP queries
mysql-test/t/group_by.test:
  Added test case for failing GROUP_CONCAT ... ROLLUP queries
sql/item_sum.cc:
  Fixed issue where field->table pointed to different temporary table than expected.
  Ensure that order->next points to the right object (could cause problems with setup_order())
parent 5f68820c
...@@ -2160,3 +2160,48 @@ f1 MIN(f2) MAX(f2) ...@@ -2160,3 +2160,48 @@ f1 MIN(f2) MAX(f2)
4 00:25:00 00:25:00 4 00:25:00 00:25:00
DROP TABLE t1; DROP TABLE t1;
#End of test#49771 #End of test#49771
#
# Test of bug in GROUP_CONCAT with ROLLUP
#
CREATE TABLE t1 ( b VARCHAR(8) NOT NULL, a INT NOT NULL ) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES (1,'c'),(2,'v');
CREATE TABLE t2 ( c VARCHAR(8), d INT, KEY (c, d) ) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('v',6),('c',4),('v',3);
SELECT b, GROUP_CONCAT( a, b ORDER BY a, b )
FROM t1 JOIN t2 ON c = b GROUP BY b;
b GROUP_CONCAT( a, b ORDER BY a, b )
c 1c
v 2v,2v
SELECT b, GROUP_CONCAT( a, b ORDER BY a, b )
FROM t1 JOIN t2 ON c = b GROUP BY b WITH ROLLUP;
b GROUP_CONCAT( a, b ORDER BY a, b )
c 1c
v 2v,2v
NULL 1c,2v,2v
DROP TABLE t1,t2;
#
# Test of MDEV-4002
#
CREATE TABLE t1 (
pk INT NOT NULL PRIMARY KEY,
d1 DOUBLE,
d2 DOUBLE,
i INT NOT NULL DEFAULT '0',
KEY (i)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,1.0,1.1,1),(2,2.0,2.2,2);
PREPARE stmt FROM "
SELECT DISTINCT i, GROUP_CONCAT( d1, d2 ORDER BY d1, d2 )
FROM t1 a1 NATURAL JOIN t1 a2 GROUP BY i WITH ROLLUP
";
EXECUTE stmt;
i GROUP_CONCAT( d1, d2 ORDER BY d1, d2 )
1 11.1
2 22.2
NULL 11.1,22.2
EXECUTE stmt;
i GROUP_CONCAT( d1, d2 ORDER BY d1, d2 )
1 11.1
2 22.2
NULL 11.1,22.2
DROP TABLE t1;
--source include/have_innodb.inc
# Initialise # Initialise
--disable_warnings --disable_warnings
...@@ -1507,3 +1508,45 @@ SELECT f1,MIN(f2),MAX(f2) FROM t1 GROUP BY 1; ...@@ -1507,3 +1508,45 @@ SELECT f1,MIN(f2),MAX(f2) FROM t1 GROUP BY 1;
DROP TABLE t1; DROP TABLE t1;
--echo #End of test#49771 --echo #End of test#49771
--echo #
--echo # Test of bug in GROUP_CONCAT with ROLLUP
--echo #
CREATE TABLE t1 ( b VARCHAR(8) NOT NULL, a INT NOT NULL ) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES (1,'c'),(2,'v');
CREATE TABLE t2 ( c VARCHAR(8), d INT, KEY (c, d) ) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('v',6),('c',4),('v',3);
SELECT b, GROUP_CONCAT( a, b ORDER BY a, b )
FROM t1 JOIN t2 ON c = b GROUP BY b;
SELECT b, GROUP_CONCAT( a, b ORDER BY a, b )
FROM t1 JOIN t2 ON c = b GROUP BY b WITH ROLLUP;
DROP TABLE t1,t2;
--echo #
--echo # Test of MDEV-4002
--echo #
CREATE TABLE t1 (
pk INT NOT NULL PRIMARY KEY,
d1 DOUBLE,
d2 DOUBLE,
i INT NOT NULL DEFAULT '0',
KEY (i)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,1.0,1.1,1),(2,2.0,2.2,2);
PREPARE stmt FROM "
SELECT DISTINCT i, GROUP_CONCAT( d1, d2 ORDER BY d1, d2 )
FROM t1 a1 NATURAL JOIN t1 a2 GROUP BY i WITH ROLLUP
";
EXECUTE stmt;
EXECUTE stmt;
DROP TABLE t1;
...@@ -2905,13 +2905,12 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1, ...@@ -2905,13 +2905,12 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
const void* key2) const void* key2)
{ {
Item_func_group_concat *item_func= (Item_func_group_concat*)arg; Item_func_group_concat *item_func= (Item_func_group_concat*)arg;
TABLE *table= item_func->table;
for (uint i= 0; i < item_func->arg_count_field; i++) for (uint i= 0; i < item_func->arg_count_field; i++)
{ {
Item *item= item_func->args[i]; Item *item= item_func->args[i];
/* /*
If field_item is a const item then either get_tp_table_field returns 0 If field_item is a const item then either get_tmp_table_field returns 0
or it is an item over a const table. or it is an item over a const table.
*/ */
if (item->const_item()) if (item->const_item())
...@@ -2923,7 +2922,8 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1, ...@@ -2923,7 +2922,8 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
*/ */
Field *field= item->get_tmp_table_field(); Field *field= item->get_tmp_table_field();
int res; int res;
uint offset= field->offset(field->table->record[0])-table->s->null_bytes; uint offset= (field->offset(field->table->record[0]) -
field->table->s->null_bytes);
if((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset))) if((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset)))
return res; return res;
} }
...@@ -2941,28 +2941,37 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1, ...@@ -2941,28 +2941,37 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1,
{ {
Item_func_group_concat* grp_item= (Item_func_group_concat*) arg; Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
ORDER **order_item, **end; ORDER **order_item, **end;
TABLE *table= grp_item->table;
for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order; for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order;
order_item < end; order_item < end;
order_item++) order_item++)
{ {
Item *item= *(*order_item)->item; Item *item= *(*order_item)->item;
/*
If field_item is a const item then either get_tmp_table_field returns 0
or it is an item over a const table.
*/
if (item->const_item())
continue;
/* /*
We have to use get_tmp_table_field() instead of We have to use get_tmp_table_field() instead of
real_item()->get_tmp_table_field() because we want the field in real_item()->get_tmp_table_field() because we want the field in
the temporary table, not the original field the temporary table, not the original field
Note that for the case of ROLLUP, field may point to another table
tham grp_item->table. This is howver ok as the table definitions are
the same.
*/ */
Field *field= item->get_tmp_table_field(); Field *field= item->get_tmp_table_field();
/* /*
If item is a const item then either get_tp_table_field returns 0 If item is a const item then either get_tmp_table_field returns 0
or it is an item over a const table. or it is an item over a const table.
*/ */
if (field && !item->const_item()) if (field)
{ {
int res; int res;
uint offset= (field->offset(field->table->record[0]) - uint offset= (field->offset(field->table->record[0]) -
table->s->null_bytes); field->table->s->null_bytes);
if ((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset))) if ((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset)))
return (*order_item)->asc ? res : -res; return (*order_item)->asc ? res : -res;
} }
...@@ -3162,6 +3171,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, ...@@ -3162,6 +3171,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
for (uint i= 0; i < arg_count_order; i++, tmp++) for (uint i= 0; i < arg_count_order; i++, tmp++)
{ {
memcpy(tmp, item->order[i], sizeof(ORDER)); memcpy(tmp, item->order[i], sizeof(ORDER));
tmp->next= i == arg_count_order-1 ? 0 : tmp+1;
order[i]= tmp; order[i]= tmp;
} }
} }
...@@ -3445,7 +3455,8 @@ bool Item_func_group_concat::setup(THD *thd) ...@@ -3445,7 +3455,8 @@ bool Item_func_group_concat::setup(THD *thd)
*/ */
if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
(ORDER*) 0, 0, TRUE, (ORDER*) 0, 0, TRUE,
(select_lex->options | thd->variables.option_bits), (select_lex->options |
thd->variables.option_bits),
HA_POS_ERROR, (char*) ""))) HA_POS_ERROR, (char*) "")))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
table->file->extra(HA_EXTRA_NO_ROWS); table->file->extra(HA_EXTRA_NO_ROWS);
......
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