Recursively collect `GROUPING(col)` calls from an expression.
(
expr: &ast::Expr,
alias: &str,
canonical_keys: &[SqlExpr],
out: &mut Vec<AggregateExpr>,
)
| 287 | |
| 288 | /// Recursively collect `GROUPING(col)` calls from an expression. |
| 289 | fn collect_grouping_from_expr( |
| 290 | expr: &ast::Expr, |
| 291 | alias: &str, |
| 292 | canonical_keys: &[SqlExpr], |
| 293 | out: &mut Vec<AggregateExpr>, |
| 294 | ) -> Result<()> { |
| 295 | match expr { |
| 296 | ast::Expr::Function(f) => { |
| 297 | let name = normalize_function_name(f); |
| 298 | if name.eq_ignore_ascii_case("grouping") { |
| 299 | // Extract the column argument(s). |
| 300 | let args = function_args_exprs(f); |
| 301 | for col_expr in &args { |
| 302 | let canonical_idx = crate::planner::grouping_sets::resolve_grouping_col( |
| 303 | col_expr, |
| 304 | canonical_keys, |
| 305 | )?; |
| 306 | // Encode index in the field name; alias is user-visible output name. |
| 307 | out.push(AggregateExpr { |
| 308 | function: "grouping".into(), |
| 309 | args: vec![convert_expr(col_expr)?], |
| 310 | alias: alias.to_string(), |
| 311 | distinct: false, |
| 312 | grouping_col_index: Some(canonical_idx), |
| 313 | }); |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | // Recurse into binary ops and other wrappers. |
| 318 | ast::Expr::BinaryOp { left, right, .. } => { |
| 319 | collect_grouping_from_expr(left, alias, canonical_keys, out)?; |
| 320 | collect_grouping_from_expr(right, alias, canonical_keys, out)?; |
| 321 | } |
| 322 | _ => {} |
| 323 | } |
| 324 | Ok(()) |
| 325 | } |
| 326 | |
| 327 | /// Extract the positional expression arguments from a function call. |
| 328 | fn function_args_exprs(f: &ast::Function) -> Vec<&ast::Expr> { |
no test coverage detected