Skip to content

MDEV-40698 ROLLUP query returns incorrect result with empty result set - #5542

Open
jaeheonshim wants to merge 1 commit into
MariaDB:10.11from
jaeheonshim:MDEV-40698
Open

MDEV-40698 ROLLUP query returns incorrect result with empty result set#5542
jaeheonshim wants to merge 1 commit into
MariaDB:10.11from
jaeheonshim:MDEV-40698

Conversation

@jaeheonshim

Copy link
Copy Markdown
Contributor

Fixes MDEV-40698

Comment thread mysql-test/main/mdev_40698.test
Comment thread sql/sql_select.cc Outdated
@grooverdan

Copy link
Copy Markdown
Member

There's a few other MTR test cases WITH ROLLUP to record too
https://buildbot.mariadb.org/#/grid?branch=refs%2Fpull%2F5542%2Fhead

@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Aug 13, 2026
@jaeheonshim
jaeheonshim force-pushed the MDEV-40698 branch 2 times, most recently from 6ad12b2 to f83223d Compare August 14, 2026 22:31
@jaeheonshim
jaeheonshim marked this pull request as ready for review August 14, 2026 23:49
@jaeheonshim
jaeheonshim requested a review from grooverdan August 16, 2026 21:40

@grooverdan grooverdan left a comment

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.

Thanks @jaeheonshim.

Can you rollup, pun intended, these commits into a single final version of a commit message with MDEV header and problem/solution explaination. Include the explain as to why InnoDB is different.

Comment thread mysql-test/main/mdev_40698.test Outdated
Comment thread mysql-test/main/mdev_40698.test Outdated
DROP TABLE t0, t1;

--echo #
--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

@gkodinov gkodinov self-assigned this Aug 17, 2026

@gkodinov gkodinov left a comment

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.

Thank you for your contribution. This is a preliminary review.

Daniel already marked the relevant points that I'd otherwise cover during the preliminary review. Please work with him to address these.

Since I have nothing more to add I'm marking it as LGTM.

@mariadb-RexJohnston mariadb-RexJohnston left a comment

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.

the patch conflicts with current IN to EXISTS mechanisms. Here is an example

CREATE TABLE t (a INT);
SELECT 1 IN (SELECT a FROM t WHERE 1=0 GROUP BY a WITH ROLLUP);

1 in NULL should be a NULL, but after the patch, we get 1.
and before the patch, we get an also incorrect 0

thd::limit_found_rows needs to be reset when sending out one of these new empty result sets.

Comment thread sql/sql_select.cc Outdated
Comment thread sql/sql_select.cc Outdated
Comment thread sql/sql_select.h
*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

ROLLUP is defined as the UNION of grouping by every prefix of fields in
the original GROUP BY list. A ROLLUP query with an empty result set
returned zero rows when it should return a summary NULL, since grouping
by the empty prefix returns a single summary row.

The empty row case is handled in two separate locations. First, if the
optimizer is able to determine that no rows will be produced, e.g. due
to the table being empty or the WHERE condition resolving to false,
JOIN::send_row_on_empty_set is used to determine whether or not to send
an empty result row. Therefore, send_row_on_empty_set is modified to
include select_lex->olap == ROLLUP_TYPE.

Second, it may be the case that the absence of rows is not confirmed
until the execution phase. For instance when the WHERE condition is not
constant, or in the case of InnoDB where an empty table is not detected
during optimization. This is handled in both end_send_group and
end_write_group by this expression

    join->first_record ||
        (end_of_records && !join->group && !join->group_optimized_away)

The condition is extracted into need_empty_set_row and a second variable
empty_set_send_rollup_total is recorded to prevent running the default
rollup_send_data/rollup_write_data on the empty row case. This is
because the null summary row is already handled by send_data_with_check.
@jaeheonshim

jaeheonshim commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the IN -> EXISTS mechanism by patching opt_subselect.cc

@gkodinov

Copy link
Copy Markdown
Member

FYI: According to our development cycle we work on bugs In the following periods 15 Mar-30 Apr, 15 Jun-30 Jul, 15 Sep-30 Oct and 15 Dec-31 Jan. So, please, expect to get a review somewhere between these two dates and the goal is to have your PR merged before the second date

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

4 participants