Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions mysql-test/main/mdev_40698.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# MDEV-40698: ROLLUP query returns incorrect result with empty result set
#
CREATE TABLE t0(a INT, b INT, c INT);
SELECT *, COUNT(0) FROM t0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT *, COUNT(0) FROM t0 WHERE 1=0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT *, COUNT(0), ROW_NUMBER() OVER () FROM t0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0) ROW_NUMBER() OVER ()
NULL NULL NULL 0 1
SELECT 1 IN (SELECT a FROM t0 WHERE a>0 GROUP BY a WITH ROLLUP);
1 IN (SELECT a FROM t0 WHERE a>0 GROUP BY a WITH ROLLUP)
NULL
INSERT INTO t0 VALUES (0, 0, 0),(0, 0, 0);
SELECT *, COUNT(0) FROM t0 WHERE a > 0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT EXISTS (SELECT t0.a FROM t0 x WHERE 1=0 GROUP BY x.a WITH ROLLUP) AS e
FROM t0;
e
1
1
SELECT DISTINCT a FROM t0 GROUP BY a, b WITH ROLLUP;
a
0
NULL
CREATE TABLE t1 (a INT, b INT, c INT) ENGINE=InnoDB;
SELECT *, COUNT(0) FROM t1 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT *, COUNT(0) FROM t1 WHERE 1=0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT *, COUNT(0), ROW_NUMBER() OVER () FROM t1 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0) ROW_NUMBER() OVER ()
NULL NULL NULL 0 1
INSERT INTO t1 VALUES (0, 0, 0),(0, 0, 0);
SELECT *, COUNT(0) FROM t1 WHERE a > 0 GROUP BY a, b, c WITH ROLLUP;
a b c COUNT(0)
NULL NULL NULL 0
SELECT EXISTS (SELECT t1.a FROM t1 x WHERE 1=0 GROUP BY x.a WITH ROLLUP) AS e
FROM t1;
e
1
1
SELECT DISTINCT a FROM t1 GROUP BY a, b WITH ROLLUP;
a
0
NULL
DROP TABLE t0, t1;
# End of 10.11 tests
30 changes: 30 additions & 0 deletions mysql-test/main/mdev_40698.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--source include/have_innodb.inc

Comment thread
jaeheonshim marked this conversation as resolved.
--echo #
--echo # MDEV-40698: ROLLUP query returns incorrect result with empty result set
--echo #

CREATE TABLE t0(a INT, b INT, c INT);
SELECT *, COUNT(0) FROM t0 GROUP BY a, b, c WITH ROLLUP;
SELECT *, COUNT(0) FROM t0 WHERE 1=0 GROUP BY a, b, c WITH ROLLUP;
SELECT *, COUNT(0), ROW_NUMBER() OVER () FROM t0 GROUP BY a, b, c WITH ROLLUP;
SELECT 1 IN (SELECT a FROM t0 WHERE a>0 GROUP BY a WITH ROLLUP);
INSERT INTO t0 VALUES (0, 0, 0),(0, 0, 0);
SELECT *, COUNT(0) FROM t0 WHERE a > 0 GROUP BY a, b, c WITH ROLLUP;
SELECT EXISTS (SELECT t0.a FROM t0 x WHERE 1=0 GROUP BY x.a WITH ROLLUP) AS e
FROM t0;
SELECT DISTINCT a FROM t0 GROUP BY a, b WITH ROLLUP;

CREATE TABLE t1 (a INT, b INT, c INT) ENGINE=InnoDB;
SELECT *, COUNT(0) FROM t1 GROUP BY a, b, c WITH ROLLUP;
SELECT *, COUNT(0) FROM t1 WHERE 1=0 GROUP BY a, b, c WITH ROLLUP;
SELECT *, COUNT(0), ROW_NUMBER() OVER () FROM t1 GROUP BY a, b, c WITH ROLLUP;
INSERT INTO t1 VALUES (0, 0, 0),(0, 0, 0);
SELECT *, COUNT(0) FROM t1 WHERE a > 0 GROUP BY a, b, c WITH ROLLUP;
SELECT EXISTS (SELECT t1.a FROM t1 x WHERE 1=0 GROUP BY x.a WITH ROLLUP) AS e
FROM t1;
SELECT DISTINCT a FROM t1 GROUP BY a, b WITH ROLLUP;

DROP TABLE t0, t1;

--echo # End of 10.11 tests

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just single line on End of x tests.

Can the tests be appended to mysql-test/main/olap.test instead of a new file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially had it that way, but the olap tests don't include innodb and I wasn't sure about including it for the whole file just for these tests

1 change: 1 addition & 0 deletions mysql-test/main/ps_error.result
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ EXECUTE stmt;
ERROR 22007: Truncated incorrect DOUBLE value: 'foo'
SELECT a FROM t1 GROUP BY NULL WITH ROLLUP;
a
NULL
DROP TABLE t1;
SET sql_mode=DEFAULT;
SET SQL_MODE= 'STRICT_ALL_TABLES';
Expand Down
1 change: 1 addition & 0 deletions mysql-test/main/win.result
Original file line number Diff line number Diff line change
Expand Up @@ -3503,6 +3503,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
select distinct 1, row_number() over (order by 1) from t1 where a=0 group by a with rollup;
1 row_number() over (order by 1)
1 1
drop table t1;
explain
SELECT DISTINCT BIT_OR(100) OVER () FROM dual
Expand Down
1 change: 1 addition & 0 deletions mysql-test/suite/encryption/r/tempfiles_encrypted.result
Original file line number Diff line number Diff line change
Expand Up @@ -3509,6 +3509,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
select distinct 1, row_number() over (order by 1) from t1 where a=0 group by a with rollup;
1 row_number() over (order by 1)
1 1
drop table t1;
explain
SELECT DISTINCT BIT_OR(100) OVER () FROM dual
Expand Down
2 changes: 1 addition & 1 deletion sql/opt_subselect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6805,7 +6805,7 @@ bool JOIN::choose_tableless_subquery_plan()
*/
if (zero_result_cause)
{
if (!implicit_grouping)
if (!implicit_grouping && select_lex->olap != ROLLUP_TYPE)
{
/*
Both group by queries and non-group by queries without aggregate
Expand Down
18 changes: 14 additions & 4 deletions sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16610,6 +16610,10 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
join->thd->set_examined_row_count(0);
join->thd->limit_found_rows= 0;
}
else
{
join->thd->limit_found_rows= send_row ? 1 : 0;
}

if (!(result->send_result_set_metadata(*fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
Expand Down Expand Up @@ -24496,6 +24500,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
join->fields.
*/
List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
bool empty_set_send_rollup_total= false;
DBUG_ENTER("end_send_group");

if (!join->items3.is_null() && !join->set_group_rpa)
Expand All @@ -24511,7 +24516,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)

if (!join->group_sent &&
(join->first_record ||
(end_of_records && !join->group && !join->group_optimized_away)))
join->need_empty_set_row(end_of_records,
&empty_set_send_rollup_total)))
{
table_map cleared_tables= (table_map) 0;
if (join->procedure)
Expand Down Expand Up @@ -24567,7 +24573,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
join->send_records++;
join->group_sent= true;
}
if (unlikely(join->rollup.state != ROLLUP::STATE_NONE && error <= 0))
if (unlikely(join->rollup.state != ROLLUP::STATE_NONE &&
!empty_set_send_rollup_total && error <= 0))
{
if (join->rollup_send_data((uint) (idx+1)))
error= 1;
Expand Down Expand Up @@ -24888,13 +24895,15 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
TABLE *table= join_tab->table;
int idx= -1;
bool empty_set_send_rollup_total= false;
DBUG_ENTER("end_write_group");

join->accepted_rows++;
if (!join->first_record || end_of_records ||
(idx=test_if_group_changed(join->group_fields)) >= 0)
{
if (join->first_record || (end_of_records && !join->group))
if (join->first_record ||
join->need_empty_set_row(end_of_records, &empty_set_send_rollup_total))
{
table_map cleared_tables= (table_map) 0;
if (join->procedure)
Expand All @@ -24919,7 +24928,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
error, 0, NULL))
DBUG_RETURN(NESTED_LOOP_ERROR);
}
if (unlikely(join->rollup.state != ROLLUP::STATE_NONE))
if (unlikely(join->rollup.state != ROLLUP::STATE_NONE &&
!empty_set_send_rollup_total))
{
if (unlikely(join->rollup_write_data((uint) (idx+1),
join_tab->tmp_table_param,
Expand Down
19 changes: 17 additions & 2 deletions sql/sql_select.h
Original file line number Diff line number Diff line change
Expand Up @@ -1746,12 +1746,27 @@ class JOIN :public Sql_alloc
void cleanup(bool full);
void clear(table_map *cleared_tables);
void inline clear_sum_funcs();
bool need_empty_set_row(bool end_of_records,
bool *empty_set_send_rollup_total) const
{
*empty_set_send_rollup_total=
end_of_records && !first_record && rollup.state != ROLLUP::STATE_NONE;
return (end_of_records && !first_record && !group &&
!group_optimized_away) ||

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a new condition. Do we need this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mainly for code cleanliness. Previously the need_empty_set_row condition was present directly in the if statement in end_send_group/end_write_group. But I figured with the extra condition for empty_set_rollup_total, which needs to be referenced again later, the code would start having many duplicated expressions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, i meant group_optimized_away. It's likely not an issue, i was curious.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh i see. actually I am curious too because group_optimized_away was included in the conditional in end_send_group but not end_write_group. But I believe it should be included in both to be consistent with send_row_on_empty_set

*empty_set_send_rollup_total;
}
bool send_row_on_empty_set()
{
return (do_send_rows && implicit_grouping && !group_optimized_away &&
return (do_send_rows &&
(select_lex->olap == ROLLUP_TYPE ||
(implicit_grouping && !group_optimized_away)) &&
having_value != Item::COND_FALSE);
}
bool empty_result() { return (zero_result_cause && !implicit_grouping); }
bool empty_result()
{
return (zero_result_cause && !implicit_grouping &&
select_lex->olap != ROLLUP_TYPE);
}
bool change_result(select_result *new_result, select_result *old_result);
bool is_top_level_join() const
{
Expand Down