@@ -1137,6 +1137,152 @@ func (p *Parser) parseNullsClause() (*bool, error) {
11371137 return nil , nil
11381138}
11391139
1140+ // parseGroupingExpressionList parses a parenthesized, comma-separated list of expressions
1141+ // used by ROLLUP and CUBE. Returns error if the list is empty.
1142+ func (p * Parser ) parseGroupingExpressionList (keyword string ) ([]ast.Expression , error ) {
1143+ if p .currentToken .Type != "(" {
1144+ return nil , p .expectedError ("( after " + keyword )
1145+ }
1146+ p .advance () // Consume (
1147+
1148+ // Check for empty list - not allowed for ROLLUP/CUBE
1149+ if p .currentToken .Type == ")" {
1150+ return nil , fmt .Errorf ("parsing failed: %s requires at least one expression" , keyword )
1151+ }
1152+
1153+ // Parse comma-separated expressions
1154+ expressions := make ([]ast.Expression , 0 )
1155+ for {
1156+ expr , err := p .parseExpression ()
1157+ if err != nil {
1158+ return nil , err
1159+ }
1160+ expressions = append (expressions , expr )
1161+
1162+ // Check for comma (more expressions) or closing paren
1163+ if p .currentToken .Type == ")" {
1164+ break
1165+ }
1166+ if p .currentToken .Type != "," {
1167+ return nil , p .expectedError (", or ) in " + keyword )
1168+ }
1169+ p .advance () // Consume comma
1170+ }
1171+ p .advance () // Consume )
1172+
1173+ return expressions , nil
1174+ }
1175+
1176+ // parseRollup parses ROLLUP(col1, col2, ...) in GROUP BY clause
1177+ // ROLLUP generates hierarchical grouping sets from right to left
1178+ // Example: ROLLUP(a, b, c) generates: (a, b, c), (a, b), (a), ()
1179+ func (p * Parser ) parseRollup () (* ast.RollupExpression , error ) {
1180+ p .advance () // Consume ROLLUP
1181+
1182+ expressions , err := p .parseGroupingExpressionList ("ROLLUP" )
1183+ if err != nil {
1184+ return nil , err
1185+ }
1186+
1187+ return & ast.RollupExpression {
1188+ Expressions : expressions ,
1189+ }, nil
1190+ }
1191+
1192+ // parseCube parses CUBE(col1, col2, ...) in GROUP BY clause
1193+ // CUBE generates all possible combinations of grouping sets
1194+ // Example: CUBE(a, b) generates: (a, b), (a), (b), ()
1195+ func (p * Parser ) parseCube () (* ast.CubeExpression , error ) {
1196+ p .advance () // Consume CUBE
1197+
1198+ expressions , err := p .parseGroupingExpressionList ("CUBE" )
1199+ if err != nil {
1200+ return nil , err
1201+ }
1202+
1203+ return & ast.CubeExpression {
1204+ Expressions : expressions ,
1205+ }, nil
1206+ }
1207+
1208+ // parseGroupingSets parses GROUPING SETS(...) in GROUP BY clause
1209+ // Allows explicit specification of grouping sets
1210+ // Example: GROUPING SETS((a, b), (a), ()) generates exactly those three grouping sets
1211+ func (p * Parser ) parseGroupingSets () (* ast.GroupingSetsExpression , error ) {
1212+ // Handle both "GROUPING SETS" as compound keyword or separate tokens
1213+ if p .currentToken .Literal == "GROUPING SETS" {
1214+ p .advance () // Consume "GROUPING SETS" compound token
1215+ } else if p .currentToken .Type == "GROUPING" {
1216+ p .advance () // Consume GROUPING
1217+ if p .currentToken .Type != "SETS" {
1218+ return nil , p .expectedError ("SETS after GROUPING" )
1219+ }
1220+ p .advance () // Consume SETS
1221+ }
1222+
1223+ if p .currentToken .Type != "(" {
1224+ return nil , p .expectedError ("( after GROUPING SETS" )
1225+ }
1226+ p .advance () // Consume (
1227+
1228+ // Parse comma-separated grouping sets
1229+ sets := make ([][]ast.Expression , 0 )
1230+ for {
1231+ // Each set is either:
1232+ // 1. A parenthesized list: (col1, col2)
1233+ // 2. An empty set: ()
1234+ // 3. A single column without parens: col1 (treated as (col1))
1235+
1236+ var set []ast.Expression
1237+ if p .currentToken .Type == "(" {
1238+ p .advance () // Consume (
1239+ // Parse expressions in this set
1240+ set = make ([]ast.Expression , 0 )
1241+ // Handle empty set: ()
1242+ if p .currentToken .Type != ")" {
1243+ for {
1244+ expr , err := p .parseExpression ()
1245+ if err != nil {
1246+ return nil , err
1247+ }
1248+ set = append (set , expr )
1249+
1250+ if p .currentToken .Type == ")" {
1251+ break
1252+ }
1253+ if p .currentToken .Type != "," {
1254+ return nil , p .expectedError (", or ) in grouping set" )
1255+ }
1256+ p .advance () // Consume comma
1257+ }
1258+ }
1259+ p .advance () // Consume )
1260+ } else {
1261+ // Single column without parens
1262+ expr , err := p .parseExpression ()
1263+ if err != nil {
1264+ return nil , err
1265+ }
1266+ set = []ast.Expression {expr }
1267+ }
1268+ sets = append (sets , set )
1269+
1270+ // Check for comma (more sets) or closing paren
1271+ if p .currentToken .Type == ")" {
1272+ break
1273+ }
1274+ if p .currentToken .Type != "," {
1275+ return nil , p .expectedError (", or ) in GROUPING SETS" )
1276+ }
1277+ p .advance () // Consume comma
1278+ }
1279+ p .advance () // Consume )
1280+
1281+ return & ast.GroupingSetsExpression {
1282+ Sets : sets ,
1283+ }, nil
1284+ }
1285+
11401286// parseColumnDef parses a column definition
11411287func (p * Parser ) parseColumnDef () (* ast.ColumnDef , error ) {
11421288 name := p .parseIdent ()
@@ -1439,9 +1585,25 @@ func (p *Parser) parseSelectStatement() (ast.Statement, error) {
14391585 p .advance () // Consume BY
14401586
14411587 // Parse GROUP BY expressions (comma-separated list)
1588+ // Supports: regular expressions, ROLLUP, CUBE, GROUPING SETS
14421589 groupByExprs := make ([]ast.Expression , 0 )
14431590 for {
1444- expr , err := p .parseExpression ()
1591+ var expr ast.Expression
1592+ var err error
1593+
1594+ // Check for grouping operations: ROLLUP, CUBE, GROUPING SETS
1595+ // Note: GROUPING SETS may come as a compound keyword or separate tokens
1596+ if p .currentToken .Type == "ROLLUP" {
1597+ expr , err = p .parseRollup ()
1598+ } else if p .currentToken .Type == "CUBE" {
1599+ expr , err = p .parseCube ()
1600+ } else if p .currentToken .Literal == "GROUPING SETS" ||
1601+ (p .currentToken .Type == "GROUPING" && p .peekToken ().Type == "SETS" ) {
1602+ expr , err = p .parseGroupingSets ()
1603+ } else {
1604+ expr , err = p .parseExpression ()
1605+ }
1606+
14451607 if err != nil {
14461608 return nil , err
14471609 }
0 commit comments