Skip to content

MDEV-22269 GROUPING function - #5314

Open
jaeheonshim wants to merge 5 commits into
MariaDB:mainfrom
jaeheonshim:MDEV-22269-grouping
Open

MDEV-22269 GROUPING function#5314
jaeheonshim wants to merge 5 commits into
MariaDB:mainfrom
jaeheonshim:MDEV-22269-grouping

Conversation

@jaeheonshim

Copy link
Copy Markdown
Contributor

MDEV-22269: Add support for the GROUPING() function (SQL:2008 feature T431).

@jaeheonshim

Copy link
Copy Markdown
Contributor Author

Note: GROUPING is currently broken and segfaults if nested inside a function (e.g.: select name, size, bin(grouping(name, size)), sum(quantity) from t group by name, size with rollup;). This is because in JOIN::rollup_init, we only check the outer-level select list Items, so Item_func_grouping::setup_rollup doesn't get called on any nested GROUPING functions. Working on a fix.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements the SQL GROUPING() function, introducing the Item_func_grouping class, adding parser support for the GROUPING keyword, and integrating it with rollup processing. The feedback highlights critical safety improvements: initializing member variables in the Item_func_grouping constructor to prevent undefined behavior, limiting the number of arguments to 64 to avoid bit-shifting overflow, and adding a null-pointer check along with using bitwise OR operations in val_int() for safer bitmask construction.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread sql/item_func.h Outdated
Comment thread sql/item_func.cc Outdated
Comment thread sql/item_func.cc
@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Jul 2, 2026
@jaeheonshim
jaeheonshim force-pushed the MDEV-22269-grouping branch from 257f8c9 to b1721fd Compare July 5, 2026 23:10
@grooverdan grooverdan added the GSoC label Jul 5, 2026
@mariadb-RexJohnston

Copy link
Copy Markdown
Member

I created https://jira.mariadb.org/browse/MDEV-40611
It'll need fixing before you can uncomment this in your tests

# Test with view and GROUPING() in having clause
#CREATE VIEW v AS SELECT (SELECT  MAX(a) FROM t1) as field1 FROM t1
#GROUP BY field1 WITH ROLLUP HAVING GROUPING(field1)=0;
#SELECT * FROM v;
#DROP VIEW v;

@jaeheonshim
jaeheonshim force-pushed the MDEV-22269-grouping branch 5 times, most recently from f635cc0 to 7011078 Compare August 10, 2026 23:07
@jaeheonshim
jaeheonshim marked this pull request as ready for review August 10, 2026 23:10
@jaeheonshim
jaeheonshim force-pushed the MDEV-22269-grouping branch 2 times, most recently from ca4106a to 597b361 Compare August 10, 2026 23:20

@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.

Thanks for your work. This is a preliminary review.

Couple of formal things to fix:

  • rebase and resolve the merge conflicts please
  • squash the two separate commits into a single one (or state the reason for having tw o commits instead of one)
  • fix the P_S digest failures, e.g.
perfschema.start_server_low_digest_sql_length w17 [ fail ]
        Test ended at 2026-08-10 23:46:51
CURRENT_TEST: perfschema.start_server_low_digest_sql_length
--- /home/buildbot/amd64-msan-clang-20/build/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.result	2026-08-10 23:25:32.000000000 +0000
+++ /home/buildbot/amd64-msan-clang-20/build/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.reject	2026-08-10 23:46:51.017149385 +0000
@@ -8,5 +8,5 @@
 ####################################
 SELECT event_name, digest, digest_text, sql_text FROM events_statements_history_long;
 event_name	digest	digest_text	sql_text
-statement/sql/select	bc85fb4e8188bed1c842f764ec9fb06a	SELECT ? + ? + 	SELECT ...
-statement/sql/truncate	208418d9203df0b1b2cadb4d7196ea77	TRUNCATE TABLE 	truncat...
+statement/sql/select	2490fb0602b2ad29d2adc5923c6be917	SELECT ? + ? + 	SELECT ...
+statement/sql/truncate	8460b8b5a83d4357fcb94a1ccbb54817	TRUNCATE TABLE 	truncat...

@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.

Either fix everything that there is to fix in this one or keep it in "draft" until you do please.
There's still two commits, unresolved conflicts and spurious errors in buildbot.

@jaeheonshim

Copy link
Copy Markdown
Contributor Author

Sorry about that, I've resolved the merge conflicts and fixed the digest failures. the reason I have two commits is purely for attribution purposes: the first commit contains only test cases pulled from mysql, and the second commit contains my actual contributions

@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.

I'd expand a little bit on the commit comments. Otherwise, LGTM.

Tests for the GROUPING() function taken from mysql-test/t/olap.test
Comment thread sql/sql_select.cc
empty grouping set. Rollup level is set to 0 so that GROUPING() behaves
correctly.
*/
rollup_set_level(0);

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.

you also need a complimentary join->rollup_set_level(0); in the send_row_on_empty_set() branch of do_select()
Add this to test

CREATE TABLE t1 (a INT PRIMARY KEY); INSERT INTO t1 VALUES (1);
SELECT a, GROUPING(a) FROM t1 WHERE a=1 AND rand() > 2 GROUP BY a WITH ROLLUP;

Comment thread sql/item_func.cc
if (Item_func::fix_fields(thd, ref))
return true;

// longlong is 64 bits, so we can represent a maximum of 64 arguments

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.

actually, longlong is 63 bits + sign bit. hint. hint.

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.

does the sign bit not count? MySQL does this, so that if you have all 64 arguments activated the value of GROUPING is -1

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.

Does it work with 64 args? I can see it working for 63.

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 works for 64, added a test to confirm this

Comment thread sql/share/errmsg-utf8.txt Outdated
Comment thread sql/item_func.cc Outdated

longlong Item_func_grouping::val_int()
{
if (!min_rollup_levels)

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.

Is this the right thing to do here? We are trying to extract a value out a function that isn't resolved.

Comment thread sql/item_func.cc

bool Item_func_grouping::resolve_args(THD *thd, ORDER *group_list)
{
if (!(min_rollup_levels= thd->alloc<uint>(arg_count)))

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 allocated on execution memory. Is the first allocation freed before, say, second execution of a prepared statement?

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'm not really sure. I thought allocating on the mem_root arena was standard for stuff like this, from just looking around the code.

Comment thread mysql-test/main/func_grouping.test Outdated

# Test with prepared statements
PREPARE ps FROM "SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=0";
EXECUTE ps;

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.

+EXECUTE ps;

EXECUTE ps;
PREPARE ps FROM
"SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=1";
EXECUTE ps;

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.

+EXECUTE PS;
+DEALLOCATE PREPARE ps;

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.

Or for a single execution -EXECUTE IMMEDIATE .. that doesn't need deallocation.

Comment thread mysql-test/main/func_grouping.test
SELECT EXISTS (SELECT t0.x FROM t0 a WHERE 1=0 GROUP BY a.x WITH ROLLUP) AS e
FROM t0;
DROP TABLE t0;

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.

please add a condition pushdown test, like this

SELECT * FROM (SELECT a, GROUPING(a) g FROM t1 GROUP BY a WITH ROLLUP) dt WHERE dt.g=1;

Comment thread sql/item_func.cc Outdated
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. GSoC

Development

Successfully merging this pull request may close these issues.

4 participants