mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-11-14 23:06:59 +00:00
fix(promql): let a too-deep tree fall back instead of failing the query
The depth limit was reported as `DataFusionError::Internal`, the error a compiler defect gets. The planner only keeps the legacy plan on `NotImplemented`, so enabling the native route turned an answer into an error: a statement compiling to more than 64 nodes -- 70 `time()` terms compile to 139 -- failed outright, where the legacy planner answers it. Switching a feature flag on must never make a query stop working. The two rejections now say what they mean. Exceeding the depth limit is "this statement is beyond what this route handles", which is `NotImplemented` and makes the planner fall back, from both the constructor and the deserializer. Every other rejection in `validate()` -- a mismatched binding, a map over a scalar, a window with the wrong grid -- stays `Internal`, because those mean the compiler built something inconsistent and reclassifying them would hide real defects as unsupported queries. A fallback test pins it: 70 `time()` terms must plan exactly as the legacy route does, with the node count in the message so a future change to the cap explains itself. `postcard` moves into the external-dependencies block. It is declared with `default-features = false`, and that block exists precisely for inherited dependencies whose features are narrowed. Signed-off-by: discord9 <discord9@163.com>
This commit is contained in:
@@ -98,11 +98,11 @@ fn ordinary_encodable_plan_keeps_in_process_encodability_gate() {
|
||||
|
||||
let in_process_rewriter = PlanRewriter::new(&plan, true);
|
||||
assert!(in_process_rewriter.whole_plan_encodable);
|
||||
assert!(!in_process_rewriter.skip_encodability_gate);
|
||||
assert!(!in_process_rewriter.skip_in_process_encodability);
|
||||
|
||||
let wire_rewriter = PlanRewriter::new(&plan, false);
|
||||
assert!(wire_rewriter.whole_plan_encodable);
|
||||
assert!(!wire_rewriter.skip_encodability_gate);
|
||||
assert!(!wire_rewriter.skip_in_process_encodability);
|
||||
}
|
||||
|
||||
struct MergeScanRemoteDynFilterProducerIdCollector<'a> {
|
||||
|
||||
@@ -1012,7 +1012,7 @@ mod tests {
|
||||
.as_any()
|
||||
.downcast_ref::<AggregateFinalize>()
|
||||
.unwrap();
|
||||
let inputs = finalize.inputs();
|
||||
let inputs = datafusion_expr::UserDefinedLogicalNodeCore::inputs(finalize);
|
||||
let [producer] = inputs.as_slice() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
@@ -2596,6 +2596,25 @@ async fn native_fused_whole_vector_operation_falls_back() {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn native_fused_depth_limit_falls_back_to_legacy_plan() {
|
||||
let query = std::iter::repeat_n("time()", 70)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" + ");
|
||||
let native = build_native_fused_plan(&query, true).await;
|
||||
let legacy = build_native_fused_plan(&query, false).await;
|
||||
let display = native.display_indent().to_string();
|
||||
assert!(
|
||||
!display.contains("FusedSeries"),
|
||||
"70 time() terms compile to 139 native nodes, exceeding the 64-node cap: {display}"
|
||||
);
|
||||
assert_eq!(
|
||||
display,
|
||||
legacy.display_indent().to_string(),
|
||||
"139 native nodes exceed the 64-node cap, so planning must preserve the legacy plan"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn native_fused_unsupported_shape_falls_back() {
|
||||
for query in [
|
||||
|
||||
Reference in New Issue
Block a user