Expand the GROUP BY clause if it contains ROLLUP/CUBE/GROUPING SETS. Returns `None` when the GROUP BY is a plain expression list with no extensions — callers fall back to the existing single-set path.
(group_by: &GroupByExpr)
| 34 | /// Returns `None` when the GROUP BY is a plain expression list with no |
| 35 | /// extensions — callers fall back to the existing single-set path. |
| 36 | pub fn expand_group_by(group_by: &GroupByExpr) -> Result<Option<GroupingSetsExpansion>> { |
| 37 | let exprs = match group_by { |
| 38 | GroupByExpr::All(_) => return Ok(None), |
| 39 | GroupByExpr::Expressions(exprs, _) => exprs, |
| 40 | }; |
| 41 | |
| 42 | // Check whether any expression is ROLLUP / CUBE / GROUPING SETS. |
| 43 | let has_extension = exprs.iter().any(is_grouping_extension); |
| 44 | if !has_extension { |
| 45 | return Ok(None); |
| 46 | } |
| 47 | |
| 48 | // Split into plain columns and the single extension expression. |
| 49 | // SQL standard: only one extension per GROUP BY; mixed is allowed but |
| 50 | // forms a cross-product with the plain columns. |
| 51 | let mut plain_ast: Vec<&ast::Expr> = Vec::new(); |
| 52 | let mut extension_sets: Option<Vec<Vec<&ast::Expr>>> = None; |
| 53 | |
| 54 | for expr in exprs { |
| 55 | match expr { |
| 56 | ast::Expr::Rollup(groups) => { |
| 57 | if extension_sets.is_some() { |
| 58 | return Err(SqlError::Unsupported { |
| 59 | detail: "only one ROLLUP/CUBE/GROUPING SETS per GROUP BY is supported" |
| 60 | .into(), |
| 61 | }); |
| 62 | } |
| 63 | extension_sets = Some(expand_rollup(groups)); |
| 64 | } |
| 65 | ast::Expr::Cube(groups) => { |
| 66 | if extension_sets.is_some() { |
| 67 | return Err(SqlError::Unsupported { |
| 68 | detail: "only one ROLLUP/CUBE/GROUPING SETS per GROUP BY is supported" |
| 69 | .into(), |
| 70 | }); |
| 71 | } |
| 72 | extension_sets = Some(expand_cube(groups)); |
| 73 | } |
| 74 | ast::Expr::GroupingSets(sets) => { |
| 75 | if extension_sets.is_some() { |
| 76 | return Err(SqlError::Unsupported { |
| 77 | detail: "only one ROLLUP/CUBE/GROUPING SETS per GROUP BY is supported" |
| 78 | .into(), |
| 79 | }); |
| 80 | } |
| 81 | // GroupingSets: each inner Vec<Expr> is one set. |
| 82 | extension_sets = Some(sets.iter().map(|s| s.iter().collect()).collect()); |
| 83 | } |
| 84 | other => { |
| 85 | plain_ast.push(other); |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | let ext_sets = extension_sets.unwrap_or_default(); |
| 91 | |
| 92 | // Build canonical key list: plain columns first, then extension columns |
| 93 | // (deduped by display name so identical columns share an index). |