parseGroupByClause parses "GROUP BY [, ...]" including ROLLUP, CUBE, GROUPING SETS, and MySQL's trailing WITH ROLLUP / WITH CUBE syntax. Returns nil slice (no error) when GROUP BY is absent.
()
| 449 | // GROUPING SETS, and MySQL's trailing WITH ROLLUP / WITH CUBE syntax. |
| 450 | // Returns nil slice (no error) when GROUP BY is absent. |
| 451 | func (p *Parser) parseGroupByClause() ([]ast.Expression, error) { |
| 452 | if !p.isType(models.TokenTypeGroup) { |
| 453 | return nil, nil |
| 454 | } |
| 455 | p.advance() // Consume GROUP |
| 456 | |
| 457 | if !p.isType(models.TokenTypeBy) { |
| 458 | return nil, p.expectedError("BY after GROUP") |
| 459 | } |
| 460 | p.advance() // Consume BY |
| 461 | |
| 462 | groupByExprs := make([]ast.Expression, 0, 4) |
| 463 | for { |
| 464 | var ( |
| 465 | expr ast.Expression |
| 466 | err error |
| 467 | ) |
| 468 | |
| 469 | switch { |
| 470 | case p.isType(models.TokenTypeRollup): |
| 471 | expr, err = p.parseRollup() |
| 472 | case p.isType(models.TokenTypeCube): |
| 473 | expr, err = p.parseCube() |
| 474 | case p.currentToken.Token.Value == "GROUPING SETS" || |
| 475 | (p.isType(models.TokenTypeGrouping) && strings.EqualFold(p.peekToken().Token.Value, "SETS")): |
| 476 | expr, err = p.parseGroupingSets() |
| 477 | default: |
| 478 | expr, err = p.parseExpression() |
| 479 | } |
| 480 | |
| 481 | if err != nil { |
| 482 | return nil, err |
| 483 | } |
| 484 | groupByExprs = append(groupByExprs, expr) |
| 485 | |
| 486 | if !p.isType(models.TokenTypeComma) { |
| 487 | break |
| 488 | } |
| 489 | p.advance() |
| 490 | } |
| 491 | |
| 492 | // MySQL / ClickHouse: GROUP BY col1 WITH ROLLUP / WITH CUBE / WITH TOTALS |
| 493 | if p.isType(models.TokenTypeWith) { |
| 494 | switch strings.ToUpper(p.peekToken().Token.Value) { |
| 495 | case "ROLLUP": |
| 496 | p.advance() // Consume WITH |
| 497 | p.advance() // Consume ROLLUP |
| 498 | groupByExprs = []ast.Expression{&ast.RollupExpression{Expressions: groupByExprs}} |
| 499 | case "CUBE": |
| 500 | p.advance() // Consume WITH |
| 501 | p.advance() // Consume CUBE |
| 502 | groupByExprs = []ast.Expression{&ast.CubeExpression{Expressions: groupByExprs}} |
| 503 | case "TOTALS": |
| 504 | // ClickHouse WITH TOTALS: adds a summary row with aggregate totals. |
| 505 | // Consumed but not modeled on the AST (follow-up). |
| 506 | p.advance() // Consume WITH |
| 507 | p.advance() // Consume TOTALS |
| 508 | } |
no test coverage detected