From f1acc0606f868132729314ca0b3efcb4151d79e5 Mon Sep 17 00:00:00 2001 From: discord9 Date: Tue, 22 Sep 2026 20:51:55 +0800 Subject: [PATCH] fix(flow): qualify recovery source tables before serialization Signed-off-by: discord9 --- src/flow/src/batching_mode/task.rs | 22 ++++++++++++++++++++-- src/flow/src/batching_mode/task/test.rs | 9 ++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/flow/src/batching_mode/task.rs b/src/flow/src/batching_mode/task.rs index e2b903d6b9c..40020f639c1 100644 --- a/src/flow/src/batching_mode/task.rs +++ b/src/flow/src/batching_mode/task.rs @@ -803,6 +803,26 @@ impl BatchingTask { context: "Failed to project recovery source timestamps".to_string(), })?, ); + let catalog = &self.config.sink_table_name[0]; + let schema = &self.config.sink_table_name[1]; + let timestamp_plan = timestamp_plan + .clone() + .transform_down_with_subqueries(|p| { + if let LogicalPlan::TableScan(mut table_scan) = p { + let resolved = table_scan.table_name.resolve(catalog, schema); + table_scan.table_name = resolved.into(); + Ok(Transformed::yes(LogicalPlan::TableScan(table_scan))) + } else { + Ok(Transformed::no(p)) + } + }) + .with_context(|_| DatafusionSnafu { + context: format!( + "Failed to fix table ref in recovery timestamp plan, plan={:?}", + timestamp_plan + ), + })? + .data; let message = DFLogicalSubstraitConvertor {} .encode(×tamp_plan, DefaultSerializer) .context(SubstraitEncodeLogicalPlanSnafu)?; @@ -820,8 +840,6 @@ impl BatchingTask { (FLOW_INCREMENTAL_MODE, FLOW_INCREMENTAL_MODE_SEQUENCE_RANGE), (FLOW_INCREMENTAL_AFTER_SEQS, lower_json.as_str()), ]; - let catalog = &self.config.sink_table_name[0]; - let schema = &self.config.sink_table_name[1]; let mut peer_desc = None; let result = frontend_client .query_with_terminal_metrics( diff --git a/src/flow/src/batching_mode/task/test.rs b/src/flow/src/batching_mode/task/test.rs index 3ec8ac8bae6..29a15600f15 100644 --- a/src/flow/src/batching_mode/task/test.rs +++ b/src/flow/src/batching_mode/task/test.rs @@ -1386,7 +1386,14 @@ fn assert_recovery_timestamp_plan(plan: &Plan, expire_after: Option) -> Opt &mut has_number_filter, &mut expiry_lower, ); - assert_eq!(scans, vec![vec!["numbers_with_ts".to_string()]]); + assert_eq!( + scans, + vec![vec![ + DEFAULT_CATALOG_NAME.to_string(), + DEFAULT_SCHEMA_NAME.to_string(), + "numbers_with_ts".to_string(), + ]] + ); assert!(has_number_filter, "recovery capture lost WHERE number = 42"); assert_eq!(expiry_lower.is_some(), expire_after.is_some()); expiry_lower