From 03b4c24cd30722cb581ddf0981f6bd3469cabc05 Mon Sep 17 00:00:00 2001 From: Jaeheon Shim Date: Mon, 10 Aug 2026 02:01:52 -0400 Subject: [PATCH 1/5] MDEV-22269 Add GROUPING() tests from MySQL Tests for the GROUPING() function taken from mysql-test/t/olap.test --- mysql-test/main/func_grouping.result | 550 +++++++++++++++++++++++++++ mysql-test/main/func_grouping.test | 331 ++++++++++++++++ 2 files changed, 881 insertions(+) create mode 100644 mysql-test/main/func_grouping.result create mode 100644 mysql-test/main/func_grouping.test diff --git a/mysql-test/main/func_grouping.result b/mysql-test/main/func_grouping.result new file mode 100644 index 0000000000000..950968fdb3354 --- /dev/null +++ b/mysql-test/main/func_grouping.result @@ -0,0 +1,550 @@ +# +# MDEV-22269: GROUPING function +# +DROP TABLE IF EXISTS t0,t1,t2,t,t3; +DROP VIEW IF EXISTS v; +# +# Tests for WL#1979 - IMPLEMENTATION OF GROUPING FUNCTION +# +CREATE TABLE t0 (i0 INTEGER); +INSERT INTO t0 VALUES (1), (2), (3), (4), (5); +CREATE TABLE t1 ( +a INTEGER, +b INTEGER, +c INTEGER, +INDEX k1 (a), +INDEX k2 (a,b) +); +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0)) % 100, +(i0 + (10 * i0) + (100 * i0)) % 100 +FROM t0; +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0) + 1) % 100, +(i0 + (10 * i0) + (100 * i0) + 1) % 100 +FROM t0; +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0) + 1) % 100, +(i0 + (10 * i0) + (100 * i0) + 2) % 100 +FROM t0; +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM t1 ORDER BY a,b,c; +a b c +111 11 11 +111 12 12 +111 12 13 +222 22 22 +222 23 23 +222 23 24 +333 33 33 +333 34 34 +333 34 35 +444 44 44 +444 45 45 +444 45 46 +555 55 55 +555 56 56 +555 56 57 +SELECT a, b, c, GROUPING(a) FROM t1 GROUP BY a,b,c WITH ROLLUP; +a b c GROUPING(a) +111 11 11 0 +111 11 NULL 0 +111 12 12 0 +111 12 13 0 +111 12 NULL 0 +111 NULL NULL 0 +222 22 22 0 +222 22 NULL 0 +222 23 23 0 +222 23 24 0 +222 23 NULL 0 +222 NULL NULL 0 +333 33 33 0 +333 33 NULL 0 +333 34 34 0 +333 34 35 0 +333 34 NULL 0 +333 NULL NULL 0 +444 44 44 0 +444 44 NULL 0 +444 45 45 0 +444 45 46 0 +444 45 NULL 0 +444 NULL NULL 0 +555 55 55 0 +555 55 NULL 0 +555 56 56 0 +555 56 57 0 +555 56 NULL 0 +555 NULL NULL 0 +NULL NULL NULL 1 +SELECT a, b, c, GROUPING(a, b) FROM t1 GROUP BY a,b,c WITH ROLLUP; +a b c GROUPING(a, b) +111 11 11 0 +111 11 NULL 0 +111 12 12 0 +111 12 13 0 +111 12 NULL 0 +111 NULL NULL 1 +222 22 22 0 +222 22 NULL 0 +222 23 23 0 +222 23 24 0 +222 23 NULL 0 +222 NULL NULL 1 +333 33 33 0 +333 33 NULL 0 +333 34 34 0 +333 34 35 0 +333 34 NULL 0 +333 NULL NULL 1 +444 44 44 0 +444 44 NULL 0 +444 45 45 0 +444 45 46 0 +444 45 NULL 0 +444 NULL NULL 1 +555 55 55 0 +555 55 NULL 0 +555 56 56 0 +555 56 57 0 +555 56 NULL 0 +555 NULL NULL 1 +NULL NULL NULL 3 +SELECT a, b, c, GROUPING(a, b, c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +a b c GROUPING(a, b, c) +111 11 11 0 +111 11 NULL 1 +111 12 12 0 +111 12 13 0 +111 12 NULL 1 +111 NULL NULL 3 +222 22 22 0 +222 22 NULL 1 +222 23 23 0 +222 23 24 0 +222 23 NULL 1 +222 NULL NULL 3 +333 33 33 0 +333 33 NULL 1 +333 34 34 0 +333 34 35 0 +333 34 NULL 1 +333 NULL NULL 3 +444 44 44 0 +444 44 NULL 1 +444 45 45 0 +444 45 46 0 +444 45 NULL 1 +444 NULL NULL 3 +555 55 55 0 +555 55 NULL 1 +555 56 56 0 +555 56 57 0 +555 56 NULL 1 +555 NULL NULL 3 +NULL NULL NULL 7 +SELECT a, b FROM t1 GROUP BY a,b WITH ROLLUP HAVING GROUPING(b) = 1; +a b +111 NULL +222 NULL +333 NULL +444 NULL +555 NULL +NULL NULL +SELECT a, b, GROUPING(a) FROM t1 GROUP BY a,b; +a b GROUPING(a) +111 11 0 +111 12 0 +222 22 0 +222 23 0 +333 33 0 +333 34 0 +444 44 0 +444 45 0 +555 55 0 +555 56 0 +SELECT a, b, GROUPING(c) FROM t1 GROUP BY a,b WITH ROLLUP; +ERROR 42000: Argument 'test.t1.c' of GROUPING function is not in GROUP BY +SELECT a, b, GROUPING(a, b, c) FROM t1 GROUP BY a,b WITH ROLLUP; +ERROR 42000: Argument 'test.t1.c' of GROUPING function is not in GROUP BY +SELECT a, GROUPING(SUM(a)) FROM t1 GROUP BY (a) WITH ROLLUP; +ERROR 42000: Argument 'tmp_field' of GROUPING function is not in GROUP BY +SELECT a, b, GROUPING(a) FROM t1; +ERROR 42000: Argument 'test.t1.a' of GROUPING function is not in GROUP BY +SELECT a, b FROM t1 WHERE GROUPING(a)=1 GROUP BY a,b WITH ROLLUP; +ERROR HY000: Invalid use of group function +SELECT a, b FROM t1 GROUP BY GROUPING(a),GROUPING(b) WITH ROLLUP; +ERROR HY000: Invalid use of group function +SELECT a, b, c, GROUPING(1) FROM t1 GROUP BY a,b,c WITH ROLLUP; +ERROR 42000: Argument '1' of GROUPING function is not in GROUP BY +SELECT a, GROUPING(1) FROM t1 GROUP BY 1 WITH ROLLUP; +ERROR 42000: Argument '1' of GROUPING function is not in GROUP BY +SELECT GROUPING(1) FROM t1 GROUP BY 1 WITH ROLLUP; +ERROR 42000: Argument '1' of GROUPING function is not in GROUP BY +CREATE TABLE t3 ( i64 INTEGER, i63 INTEGER, i62 INTEGER, i61 INTEGER, i60 INTEGER, i59 INTEGER, i58 INTEGER, i57 INTEGER, i56 INTEGER, i55 INTEGER, i54 INTEGER, i53 INTEGER, i52 INTEGER, i51 INTEGER, i50 INTEGER, i49 INTEGER, i48 INTEGER, i47 INTEGER, i46 INTEGER, i45 INTEGER, i44 INTEGER, i43 INTEGER, i42 INTEGER, i41 INTEGER, i40 INTEGER, i39 INTEGER, i38 INTEGER, i37 INTEGER, i36 INTEGER, i35 INTEGER, i34 INTEGER, i33 INTEGER, i32 INTEGER, i31 INTEGER, i30 INTEGER, i29 INTEGER, i28 INTEGER, i27 INTEGER, i26 INTEGER, i25 INTEGER, i24 INTEGER, i23 INTEGER, i22 INTEGER, i21 INTEGER, i20 INTEGER, i19 INTEGER, i18 INTEGER, i17 INTEGER, i16 INTEGER, i15 INTEGER, i14 INTEGER, i13 INTEGER, i12 INTEGER, i11 INTEGER, i10 INTEGER, i9 INTEGER, i8 INTEGER, i7 INTEGER, i6 INTEGER, i5 INTEGER, i4 INTEGER, i3 INTEGER, i2 INTEGER, i1 INTEGER, i65 INTEGER); +SELECT GROUPING( i64, i63, i62, i61, i60, i59, i58, i57, i56, i55, i54, i53, i52, i51, i50, i49, i48, i47, i46, i45, i44, i43, i42, i41, i40, i39, i38, i37, i36, i35, i34, i33, i32, i31, i30, i29, i28, i27, i26, i25, i24, i23, i22, i21, i20, i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6, i5, i4, i3, i2, i1, i65) FROM t3 GROUP BY (i1) WITH ROLLUP; +ERROR 42000: Too many arguments for function GROUPING: 65; maximum allowed is 64. +DROP TABLE t3; +SELECT a, b, GROUPING(c + c) FROM t1 GROUP BY a,b WITH ROLLUP; +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT a, b, GROUPING(c + c) FROM t1 GROUP BY a,b,(c + c) WITH ROLLUP; +a b GROUPING(c + c) +111 11 0 +111 11 1 +111 12 0 +111 12 0 +111 12 1 +111 NULL 1 +222 22 0 +222 22 1 +222 23 0 +222 23 0 +222 23 1 +222 NULL 1 +333 33 0 +333 33 1 +333 34 0 +333 34 0 +333 34 1 +333 NULL 1 +444 44 0 +444 44 1 +444 45 0 +444 45 0 +444 45 1 +444 NULL 1 +555 55 0 +555 55 1 +555 56 0 +555 56 0 +555 56 1 +555 NULL 1 +NULL NULL 1 +SELECT GROUPING((SELECT MAX(b) FROM t1)) FROM t1 +GROUP BY (SELECT MAX(b) FROM t1) WITH ROLLUP; +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT (SELECT MAX(b) FROM t1) FROM t1 GROUP BY (SELECT MAX(b) FROM t1) +WITH ROLLUP HAVING GROUPING((SELECT 1 FROM DUAL))=0; +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT (SELECT MAX(b) FROM t1) FROM t1 GROUP BY (SELECT MAX(b) FROM t1) +WITH ROLLUP HAVING GROUPING((SELECT MAX(b) FROM t1))=0; +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT 1 WHERE EXISTS (SELECT a FROM t1 GROUP BY a WITH ROLLUP); +1 +1 +SELECT 1 WHERE 2 > +ALL (SELECT GROUPING(a) FROM t1 GROUP BY a WITH ROLLUP); +1 +1 +SELECT 1 WHERE 1 = +ANY (SELECT GROUPING(a) FROM t1 GROUP BY a WITH ROLLUP); +1 +1 +PREPARE ps FROM "SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=0"; +EXECUTE ps; +a +111 +222 +333 +444 +555 +PREPARE ps FROM +"SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=1"; +EXECUTE ps; +a +NULL +CREATE VIEW v AS SELECT * FROM t1; +PREPARE ps FROM "SELECT GROUPING(a) FROM v GROUP BY a WITH ROLLUP"; +EXECUTE ps; +GROUPING(a) +0 +0 +0 +0 +0 +1 +DROP VIEW v; +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM (SELECT b from t1) AS t2 GROUP BY t2.b); +MAX(a) +555 +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM t1 AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0); +MAX(a) +555 +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM (SELECT b from t1) AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0); +MAX(a) +555 +WITH qn AS (SELECT a, b, c, GROUPING(a) as grouping_a FROM t1 +GROUP BY a,b,c WITH ROLLUP) +SELECT * FROM qn; +a b c grouping_a +111 11 11 0 +111 11 NULL 0 +111 12 12 0 +111 12 13 0 +111 12 NULL 0 +111 NULL NULL 0 +222 22 22 0 +222 22 NULL 0 +222 23 23 0 +222 23 24 0 +222 23 NULL 0 +222 NULL NULL 0 +333 33 33 0 +333 33 NULL 0 +333 34 34 0 +333 34 35 0 +333 34 NULL 0 +333 NULL NULL 0 +444 44 44 0 +444 44 NULL 0 +444 45 45 0 +444 45 46 0 +444 45 NULL 0 +444 NULL NULL 0 +555 55 55 0 +555 55 NULL 0 +555 56 56 0 +555 56 57 0 +555 56 NULL 0 +555 NULL NULL 0 +NULL NULL NULL 1 +WITH qn AS (SELECT (SELECT MAX(a) FROM t1) as field1 FROM t1 +GROUP BY field1 WITH ROLLUP HAVING GROUPING(field1)=0) +SELECT * FROM qn; +field1 +555 +with qn as (SELECT MAX(a) FROM t1 WHERE (b) IN ( +SELECT MIN(t2.b) FROM (SELECT b from t1) AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0)) +SELECT * FROM qn; +MAX(a) +555 +WITH qn AS(SELECT GROUPING((SELECT MAX(b) FROM t1)) as field1 +FROM t1 GROUP BY (SELECT MAX(b) FROM t1) WITH ROLLUP) +SELECT qn.field1 FROM qn; +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT a as Department,b as Employees, SUM(c), GROUPING(a) as GP_A, +GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP; +Department Employees SUM(c) GP_A GP_B +111 11 11 0 0 +111 12 25 0 0 +111 NULL 36 0 1 +222 22 22 0 0 +222 23 47 0 0 +222 NULL 69 0 1 +333 33 33 0 0 +333 34 69 0 0 +333 NULL 102 0 1 +444 44 44 0 0 +444 45 91 0 0 +444 NULL 135 0 1 +555 55 55 0 0 +555 56 113 0 0 +555 NULL 168 0 1 +NULL NULL 510 1 1 +SELECT a as Department,b as Employees, SUM(c), GROUPING(a) as GP_A, +GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP +HAVING GP_A=1 OR GP_B=1; +Department Employees SUM(c) GP_A GP_B +111 NULL 36 0 1 +222 NULL 69 0 1 +333 NULL 102 0 1 +444 NULL 135 0 1 +555 NULL 168 0 1 +NULL NULL 510 1 1 +SELECT IF(GROUPING(a)=1,'All Departments', a) as Department, +IF(GROUPING(b)=1, 'All Employees', b) as Employees, +SUM(c) as SUM +FROM t1 GROUP BY a,b WITH ROLLUP; +Department Employees SUM +111 11 11 +111 12 25 +111 All Employees 36 +222 22 22 +222 23 47 +222 All Employees 69 +333 33 33 +333 34 69 +333 All Employees 102 +444 44 44 +444 45 91 +444 All Employees 135 +555 55 55 +555 56 113 +555 All Employees 168 +All Departments All Employees 510 +INSERT INTO t1 values (1111,NULL,112); +INSERT INTO t1 values (1111,NULL,NULL); +INSERT INTO t1 values (NULL,112,NULL); +SELECT a as Department, b as Employees, SUM(c), GROUPING(a) as GP_A, +GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP; +Department Employees SUM(c) GP_A GP_B +NULL 112 NULL 0 0 +NULL NULL NULL 0 1 +111 11 11 0 0 +111 12 25 0 0 +111 NULL 36 0 1 +222 22 22 0 0 +222 23 47 0 0 +222 NULL 69 0 1 +333 33 33 0 0 +333 34 69 0 0 +333 NULL 102 0 1 +444 44 44 0 0 +444 45 91 0 0 +444 NULL 135 0 1 +555 55 55 0 0 +555 56 113 0 0 +555 NULL 168 0 1 +1111 NULL 112 0 0 +1111 NULL 112 0 1 +NULL NULL 622 1 1 +SELECT a as Department, b as Employees, SUM(c), GROUPING(a) as GP_A, +GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP +HAVING (GP_A =1 AND GP_B=1) OR (GP_B=1); +Department Employees SUM(c) GP_A GP_B +NULL NULL NULL 0 1 +111 NULL 36 0 1 +222 NULL 69 0 1 +333 NULL 102 0 1 +444 NULL 135 0 1 +555 NULL 168 0 1 +1111 NULL 112 0 1 +NULL NULL 622 1 1 +DROP TABLE t0,t1; +# +# Bug#26073525: Allow GROUPING function in ORDER BY +# +CREATE TABLE t0 (i0 INTEGER); +INSERT INTO t0 VALUES (1), (2), (3), (4), (5); +CREATE TABLE t1 (i INTEGER, j INTEGER, k INTEGER, INDEX k1(i), INDEX k2(j,k)); +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0)) % 100, +(i0 + (10 * i0) + (100 * i0)) % 100 +FROM t0; +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0) + 1) % 100, +(i0 + (10 * i0) + (100 * i0) + 1) % 100 +FROM t0; +INSERT INTO t1 +SELECT i0 + (10 * i0) + (100 * i0), +(i0 + (10 * i0) + (100 * i0) + 1) % 100, +(i0 + (10 * i0) + (100 * i0) + 2) % 100 +FROM t0; +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT DISTINCT GROUPING(i), GROUPING(j) FROM t1 GROUP BY i,j WITH ROLLUP; +GROUPING(i) GROUPING(j) +0 0 +0 1 +1 1 +SELECT DISTINCT j, GROUPING(j) FROM t1 GROUP BY i,j WITH ROLLUP; +j GROUPING(j) +11 0 +12 0 +22 0 +23 0 +33 0 +34 0 +44 0 +45 0 +55 0 +56 0 +NULL 1 +SELECT i, j, AVG(k) FROM t1 GROUP BY i,j+GROUPING(i) WITH ROLLUP; +ERROR HY000: Invalid use of group function +DROP TABLE t0,t1; +# +# Bug #33149402: SELECT'S GROUPING() NOT TAKEN IN ACCOUNT IN HAVING WHEN JOIN USED +# +CREATE TABLE t1 (a INTEGER, b INTEGER); +INSERT INTO t1 VALUES (2020, 2); +CREATE TABLE t2 (b INTEGER); +INSERT INTO t2 VALUES (2); +SELECT a, GROUPING(a) AS ga +FROM t1 JOIN t2 USING (b) +GROUP BY a WITH ROLLUP +HAVING ga = 0; +a ga +2020 0 +DROP TABLE t1, t2; +# +# Bug#36039905: Assertion `table_num_to_node_num[table_num] != -1' failed +# +CREATE TABLE t(x INT); +SELECT 1 FROM t AS t1, t AS t2, +(SELECT DISTINCT GROUPING(t3.x) FROM t AS t3, t AS t4 +GROUP BY t3.x WITH ROLLUP) AS dt; +1 +DROP TABLE t; +# +# Bug#36514339 ROLLUP misses a summary NULL +# +CREATE TABLE t(a INT); +SELECT GROUPING(a), a, COUNT(*) FROM t GROUP BY a WITH ROLLUP; +GROUPING(a) a COUNT(*) +1 NULL 0 +DROP TABLE t; +# +# Bug#38168051: Support for GROUPING() function with primitive GBY +# +CREATE TABLE t1 (f1 INTEGER, f2 INTEGER); +INSERT INTO t1 VALUES (1,1), (1,2), (2,1); +SELECT GROUPING(f1) FROM t1 GROUP BY f1; +GROUPING(f1) +0 +0 +SELECT GROUPING(f2) FROM t1 GROUP BY f1; +ERROR 42000: Argument 'test.t1.f2' of GROUPING function is not in GROUP BY +SELECT GROUPING(f3) FROM t1 GROUP BY f1; +ERROR 42S22: Unknown column 'f3' in 'SELECT' +SELECT f1, f2, GROUPING(f3) FROM t1 GROUP BY f1; +ERROR 42S22: Unknown column 'f3' in 'SELECT' +SELECT f1, f1+GROUPING(f1) FROM t1 GROUP BY f1; +f1 f1+GROUPING(f1) +1 1 +2 2 +SELECT f1 FROM t1 GROUP BY f1 HAVING GROUPING(f1) = 0; +f1 +1 +2 +SELECT f1 FROM t1 GROUP BY f1 HAVING GROUPING(f2) = 0; +ERROR 42S22: Unknown column 'f2' in 'HAVING' +SELECT f1 FROM t1 GROUP BY f1 HAVING f1+GROUPING(f1) = 0; +f1 +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f1); +f1 +1 +2 +SELECT SUM(f1) OVER(PARTITION BY GROUPING(f1)) FROM t1 GROUP BY f1; +SUM(f1) OVER(PARTITION BY GROUPING(f1)) +3 +3 +SELECT SUM(f1) OVER(PARTITION BY GROUPING(f2)) FROM t1 GROUP BY f1; +ERROR 42000: Argument 'test.t1.f2' of GROUPING function is not in GROUP BY +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f2); +ERROR 42000: Argument 'test.t1.f2' of GROUPING function is not in GROUP BY +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f1+f1); +ERROR 42000: Argument '???' of GROUPING function is not in GROUP BY +SELECT 1 FROM t1 GROUP BY (f1+f1) ORDER BY GROUPING(f1+f1); +1 +1 +1 +DROP TABLE t1; +# End of 13.1 tests. diff --git a/mysql-test/main/func_grouping.test b/mysql-test/main/func_grouping.test new file mode 100644 index 0000000000000..55a5626328129 --- /dev/null +++ b/mysql-test/main/func_grouping.test @@ -0,0 +1,331 @@ +# Copyright (c) 2016, 2025, Oracle and/or its affiliates. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +--echo # +--echo # MDEV-22269: GROUPING function +--echo # + +--source include/have_innodb.inc + +--disable_warnings +DROP TABLE IF EXISTS t0,t1,t2,t,t3; +DROP VIEW IF EXISTS v; +--enable_warnings + +--echo # +--echo # Tests for WL#1979 - IMPLEMENTATION OF GROUPING FUNCTION +--echo # + +CREATE TABLE t0 (i0 INTEGER); + +INSERT INTO t0 VALUES (1), (2), (3), (4), (5); + +CREATE TABLE t1 ( + a INTEGER, + b INTEGER, + c INTEGER, + INDEX k1 (a), + INDEX k2 (a,b) +); + +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0)) % 100, + (i0 + (10 * i0) + (100 * i0)) % 100 + FROM t0; + +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0) + 1) % 100, + (i0 + (10 * i0) + (100 * i0) + 1) % 100 + FROM t0; + +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0) + 1) % 100, + (i0 + (10 * i0) + (100 * i0) + 2) % 100 + FROM t0; + +ANALYZE TABLE t1; + +SELECT * FROM t1 ORDER BY a,b,c; + +# Testing for syntax +# Success cases +SELECT a, b, c, GROUPING(a) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT a, b, c, GROUPING(a, b) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT a, b, c, GROUPING(a, b, c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT a, b FROM t1 GROUP BY a,b WITH ROLLUP HAVING GROUPING(b) = 1; +SELECT a, b, GROUPING(a) FROM t1 GROUP BY a,b; + +# Failure cases +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, b, GROUPING(c) FROM t1 GROUP BY a,b WITH ROLLUP; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, b, GROUPING(a, b, c) FROM t1 GROUP BY a,b WITH ROLLUP; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, GROUPING(SUM(a)) FROM t1 GROUP BY (a) WITH ROLLUP; + +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, b, GROUPING(a) FROM t1; +--error ER_INVALID_GROUP_FUNC_USE +SELECT a, b FROM t1 WHERE GROUPING(a)=1 GROUP BY a,b WITH ROLLUP; +--error ER_INVALID_GROUP_FUNC_USE +SELECT a, b FROM t1 GROUP BY GROUPING(a),GROUPING(b) WITH ROLLUP; + +# Check for GROUPING by position. We do not allow it +-- error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, b, c, GROUPING(1) FROM t1 GROUP BY a,b,c WITH ROLLUP; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, GROUPING(1) FROM t1 GROUP BY 1 WITH ROLLUP; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT GROUPING(1) FROM t1 GROUP BY 1 WITH ROLLUP; + +# Check the restriction on the number of args to +# grouping function +let $query1= CREATE TABLE t3 (; +let $col_cnt=64; +while ($col_cnt) +{ + let $query1= $query1 i$col_cnt INTEGER,; + dec $col_cnt; +} + +let $query1= $query1 i65 INTEGER); +eval $query1; + +let $query= SELECT GROUPING(; +let col_cnt=64; +while ($col_cnt) +{ +let $query= $query i$col_cnt,; +dec $col_cnt; +} +let $query= $query i65) FROM t3 GROUP BY (i1) WITH ROLLUP; + +--error ER_TOO_MANY_ARGS +eval $query; +DROP TABLE t3; + +# Check for expressions +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT a, b, GROUPING(c + c) FROM t1 GROUP BY a,b WITH ROLLUP; +# Wrong results FROM this because of bug in rollup +SELECT a, b, GROUPING(c + c) FROM t1 GROUP BY a,b,(c + c) WITH ROLLUP; + +# We do not allow sub-queries as arguments to GROUPING() +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT GROUPING((SELECT MAX(b) FROM t1)) FROM t1 +GROUP BY (SELECT MAX(b) FROM t1) WITH ROLLUP; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT (SELECT MAX(b) FROM t1) FROM t1 GROUP BY (SELECT MAX(b) FROM t1) + WITH ROLLUP HAVING GROUPING((SELECT 1 FROM DUAL))=0; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT (SELECT MAX(b) FROM t1) FROM t1 GROUP BY (SELECT MAX(b) FROM t1) + WITH ROLLUP HAVING GROUPING((SELECT MAX(b) FROM t1))=0; + +# Test GROUPING() with ALL/ANY/EXISTS +SELECT 1 WHERE EXISTS (SELECT a FROM t1 GROUP BY a WITH ROLLUP); +SELECT 1 WHERE 2 > +ALL (SELECT GROUPING(a) FROM t1 GROUP BY a WITH ROLLUP); +SELECT 1 WHERE 1 = +ANY (SELECT GROUPING(a) FROM t1 GROUP BY a WITH ROLLUP); + +# Test with prepared statements +PREPARE ps FROM "SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=0"; +EXECUTE ps; +PREPARE ps FROM +"SELECT a FROM t1 GROUP BY a WITH ROLLUP HAVING GROUPING(a)=1"; +EXECUTE ps; + +# Test with derived tables with prepared statements +CREATE VIEW v AS SELECT * FROM t1; +PREPARE ps FROM "SELECT GROUPING(a) FROM v GROUP BY a WITH ROLLUP"; +EXECUTE ps; +DROP VIEW v; + +# 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; + +# Test with derived tables +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM (SELECT b from t1) AS t2 GROUP BY t2.b); +# With out derived table in where subquery +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM t1 AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0); +# With derived table in where subquery +SELECT MAX(a) FROM t1 WHERE (b) IN (SELECT MIN(t2.b) +FROM (SELECT b from t1) AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0); +# With CTE +WITH qn AS (SELECT a, b, c, GROUPING(a) as grouping_a FROM t1 + GROUP BY a,b,c WITH ROLLUP) +SELECT * FROM qn; +WITH qn AS (SELECT (SELECT MAX(a) FROM t1) as field1 FROM t1 +GROUP BY field1 WITH ROLLUP HAVING GROUPING(field1)=0) +SELECT * FROM qn; +with qn as (SELECT MAX(a) FROM t1 WHERE (b) IN ( +SELECT MIN(t2.b) FROM (SELECT b from t1) AS t2 GROUP BY t2.b WITH +ROLLUP HAVING GROUPING (t2.b)=0)) +SELECT * FROM qn; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +WITH qn AS(SELECT GROUPING((SELECT MAX(b) FROM t1)) as field1 + FROM t1 GROUP BY (SELECT MAX(b) FROM t1) WITH ROLLUP) +SELECT qn.field1 FROM qn; + +# Usage + +# Check for grouping of the two columns +SELECT a as Department,b as Employees, SUM(c), GROUPING(a) as GP_A, + GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP; + +# Check for the rows having only super-aggregates +SELECT a as Department,b as Employees, SUM(c), GROUPING(a) as GP_A, + GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP + HAVING GP_A=1 OR GP_B=1; + +# Differentiate Super-Aggregates and Aggregates +SELECT IF(GROUPING(a)=1,'All Departments', a) as Department, + IF(GROUPING(b)=1, 'All Employees', b) as Employees, + SUM(c) as SUM +FROM t1 GROUP BY a,b WITH ROLLUP; + +# Use grouping to differentiate between NULLs FROM the table data +# and NULLs FROM the ROLLUP + +INSERT INTO t1 values (1111,NULL,112); +INSERT INTO t1 values (1111,NULL,NULL); +INSERT INTO t1 values (NULL,112,NULL); + +SELECT a as Department, b as Employees, SUM(c), GROUPING(a) as GP_A, + GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP; + +SELECT a as Department, b as Employees, SUM(c), GROUPING(a) as GP_A, + GROUPING(b) as GP_B FROM t1 GROUP BY a,b WITH ROLLUP + HAVING (GP_A =1 AND GP_B=1) OR (GP_B=1); + +DROP TABLE t0,t1; + +# End of test for WL#1979 + +--echo # +--echo # Bug#26073525: Allow GROUPING function in ORDER BY +--echo # + +CREATE TABLE t0 (i0 INTEGER); +INSERT INTO t0 VALUES (1), (2), (3), (4), (5); + +CREATE TABLE t1 (i INTEGER, j INTEGER, k INTEGER, INDEX k1(i), INDEX k2(j,k)); +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0)) % 100, + (i0 + (10 * i0) + (100 * i0)) % 100 + FROM t0; + +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0) + 1) % 100, + (i0 + (10 * i0) + (100 * i0) + 1) % 100 + FROM t0; + +INSERT INTO t1 + SELECT i0 + (10 * i0) + (100 * i0), + (i0 + (10 * i0) + (100 * i0) + 1) % 100, + (i0 + (10 * i0) + (100 * i0) + 2) % 100 + FROM t0; + +ANALYZE TABLE t1; + +#GROUPING with DISTINCT +--sorted_result +SELECT DISTINCT GROUPING(i), GROUPING(j) FROM t1 GROUP BY i,j WITH ROLLUP; +--sorted_result +SELECT DISTINCT j, GROUPING(j) FROM t1 GROUP BY i,j WITH ROLLUP; + +#Error case +--error ER_INVALID_GROUP_FUNC_USE +SELECT i, j, AVG(k) FROM t1 GROUP BY i,j+GROUPING(i) WITH ROLLUP; + +DROP TABLE t0,t1; + +--echo # +--echo # Bug #33149402: SELECT'S GROUPING() NOT TAKEN IN ACCOUNT IN HAVING WHEN JOIN USED +--echo # + +CREATE TABLE t1 (a INTEGER, b INTEGER); +INSERT INTO t1 VALUES (2020, 2); + +CREATE TABLE t2 (b INTEGER); +INSERT INTO t2 VALUES (2); + +SELECT a, GROUPING(a) AS ga + FROM t1 JOIN t2 USING (b) + GROUP BY a WITH ROLLUP + HAVING ga = 0; + +DROP TABLE t1, t2; + +--echo # +--echo # Bug#36039905: Assertion `table_num_to_node_num[table_num] != -1' failed +--echo # + +CREATE TABLE t(x INT); +# Used to fail when running with the hypergraph optimizer and --ps-protocol. +SELECT 1 FROM t AS t1, t AS t2, +(SELECT DISTINCT GROUPING(t3.x) FROM t AS t3, t AS t4 +GROUP BY t3.x WITH ROLLUP) AS dt; +DROP TABLE t; + +--echo # +--echo # Bug#36514339 ROLLUP misses a summary NULL +--echo # +CREATE TABLE t(a INT); +SELECT GROUPING(a), a, COUNT(*) FROM t GROUP BY a WITH ROLLUP; +DROP TABLE t; + +--echo # +--echo # Bug#38168051: Support for GROUPING() function with primitive GBY +--echo # + +CREATE TABLE t1 (f1 INTEGER, f2 INTEGER); +INSERT INTO t1 VALUES (1,1), (1,2), (2,1); +SELECT GROUPING(f1) FROM t1 GROUP BY f1; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT GROUPING(f2) FROM t1 GROUP BY f1; +--error ER_BAD_FIELD_ERROR +SELECT GROUPING(f3) FROM t1 GROUP BY f1; +--error ER_BAD_FIELD_ERROR +SELECT f1, f2, GROUPING(f3) FROM t1 GROUP BY f1; +SELECT f1, f1+GROUPING(f1) FROM t1 GROUP BY f1; +SELECT f1 FROM t1 GROUP BY f1 HAVING GROUPING(f1) = 0; +--error ER_BAD_FIELD_ERROR +SELECT f1 FROM t1 GROUP BY f1 HAVING GROUPING(f2) = 0; +SELECT f1 FROM t1 GROUP BY f1 HAVING f1+GROUPING(f1) = 0; +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f1); +SELECT SUM(f1) OVER(PARTITION BY GROUPING(f1)) FROM t1 GROUP BY f1; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT SUM(f1) OVER(PARTITION BY GROUPING(f2)) FROM t1 GROUP BY f1; +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f2); +--error ER_FIELD_IN_GROUPING_NOT_GROUP_BY +SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f1+f1); +SELECT 1 FROM t1 GROUP BY (f1+f1) ORDER BY GROUPING(f1+f1); +DROP TABLE t1; + +--echo # End of 13.1 tests. From 30035003f23f382f1f91207637ad692c5bf08d61 Mon Sep 17 00:00:00 2001 From: Jaeheon Shim Date: Mon, 29 Jun 2026 18:34:35 -0400 Subject: [PATCH 2/5] MDEV-22269 Add support for the GROUPING() function SQL:2008 feature T431 --- mysql-test/main/func_grouping.result | 19 +++++ mysql-test/main/func_grouping.test | 14 ++++ mysql-test/main/ps_error.result | 1 + mysql-test/main/win.result | 1 + .../encryption/r/tempfiles_encrypted.result | 1 + .../suite/perfschema/r/digest_view.result | 50 ++++++------- .../start_server_low_digest_sql_length.result | 4 +- sql/item_func.cc | 71 +++++++++++++++++++ sql/item_func.h | 42 ++++++++++- sql/lex.h | 1 + sql/share/errmsg-utf8.txt | 4 ++ sql/sql_lex.cc | 7 ++ sql/sql_lex.h | 3 + sql/sql_select.cc | 71 +++++++++++++++++-- sql/sql_select.h | 13 +++- sql/sql_yacc.yy | 14 ++++ 16 files changed, 278 insertions(+), 38 deletions(-) diff --git a/mysql-test/main/func_grouping.result b/mysql-test/main/func_grouping.result index 950968fdb3354..2a68dd498e152 100644 --- a/mysql-test/main/func_grouping.result +++ b/mysql-test/main/func_grouping.result @@ -547,4 +547,23 @@ SELECT 1 FROM t1 GROUP BY (f1+f1) ORDER BY GROUPING(f1+f1); 1 1 DROP TABLE t1; +CREATE TABLE t0(x INT); +SELECT x, GROUPING(x) FROM t0 GROUP BY x WITH ROLLUP; +x GROUPING(x) +NULL 1 +SELECT * FROM t0 GROUP BY x WITH ROLLUP HAVING GROUPING(x)=1; +x +NULL +SELECT x FROM t0 WHERE 1=0 GROUP BY x WITH ROLLUP; +x +NULL +SELECT x, GROUPING(x), ROW_NUMBER() OVER () FROM t0 GROUP BY x WITH ROLLUP; +x GROUPING(x) ROW_NUMBER() OVER () +NULL 1 1 +INSERT INTO t0 VALUES (0); +SELECT EXISTS (SELECT t0.x FROM t0 a WHERE 1=0 GROUP BY a.x WITH ROLLUP) AS e +FROM t0; +e +1 +DROP TABLE t0; # End of 13.1 tests. diff --git a/mysql-test/main/func_grouping.test b/mysql-test/main/func_grouping.test index 55a5626328129..be7e26c9e3d00 100644 --- a/mysql-test/main/func_grouping.test +++ b/mysql-test/main/func_grouping.test @@ -287,9 +287,11 @@ DROP TABLE t1, t2; CREATE TABLE t(x INT); # Used to fail when running with the hypergraph optimizer and --ps-protocol. +--disable_view_protocol SELECT 1 FROM t AS t1, t AS t2, (SELECT DISTINCT GROUPING(t3.x) FROM t AS t3, t AS t4 GROUP BY t3.x WITH ROLLUP) AS dt; +--enable_view_protocol DROP TABLE t; --echo # @@ -328,4 +330,16 @@ SELECT f1 FROM t1 GROUP BY f1 ORDER BY GROUPING(f1+f1); SELECT 1 FROM t1 GROUP BY (f1+f1) ORDER BY GROUPING(f1+f1); DROP TABLE t1; +# send_row_on_empty_set tests +CREATE TABLE t0(x INT); +SELECT x, GROUPING(x) FROM t0 GROUP BY x WITH ROLLUP; +SELECT * FROM t0 GROUP BY x WITH ROLLUP HAVING GROUPING(x)=1; +SELECT x FROM t0 WHERE 1=0 GROUP BY x WITH ROLLUP; +SELECT x, GROUPING(x), ROW_NUMBER() OVER () FROM t0 GROUP BY x WITH ROLLUP; + +INSERT INTO t0 VALUES (0); +SELECT EXISTS (SELECT t0.x FROM t0 a WHERE 1=0 GROUP BY a.x WITH ROLLUP) AS e + FROM t0; +DROP TABLE t0; + --echo # End of 13.1 tests. diff --git a/mysql-test/main/ps_error.result b/mysql-test/main/ps_error.result index ad178f869155a..f3fa78a1bbe36 100644 --- a/mysql-test/main/ps_error.result +++ b/mysql-test/main/ps_error.result @@ -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'; diff --git a/mysql-test/main/win.result b/mysql-test/main/win.result index ec9ea7469eb83..16a37293d14d6 100644 --- a/mysql-test/main/win.result +++ b/mysql-test/main/win.result @@ -3539,6 +3539,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 diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index 16ab0b376da18..75291132437d8 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -3545,6 +3545,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 diff --git a/mysql-test/suite/perfschema/r/digest_view.result b/mysql-test/suite/perfschema/r/digest_view.result index 346b5e0c44e60..f9b22ba260e01 100644 --- a/mysql-test/suite/perfschema/r/digest_view.result +++ b/mysql-test/suite/perfschema/r/digest_view.result @@ -191,17 +191,17 @@ SELECT SCHEMA_NAME, DIGEST, DIGEST_TEXT, COUNT_STAR FROM performance_schema.events_statements_summary_by_digest ORDER BY DIGEST_TEXT; SCHEMA_NAME DIGEST DIGEST_TEXT COUNT_STAR -test cc5e38c5a702f49627052e59a2603818 EXPLAIN SELECT * FROM `test` . `v1` 1 -test 264b69debfd30bbfe374cdca018fa4f9 EXPLAIN SELECT * FROM `test` . `v1` WHERE `a` = ? 1 -test 75f31bf60b75a4f851ff9c9ee4e19d96 EXPLAIN SELECT * FROM `test` . `v1` WHERE `b` > ? 1 -test a8f8a85697afacda9f2f3d3b023f9ed0 EXPLAIN SELECT `a` , `b` FROM `test` . `v1` 1 -test 512598992d37826136f3f1292bb32e1e EXPLAIN SELECT `b` , `a` FROM `test` . `v1` 1 -test 54342cc19df16ce54b3ba43d1fd7552d SELECT * FROM `test` . `v1` 1 -test 3750b7d8c33e040b90a2cdccb4c642a3 SELECT * FROM `test` . `v1` WHERE `a` = ? 1 -test 94af70ef76a31364845f534863d99da8 SELECT * FROM `test` . `v1` WHERE `b` > ? 1 -test 0c87d86b62e664a81a23d4f176fbb377 SELECT `a` , `b` FROM `test` . `v1` 1 -test de7e6f1350ff14a952b97b373d76c1a4 SELECT `b` , `a` FROM `test` . `v1` 1 -test 3468091e6d6ce474aded20beaec36b53 TRUNCATE TABLE `performance_schema` . `events_statements_summary_by_digest` 1 +test a8719799988e32ae905b4d7bfef416f4 EXPLAIN SELECT * FROM `test` . `v1` 1 +test e61737b03042bac0dd2c45043b6686ba EXPLAIN SELECT * FROM `test` . `v1` WHERE `a` = ? 1 +test 88ab58db610f85333438b44f73adf260 EXPLAIN SELECT * FROM `test` . `v1` WHERE `b` > ? 1 +test 06376e4a052b257959bd3c60cae74230 EXPLAIN SELECT `a` , `b` FROM `test` . `v1` 1 +test a4d7551ca1c2458912541a4a7c682732 EXPLAIN SELECT `b` , `a` FROM `test` . `v1` 1 +test 4c4af7b536b849c61e011ef5d029edf1 SELECT * FROM `test` . `v1` 1 +test b04bcdacfc4f8ab9b08a119c44fcbb5c SELECT * FROM `test` . `v1` WHERE `a` = ? 1 +test 1d5b863293884ae15e046ae8e2008304 SELECT * FROM `test` . `v1` WHERE `b` > ? 1 +test 2f436c5c0ab6d7376c4586a6bd864580 SELECT `a` , `b` FROM `test` . `v1` 1 +test 125d6236e1ec60f9e46834b030bd8805 SELECT `b` , `a` FROM `test` . `v1` 1 +test 53dcc5b0f6bec99acc4336a294e337ac TRUNCATE TABLE `performance_schema` . `events_statements_summary_by_digest` 1 DROP TABLE test.v1; CREATE VIEW test.v1 AS SELECT * FROM test.t1; EXPLAIN SELECT * from test.v1; @@ -248,19 +248,19 @@ SELECT SCHEMA_NAME, DIGEST, DIGEST_TEXT, COUNT_STAR FROM performance_schema.events_statements_summary_by_digest ORDER BY DIGEST_TEXT; SCHEMA_NAME DIGEST DIGEST_TEXT COUNT_STAR -test ef8b10f452e117fa96af49687a93a10f CREATE VIEW `test` . `v1` AS SELECT * FROM `test` . `t1` 1 -test 6b99f4d2ad410f9fa4ee1d501b0db571 DROP TABLE `test` . `v1` 1 -test cc5e38c5a702f49627052e59a2603818 EXPLAIN SELECT * FROM `test` . `v1` 2 -test 264b69debfd30bbfe374cdca018fa4f9 EXPLAIN SELECT * FROM `test` . `v1` WHERE `a` = ? 2 -test 75f31bf60b75a4f851ff9c9ee4e19d96 EXPLAIN SELECT * FROM `test` . `v1` WHERE `b` > ? 2 -test a8f8a85697afacda9f2f3d3b023f9ed0 EXPLAIN SELECT `a` , `b` FROM `test` . `v1` 2 -test 512598992d37826136f3f1292bb32e1e EXPLAIN SELECT `b` , `a` FROM `test` . `v1` 2 -test 54342cc19df16ce54b3ba43d1fd7552d SELECT * FROM `test` . `v1` 2 -test 3750b7d8c33e040b90a2cdccb4c642a3 SELECT * FROM `test` . `v1` WHERE `a` = ? 2 -test 94af70ef76a31364845f534863d99da8 SELECT * FROM `test` . `v1` WHERE `b` > ? 2 -test 187a846fafe04b746eddaaab80b6a766 SELECT SCHEMA_NAME , `DIGEST` , `DIGEST_TEXT` , `COUNT_STAR` FROM `performance_schema` . `events_statements_summary_by_digest` ORDER BY `DIGEST_TEXT` 1 -test 0c87d86b62e664a81a23d4f176fbb377 SELECT `a` , `b` FROM `test` . `v1` 2 -test de7e6f1350ff14a952b97b373d76c1a4 SELECT `b` , `a` FROM `test` . `v1` 2 -test 3468091e6d6ce474aded20beaec36b53 TRUNCATE TABLE `performance_schema` . `events_statements_summary_by_digest` 1 +test c131cb28e0201dc6d2a8dccd7f2931ca CREATE VIEW `test` . `v1` AS SELECT * FROM `test` . `t1` 1 +test 06b54da71da538a63e29a5bd9f22f452 DROP TABLE `test` . `v1` 1 +test a8719799988e32ae905b4d7bfef416f4 EXPLAIN SELECT * FROM `test` . `v1` 2 +test e61737b03042bac0dd2c45043b6686ba EXPLAIN SELECT * FROM `test` . `v1` WHERE `a` = ? 2 +test 88ab58db610f85333438b44f73adf260 EXPLAIN SELECT * FROM `test` . `v1` WHERE `b` > ? 2 +test 06376e4a052b257959bd3c60cae74230 EXPLAIN SELECT `a` , `b` FROM `test` . `v1` 2 +test a4d7551ca1c2458912541a4a7c682732 EXPLAIN SELECT `b` , `a` FROM `test` . `v1` 2 +test 4c4af7b536b849c61e011ef5d029edf1 SELECT * FROM `test` . `v1` 2 +test b04bcdacfc4f8ab9b08a119c44fcbb5c SELECT * FROM `test` . `v1` WHERE `a` = ? 2 +test 1d5b863293884ae15e046ae8e2008304 SELECT * FROM `test` . `v1` WHERE `b` > ? 2 +test 78acef9adeb4b3e3fe8a64f8515a76fd SELECT SCHEMA_NAME , `DIGEST` , `DIGEST_TEXT` , `COUNT_STAR` FROM `performance_schema` . `events_statements_summary_by_digest` ORDER BY `DIGEST_TEXT` 1 +test 2f436c5c0ab6d7376c4586a6bd864580 SELECT `a` , `b` FROM `test` . `v1` 2 +test 125d6236e1ec60f9e46834b030bd8805 SELECT `b` , `a` FROM `test` . `v1` 2 +test 53dcc5b0f6bec99acc4336a294e337ac TRUNCATE TABLE `performance_schema` . `events_statements_summary_by_digest` 1 DROP VIEW test.v1; DROP TABLE test.t1; diff --git a/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.result b/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.result index e4e2c8b294a3f..499afef709f90 100644 --- a/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.result +++ b/mysql-test/suite/perfschema/r/start_server_low_digest_sql_length.result @@ -8,5 +8,5 @@ SELECT 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 #################################### SELECT event_name, digest, digest_text, sql_text FROM events_statements_history_long; event_name digest digest_text sql_text -statement/sql/select c9e142fe40c43498607ca5310e11d2ce SELECT ? + ? + SELECT ... -statement/sql/truncate 506e3496d92689cd2367329dc7725165 TRUNCATE TABLE truncat... +statement/sql/select 671245e6a1fc12e1fcef1c9955d783e3 SELECT ? + ? + SELECT ... +statement/sql/truncate 73163b1bf624059ddc4579dae105f649 TRUNCATE TABLE truncat... diff --git a/sql/item_func.cc b/sql/item_func.cc index 2b0bbbba70991..0347fe658e07a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -837,6 +837,77 @@ String *Item_int_func::val_str(String *str) } +bool Item_func_grouping::fix_fields(THD *thd, Item **ref) +{ + SELECT_LEX *curr_sel= thd->lex->current_select; + + if (Item_func::fix_fields(thd, ref)) + return true; + + // longlong is 64 bits, so we can represent a maximum of 64 arguments + if (arg_count > 64) + { + my_error(ER_TOO_MANY_ARGS, MYF(0), "GROUPING", arg_count, "64"); + return true; + } + + if (!curr_sel || !(thd->lex->allow_sum_func.is_set(curr_sel->nest_level))) + { + my_message(ER_INVALID_GROUP_FUNC_USE, + ER_THD(thd, ER_INVALID_GROUP_FUNC_USE), MYF(0)); + return TRUE; + } + + return false; +} + + +bool Item_func_grouping::resolve_args(THD *thd, ORDER *group_list) +{ + if (!(min_rollup_levels= thd->alloc(arg_count))) + { + return true; + } + + for (uint i= 0; i < arg_count; i++) + { + uint gp= 0; + ORDER *g; + for (g= group_list; g; g= g->next, gp++) + { + if (args[i]->real_item()->eq((*g->item)->real_item(), 0)) + break; + } + if (!g) + { + my_error(ER_FIELD_IN_GROUPING_NOT_GROUP_BY, MYF(0), + args[i]->full_name()); + return true; + } + min_rollup_levels[i]= gp; + } + + return false; +} + + +longlong Item_func_grouping::val_int() +{ + if (!min_rollup_levels) + return 0; + + longlong result= 0; + for (uint i= 0; i < arg_count; i++) + { + if (current_level <= min_rollup_levels[i]) + { + result|= 1ULL << (arg_count - i - 1); + } + } + return result; +} + + bool Item_func_connection_id::fix_length_and_dec(THD *thd) { if (Item_long_func::fix_length_and_dec(thd)) diff --git a/sql/item_func.h b/sql/item_func.h index cc0985c8d53b7..3860218a58156 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -109,7 +109,8 @@ class Item_func :public Item_func_or_sum JSON_EXTRACT_FUNC, JSON_VALID_FUNC, ROWNUM_FUNC, CASE_SEARCHED_FUNC, // Used by ColumnStore/Spider CASE_SIMPLE_FUNC, // Used by ColumnStore/spider, - DATE_FUNC, YEAR_FUNC, SUBSTR_FUNC, LEFT_FUNC + DATE_FUNC, YEAR_FUNC, SUBSTR_FUNC, LEFT_FUNC, + GROUPING_FUNC }; /* @@ -1331,6 +1332,45 @@ class Item_int_func :public Item_func }; +class Item_func_grouping final : public Item_int_func +{ + uint *min_rollup_levels; + uint current_level; + +public: + Item_func_grouping(THD *thd, List &args) + : Item_int_func(thd, args), min_rollup_levels(NULL), + current_level(UINT_MAX) + { + } + + bool fix_fields(THD *thd, Item **ref) override; + bool resolve_args(THD *thd, ORDER *group_list); + void update_used_tables() override + { + Item_func::update_used_tables(); + // GROUPING()'s value depends on the rollup level, + // and so it must never be treated as constant + const_item_cache= false; + } + void set_current_rollup_level(uint level) { current_level= level; } + longlong val_int() override; + const Type_handler *type_handler() const override + { return &type_handler_slonglong; } + enum Functype functype() const override { return GROUPING_FUNC; } + LEX_CSTRING func_name_cstring() const override + { + static LEX_CSTRING sum_name= {STRING_WITH_LEN("grouping") }; + return sum_name; + } + bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return false; } + +protected: + Item *shallow_copy(THD *thd) const override + { return get_item_copy(thd, this); } +}; + + class Item_long_func: public Item_int_func { public: diff --git a/sql/lex.h b/sql/lex.h index 61774df019f0d..f080eeaf0fb7e 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -274,6 +274,7 @@ SYMBOL symbols[] = { { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP_SYM)}, + { "GROUPING", SYM(GROUPING_SYM)}, { "HANDLER", SYM(HANDLER_SYM)}, { "HARD", SYM(HARD_SYM)}, { "HASH", SYM(HASH_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index d6436255da7d1..1f7e00440ae52 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12418,3 +12418,7 @@ ER_JSON_OPTIMIZER_REPLAY_CONTEXT_PARSE_FAILED eng "Failed to parse saved optimizer context: %s at offset %d." ER_JSON_OPTIMIZER_REPLAY_CONTEXT_MATCH_FAILED eng "Failed to match the stats from replay context with the optimizer stats: %s doesn't exist in %s" +ER_FIELD_IN_GROUPING_NOT_GROUP_BY 42000 + eng "Argument '%-.192s' of GROUPING function is not in GROUP BY" +ER_TOO_MANY_ARGS 42000 + eng "Too many arguments for function %s: %lu; maximum allowed is %s." diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6e1c6df4715b7..a6af118e57cf0 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3695,6 +3695,13 @@ bool st_select_lex::add_gorder_to_list(THD *thd, Item *item, bool asc) } +bool st_select_lex::add_grouping_func_to_list(THD *thd, + Item_func_grouping *func) +{ + return !func || grouping_func_list.push_back(func, thd->mem_root); +} + + bool st_select_lex::add_item_to_list(THD *thd, Item *item) { DBUG_ENTER("st_select_lex::add_item_to_list"); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5e0258ee42bf3..87483736468c1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1275,6 +1275,8 @@ class st_select_lex: public st_select_lex_node List save_many_values; List *save_insert_list; + List grouping_func_list; + enum_column_usage item_list_usage; bool is_item_list_lookup:1; /* @@ -1497,6 +1499,7 @@ class st_select_lex: public st_select_lex_node bool add_ftfunc_to_list(THD *thd, Item_func_match *func); bool add_order_to_list(THD *thd, Item *item, bool asc); bool add_gorder_to_list(THD *thd, Item *item, bool asc); + bool add_grouping_func_to_list(THD *thd, Item_func_grouping *func); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, const LEX_CSTRING *alias, ulong table_options, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index dc9e7b6113333..2efe1f15277e8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -850,10 +850,11 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) /* Remove GROUP BY if there are no aggregate functions and no HAVING - clause + clause and no GROUPING() functions */ if (subq_select_lex->group_list.elements && - !subq_select_lex->with_sum_func && !subq_select_lex->join->having) + !subq_select_lex->with_sum_func && !subq_select_lex->join->having && + subq_select_lex->grouping_func_list.is_empty()) { /* Temporary workaround for MDEV-28621: Do not remove GROUP BY expression @@ -1929,6 +1930,8 @@ bool JOIN::prepare_stage2() #endif if (select_lex->olap == ROLLUP_TYPE && rollup_init()) goto err; + if (rollup_setup_grouping_funcs()) + goto err; if (alloc_func_list() || make_sum_func_list(all_fields, fields_list, false)) goto err; @@ -5035,6 +5038,12 @@ int JOIN::exec_inner() if (zero_result_cause) { + /* + If zero results, WITH ROLLUP will still return a summary row for the + empty grouping set. Rollup level is set to 0 so that GROUPING() behaves + correctly. + */ + rollup_set_level(0); if (select_lex->have_window_funcs() && send_row_on_empty_set()) { /* @@ -17975,7 +17984,9 @@ return_zero_rows(JOIN *join, select_result *result, List *tables, { bool send_error= FALSE; if (send_row) + { send_error= result->send_data_with_check(*fields, join->unit, 0) > 0; + } if (likely(!send_error)) result->send_eof(); // Should be safe } @@ -22242,6 +22253,16 @@ TABLE *Create_tmp_table::start(THD *thd, } +/** + Return TRUE if 'item' is a GROUPING() function. +*/ +static inline bool is_grouping_func(const Item *item) +{ + return item->type() == Item::FUNC_ITEM && + ((Item_func *) item)->functype() == Item_func::GROUPING_FUNC; +} + + bool Create_tmp_table::add_fields(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, @@ -22297,7 +22318,8 @@ bool Create_tmp_table::add_fields(THD *thd, } if (not_all_columns) { - if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM && + !is_grouping_func(item)) { if (item->used_tables() & OUTER_REF_TABLE_BIT) item->update_used_tables(); @@ -30071,8 +30093,9 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, temporary table. */ enum Item::Type item_type= item->type(); - if ((item->with_sum_func() && item_type != Item::SUM_FUNC_ITEM) || - item->with_window_func()) + if (((item->with_sum_func() && item_type != Item::SUM_FUNC_ITEM && + !is_grouping_func(item)) || + item->with_window_func())) item_field= item; else if (item_type == Item::FIELD_ITEM || item_type == Item::DEFAULT_VALUE_ITEM) @@ -30566,7 +30589,8 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, arg != arg_end; arg++) { Item *item= *arg; - if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM) + bool matched= false; + if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM || item->type() == Item::FUNC_ITEM) { ORDER *group_tmp; for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) @@ -30581,10 +30605,12 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, return 1; // fatal_error is set thd->change_item_tree(arg, new_item); arg_changed= TRUE; + matched= true; + break; } } } - else if (item->type() == Item::FUNC_ITEM) + if (!matched && item->type() == Item::FUNC_ITEM) { if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed)) return 1; @@ -30873,6 +30899,33 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, return 0; } + +bool JOIN::rollup_setup_grouping_funcs() +{ + List_iterator it(select_lex->grouping_func_list); + Item_func_grouping *item; + while ((item= it++)) + { + if (item->resolve_args(thd, group_list)) + return true; + } + return false; +} + + +void JOIN::rollup_set_level(uint level) +{ + List_iterator it(select_lex->grouping_func_list); + Item_func_grouping *grouping; + while ((grouping= it++)) + { + grouping->set_current_rollup_level(level); + if (grouping->result_field) + grouping->save_in_result_field(1); + } +} + + /** Send all rollup levels higher than the current one to the client. @@ -30897,6 +30950,7 @@ int JOIN::rollup_send_data(uint idx) uint i; for (i= send_group_parts ; i-- > idx ; ) { + rollup_set_level(i); int res= 0; /* Get reference pointers to sum functions in place */ copy_ref_ptr_array(ref_ptrs, rollup.ref_pointer_arrays[i]); @@ -30910,6 +30964,7 @@ int JOIN::rollup_send_data(uint idx) send_records++; } } + rollup_set_level(send_group_parts); /* Restore ref_pointer_array */ set_items_ref_array(current_ref_ptrs); return 0; @@ -30941,6 +30996,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, uint i; for (i= send_group_parts ; i-- > idx ; ) { + rollup_set_level(i); /* Get reference pointers to sum functions in place */ copy_ref_ptr_array(ref_ptrs, rollup.ref_pointer_arrays[i]); if ((!having || having->val_bool())) @@ -30965,6 +31021,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, } } } + rollup_set_level(send_group_parts); /* Restore ref_pointer_array */ set_items_ref_array(current_ref_ptrs); return 0; diff --git a/sql/sql_select.h b/sql/sql_select.h index 23a927bfcb14e..7664deaa99ccb 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1812,7 +1812,6 @@ class JOIN :public Sql_alloc bool subq_exit_fl; ROLLUP rollup; ///< Used with rollup - bool mixed_implicit_grouping; bool select_distinct; ///< Set if SELECT DISTINCT /** @@ -2087,6 +2086,8 @@ class JOIN :public Sql_alloc Item_sum ***func); int rollup_send_data(uint idx); int rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param, TABLE *table); + bool rollup_setup_grouping_funcs(); + void rollup_set_level(uint level); void join_free(); /** Cleanup this JOIN, possibly for reuse */ void cleanup(bool full); @@ -2094,10 +2095,16 @@ class JOIN :public Sql_alloc void inline clear_sum_funcs(); 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 { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c2fe9974c42df..281cd76a14aee 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -571,6 +571,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token FULLTEXT_SYM %token GOTO_ORACLE_SYM /* Oracle-R */ %token GRANT /* SQL-2003-R */ +%token GROUPING_SYM %token GROUP_CONCAT_SYM %token JSON_ARRAYAGG_SYM %token JSON_OBJECTAGG_SYM @@ -1629,6 +1630,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_versioning_interval_start json_default_literal set_expr_misc + grouping_operation %type sql_statement_name @@ -10596,6 +10598,7 @@ column_default_non_parenthesized_expr: MYSQL_YYABORT; } } + | grouping_operation | window_func_expr { if (!Lex->select_stack_top) @@ -11692,6 +11695,17 @@ udf_expr: } ; +grouping_operation: + GROUPING_SYM '(' expr_list ')' + { + Item_func_grouping *i1= new (thd->mem_root) Item_func_grouping(thd, *$3); + if (unlikely(i1 == NULL)) + MYSQL_YYABORT; + Select->add_grouping_func_to_list(thd, i1); + $$= i1; + } + ; + sum_expr: AVG_SYM '(' in_sum_expr ')' { From f5e1b40d2d48f6713bc32daca4575f361bf0dc2d Mon Sep 17 00:00:00 2001 From: Jaeheon Shim Date: Thu, 27 Aug 2026 16:38:18 -0400 Subject: [PATCH 3/5] Add test that uses GROUPING with max number of arguments --- mysql-test/main/func_grouping.result | 5 ++++ mysql-test/main/func_grouping.test | 34 ++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/func_grouping.result b/mysql-test/main/func_grouping.result index 2a68dd498e152..40ff06c69acc2 100644 --- a/mysql-test/main/func_grouping.result +++ b/mysql-test/main/func_grouping.result @@ -566,4 +566,9 @@ FROM t0; e 1 DROP TABLE t0; +CREATE TABLE t0 ( i63 INTEGER, i62 INTEGER, i61 INTEGER, i60 INTEGER, i59 INTEGER, i58 INTEGER, i57 INTEGER, i56 INTEGER, i55 INTEGER, i54 INTEGER, i53 INTEGER, i52 INTEGER, i51 INTEGER, i50 INTEGER, i49 INTEGER, i48 INTEGER, i47 INTEGER, i46 INTEGER, i45 INTEGER, i44 INTEGER, i43 INTEGER, i42 INTEGER, i41 INTEGER, i40 INTEGER, i39 INTEGER, i38 INTEGER, i37 INTEGER, i36 INTEGER, i35 INTEGER, i34 INTEGER, i33 INTEGER, i32 INTEGER, i31 INTEGER, i30 INTEGER, i29 INTEGER, i28 INTEGER, i27 INTEGER, i26 INTEGER, i25 INTEGER, i24 INTEGER, i23 INTEGER, i22 INTEGER, i21 INTEGER, i20 INTEGER, i19 INTEGER, i18 INTEGER, i17 INTEGER, i16 INTEGER, i15 INTEGER, i14 INTEGER, i13 INTEGER, i12 INTEGER, i11 INTEGER, i10 INTEGER, i9 INTEGER, i8 INTEGER, i7 INTEGER, i6 INTEGER, i5 INTEGER, i4 INTEGER, i3 INTEGER, i2 INTEGER, i1 INTEGER, i64 INTEGER); +SELECT GROUPING( i63, i62, i61, i60, i59, i58, i57, i56, i55, i54, i53, i52, i51, i50, i49, i48, i47, i46, i45, i44, i43, i42, i41, i40, i39, i38, i37, i36, i35, i34, i33, i32, i31, i30, i29, i28, i27, i26, i25, i24, i23, i22, i21, i20, i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6, i5, i4, i3, i2, i1, i64) FROM t0 GROUP BY i63, i62, i61, i60, i59, i58, i57, i56, i55, i54, i53, i52, i51, i50, i49, i48, i47, i46, i45, i44, i43, i42, i41, i40, i39, i38, i37, i36, i35, i34, i33, i32, i31, i30, i29, i28, i27, i26, i25, i24, i23, i22, i21, i20, i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6, i5, i4, i3, i2, i1, i64 WITH ROLLUP; +GROUPING( i63, i62, i61, i60, i59, i58, i57, i56, i55, i54, i53, i52, i51, i50, i49, i48, i47, i46, i45, i44, i43, i42, i41, i40, i39, i38, i37, i36, i35, i34, i33, i32, i31, i30, i29, i28, i27, i26, i25, i24, i23, i22, i21, i20, i19, i18, i17, i16, i15, +-1 +DROP TABLE t0; # End of 13.1 tests. diff --git a/mysql-test/main/func_grouping.test b/mysql-test/main/func_grouping.test index be7e26c9e3d00..a8db2d91c79e8 100644 --- a/mysql-test/main/func_grouping.test +++ b/mysql-test/main/func_grouping.test @@ -17,8 +17,6 @@ --echo # MDEV-22269: GROUPING function --echo # ---source include/have_innodb.inc - --disable_warnings DROP TABLE IF EXISTS t0,t1,t2,t,t3; DROP VIEW IF EXISTS v; @@ -342,4 +340,36 @@ SELECT EXISTS (SELECT t0.x FROM t0 a WHERE 1=0 GROUP BY a.x WITH ROLLUP) AS e FROM t0; DROP TABLE t0; +# Check GROUPING works with 64 arguments +let $query1= CREATE TABLE t0 (; +let $col_cnt=63; +while ($col_cnt) +{ + let $query1= $query1 i$col_cnt INTEGER,; + dec $col_cnt; +} + +let $query1= $query1 i64 INTEGER); +eval $query1; + +let $query= SELECT GROUPING(; +let col_cnt=63; +while ($col_cnt) +{ +let $query= $query i$col_cnt,; +dec $col_cnt; +} +let $query= $query i64) FROM t0 GROUP BY ; +let col_cnt=63; +while ($col_cnt) +{ +let $query= $query i$col_cnt,; +dec $col_cnt; +} +let $query= $query i64 WITH ROLLUP; + +eval $query; +DROP TABLE t0; + + --echo # End of 13.1 tests. From 14d4b56e6660f4aa6c3ed948004cbadd13a1aea8 Mon Sep 17 00:00:00 2001 From: Jaeheon Shim Date: Thu, 27 Aug 2026 16:40:00 -0400 Subject: [PATCH 4/5] Fix ER_TOO_MANY_ARGS --- sql/item_func.cc | 2 +- sql/share/errmsg-utf8.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 0347fe658e07a..3e794c9938f3b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -847,7 +847,7 @@ bool Item_func_grouping::fix_fields(THD *thd, Item **ref) // longlong is 64 bits, so we can represent a maximum of 64 arguments if (arg_count > 64) { - my_error(ER_TOO_MANY_ARGS, MYF(0), "GROUPING", arg_count, "64"); + my_error(ER_TOO_MANY_ARGS, MYF(0), "GROUPING", arg_count, 64u); return true; } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 1f7e00440ae52..38a39fa838ed9 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12421,4 +12421,4 @@ ER_JSON_OPTIMIZER_REPLAY_CONTEXT_MATCH_FAILED ER_FIELD_IN_GROUPING_NOT_GROUP_BY 42000 eng "Argument '%-.192s' of GROUPING function is not in GROUP BY" ER_TOO_MANY_ARGS 42000 - eng "Too many arguments for function %s: %lu; maximum allowed is %s." + eng "Too many arguments for function %s: %u; maximum allowed is %u." From e9a75eb6d134395bb66eab30674de0d0a89a43dd Mon Sep 17 00:00:00 2001 From: Jaeheon Shim Date: Fri, 28 Aug 2026 16:26:51 -0400 Subject: [PATCH 5/5] Replaced min_rollup_levels check in val_int with a dbug_assert --- sql/item_func.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 3e794c9938f3b..d054f804866c1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -893,8 +893,7 @@ bool Item_func_grouping::resolve_args(THD *thd, ORDER *group_list) longlong Item_func_grouping::val_int() { - if (!min_rollup_levels) - return 0; + DBUG_ASSERT(min_rollup_levels); longlong result= 0; for (uint i= 0; i < arg_count; i++)