{"record":{"id":"d2c4a27ef12a92d2","repo":"databendlabs/databend","slug":"grouping-function-must-be-rewritten-in-type-checke","errorCode":null,"errorMessage":"grouping function must be rewritten in type_checker, but got: {:?}","messagePattern":"grouping function must be rewritten in type_checker, but got: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/functions/src/scalars/other.rs","lineNumber":433,"sourceCode":"                derive_stat: None,\n            },\n        }))\n    }));\n    registry.register_function_factory(\"grouping\", grouping);\n\n    // dummy grouping\n    // used in type_check before AggregateRewriter\n    let dummy_grouping = FunctionFactory::Closure(Box::new(|_, arg_type: &[DataType]| {\n        Some(Arc::new(Function {\n            signature: FunctionSignature {\n                name: \"grouping\".to_string(),\n                args_type: vec![DataType::Generic(0); arg_type.len()],\n                return_type: DataType::Number(NumberDataType::UInt32),\n            },\n            eval: FunctionEval::Scalar {\n                calc_domain: Box::new(FunctionDomain::Full),\n                eval: scalar_evaluator(move |args, _| {\n                    unreachable!(\n                        \"grouping function must be rewritten in type_checker, but got: {:?}\",\n                        args\n                    )\n                }),\n                derive_stat: None,\n            },\n        }))\n    }));\n    registry.register_function_factory(\"grouping\", dummy_grouping);\n}\n\nfn register_num_to_char(registry: &mut FunctionRegistry) {\n    registry.register_aliases(\"to_string\", &[\"to_char\"]);\n    registry.register_passthrough_nullable_2_arg::<Int64Type, StringType, StringType, _, _>(\n        \"to_string\",\n        |_, _, _| FunctionDomain::MayThrow,\n        vectorize_with_builder_2_arg::<Int64Type, StringType, StringType>(\n            |value, fmt, builder, ctx| {","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/functions/src/scalars/other.rs#L415-L451","documentation":"The `grouping` function is registered with a placeholder scalar evaluator in src/query/functions/src/scalars/other.rs:433 that must never run: the query pipeline is required to rewrite GROUPING(...) during type checking into an expression over the GROUPING ID bitmap. Reaching this evaluator means that rewrite was skipped, so the engine panics with the evaluated args for diagnostics.","triggerScenarios":"A GROUPING(...) call bypasses type_checker rewriting — e.g. executed via an execution path that skips the rewrite pass, a cached/externally-built plan, or direct invocation of the registered scalar evaluator in tests or extensions.","commonSituations":"Custom planners or external plan builders that construct GROUPING function expressions without running the type_checker rewrite; regression after refactoring the rewrite pass; executing raw function calls through lower-level APIs (e.g. extensions or embedded use of the function registry).","solutions":["Verify the query plan goes through the type_checker pass that rewrites GROUPING before execution.","If building plans programmatically, apply the same rewrite pass the normal pipeline applies before calling the evaluator.","Replace the placeholder evaluator with a real scalar implementation if GROUPING must be evaluable at scalar level.","Report the query shape (exact SQL and plan) as a bug — this path is unreachable in normal execution."],"exampleFix":"// before\nscalar_evaluator(move |args, _| {\n    unreachable!(\"grouping function must be rewritten in type_checker, but got: {:?}\", args)\n})\n// after\nscalar_evaluator(move |args, _| {\n    let ids = args[0].as_number_u32().ok_or_else(||\n        ErrorCode::BadArguments(\"grouping requires rewritten UInt32 grouping-id argument\".into()))?;\n    Ok(Value::UInt32(compute_grouping_from_ids(ids)))\n})","handlingStrategy":"validation","validationCode":"// Before execution, confirm the plan had GROUPING rewritten:\nfn assert_grouping_rewritten(plan: &Plan) -> Result<(), String> {\n    if plan_contains_unrewritten_grouping(plan) {\n        Err(\"GROUPING function was not rewritten in type_checker\".into())\n    } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":"// Wrap plan execution to detect the invariant break:\nmatch std::panic::catch_unwind(|| execute(plan.clone())) {\n    Ok(r) => r,\n    Err(e) => return Err(ErrorCode::Internal(\n        format!(\"plan execution invariant violated: {:?}\", e))),\n}","preventionTips":["Never bypass type_checker when building or replaying plans programmatically.","Do not cache plans across versions where the rewrite pass changed.","Treat this panic as a bug report trigger: capture the SQL and plan tree."],"tags":["sql-functions","rust","panic","grouping","query-planning"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}