1use std::collections::{BTreeMap, BTreeSet, HashSet};
16use std::sync::Arc;
17
18use common_telemetry::debug;
19use datafusion::config::{ConfigExtension, ExtensionOptions};
20use datafusion::datasource::DefaultTableSource;
21use datafusion::error::Result as DfResult;
22use datafusion_common::Column;
23use datafusion_common::config::ConfigOptions;
24use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRewriter};
25use datafusion_expr::expr::{Exists, InSubquery};
26use datafusion_expr::utils::expr_to_columns;
27use datafusion_expr::{Expr, LogicalPlan, LogicalPlanBuilder, Subquery, col as col_fn};
28use datafusion_optimizer::analyzer::AnalyzerRule;
29use datafusion_optimizer::decorrelate_lateral_join::DecorrelateLateralJoin;
30use datafusion_optimizer::decorrelate_predicate_subquery::DecorrelatePredicateSubquery;
31use datafusion_optimizer::eliminate_filter::EliminateFilter;
32use datafusion_optimizer::extract_equijoin_predicate::ExtractEquijoinPredicate;
33use datafusion_optimizer::filter_null_join_keys::FilterNullJoinKeys;
34use datafusion_optimizer::optimizer::Optimizer;
35use datafusion_optimizer::propagate_empty_relation::PropagateEmptyRelation;
36use datafusion_optimizer::push_down_filter::PushDownFilter;
37use datafusion_optimizer::rewrite_set_comparison::RewriteSetComparison;
38use datafusion_optimizer::scalar_subquery_to_join::ScalarSubqueryToJoin;
39use datafusion_optimizer::simplify_expressions::SimplifyExpressions;
40use promql::extension_plan::SeriesDivide;
41use substrait::{DFLogicalSubstraitConvertor, SubstraitPlan};
42use table::metadata::TableType;
43use table::table::adapter::DfTableProviderAdapter;
44
45use crate::dist_plan::RemoteDynFilterProducerId;
46use crate::dist_plan::analyzer::utils::{
47 PatchOptimizerContext, PlanTreeExpressionSimplifier, aliased_columns_for,
48 rewrite_merge_sort_exprs,
49};
50use crate::dist_plan::commutativity::{
51 Categorizer, Commutativity, partial_commutative_transformer,
52};
53use crate::dist_plan::merge_scan::MergeScanLogicalPlan;
54use crate::dist_plan::merge_sort::MergeSortLogicalPlan;
55use crate::metrics::PUSH_DOWN_FALLBACK_ERRORS_TOTAL;
56use crate::options::ScheduledTimeExtension;
57use crate::plan::ExtractExpr;
58use crate::query_engine::DefaultSerializer;
59
60#[cfg(test)]
61mod test;
62
63mod fallback;
64pub(crate) mod utils;
65
66pub(crate) use utils::AliasMapping;
67
68const OTHER_PHY_PART_COL_PLACEHOLDER: &str = "__OTHER_PHYSICAL_PART_COLS_PLACEHOLDER__";
70
71#[derive(Debug, Clone)]
72pub struct DistPlannerOptions {
73 pub allow_query_fallback: bool,
74}
75
76impl ConfigExtension for DistPlannerOptions {
77 const PREFIX: &'static str = "dist_planner";
78}
79
80impl ExtensionOptions for DistPlannerOptions {
81 fn as_any(&self) -> &dyn std::any::Any {
82 self
83 }
84
85 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
86 self
87 }
88
89 fn cloned(&self) -> Box<dyn ExtensionOptions> {
90 Box::new(self.clone())
91 }
92
93 fn set(&mut self, key: &str, value: &str) -> DfResult<()> {
94 Err(datafusion_common::DataFusionError::NotImplemented(format!(
95 "DistPlannerOptions does not support set key: {key} with value: {value}"
96 )))
97 }
98
99 fn entries(&self) -> Vec<datafusion::config::ConfigEntry> {
100 vec![datafusion::config::ConfigEntry {
101 key: "allow_query_fallback".to_string(),
102 value: Some(self.allow_query_fallback.to_string()),
103 description: "Allow query fallback to fallback plan rewriter",
104 }]
105 }
106}
107
108#[derive(Debug)]
109pub struct DistPlannerAnalyzer;
110
111impl AnalyzerRule for DistPlannerAnalyzer {
112 fn name(&self) -> &str {
113 "DistPlannerAnalyzer"
114 }
115
116 fn analyze(
117 &self,
118 plan: LogicalPlan,
119 config: &ConfigOptions,
120 ) -> datafusion_common::Result<LogicalPlan> {
121 let mut config = config.clone();
122 config.optimizer.filter_null_join_keys = true;
124 let config = Arc::new(config);
125 let opt = config.extensions.get::<DistPlannerOptions>();
126 let allow_fallback = opt.map(|o| o.allow_query_fallback).unwrap_or(false);
127
128 let scheduled_time = config
132 .extensions
133 .get::<ScheduledTimeExtension>()
134 .and_then(|ext| ext.scheduled_time);
135
136 let optimizer_context = PatchOptimizerContext {
137 inner: datafusion_optimizer::OptimizerContext::new(),
138 config: config.clone(),
139 scheduled_time,
140 };
141
142 let plan = plan
143 .rewrite_with_subqueries(&mut PlanTreeExpressionSimplifier::new(optimizer_context))?
144 .data;
145 let fallback_plan = plan.clone();
146
147 let optimizer_context = PatchOptimizerContext {
154 inner: datafusion_optimizer::OptimizerContext::new(),
155 config: config.clone(),
156 scheduled_time,
157 };
158 let plan = match pre_merge_scan_optimizer().optimize(plan, &optimizer_context, |_, _| {}) {
159 Ok(plan) => plan,
160 Err(err) => {
161 if allow_fallback {
162 common_telemetry::warn!(err; "Failed to pre-optimize plan, using fallback plan rewriter for plan: {fallback_plan}");
163 PUSH_DOWN_FALLBACK_ERRORS_TOTAL.inc();
164 return self.use_fallback(fallback_plan);
165 } else {
166 return Err(err);
167 }
168 }
169 };
170
171 let result = match self.try_push_down(plan.clone()) {
172 Ok(plan) => plan,
173 Err(err) => {
174 if allow_fallback {
175 common_telemetry::warn!(err; "Failed to push down plan, using fallback plan rewriter for plan: {plan}");
176 PUSH_DOWN_FALLBACK_ERRORS_TOTAL.inc();
178 self.use_fallback(fallback_plan)?
179 } else {
180 return Err(err);
181 }
182 }
183 };
184
185 Ok(result)
186 }
187}
188
189fn pre_merge_scan_optimizer() -> Optimizer {
213 Optimizer::with_rules(vec![
214 Arc::new(RewriteSetComparison::new()),
215 Arc::new(DecorrelatePredicateSubquery::new()),
216 Arc::new(ScalarSubqueryToJoin::new()),
217 Arc::new(DecorrelateLateralJoin::new()),
218 Arc::new(ExtractEquijoinPredicate::new()),
219 Arc::new(EliminateFilter::new()),
220 Arc::new(PropagateEmptyRelation::new()),
221 Arc::new(FilterNullJoinKeys::default()),
222 Arc::new(PushDownFilter::new()),
223 Arc::new(SimplifyExpressions::new()),
224 ])
225}
226
227impl DistPlannerAnalyzer {
228 fn try_push_down(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
230 let plan = plan.transform(&Self::inspect_plan_with_subquery)?;
231 let mut rewriter = PlanRewriter::default();
232 let result = plan.data.rewrite(&mut rewriter)?.data;
233 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
234 }
235
236 fn use_fallback(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
238 let mut rewriter = fallback::FallbackPlanRewriter;
239 let result = plan.rewrite(&mut rewriter)?.data;
240 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
241 }
242
243 fn inspect_plan_with_subquery(plan: LogicalPlan) -> DfResult<Transformed<LogicalPlan>> {
244 if let LogicalPlan::Limit(_) | LogicalPlan::Distinct(_) = &plan {
247 return Ok(Transformed::no(plan));
248 }
249
250 let exprs = plan
251 .expressions_consider_join()
252 .into_iter()
253 .map(|e| e.transform(&Self::transform_subquery).map(|x| x.data))
254 .collect::<DfResult<Vec<_>>>()?;
255
256 if !matches!(plan, LogicalPlan::Unnest(_)) {
258 let inputs = plan.inputs().into_iter().cloned().collect::<Vec<_>>();
259 Ok(Transformed::yes(plan.with_new_exprs(exprs, inputs)?))
260 } else {
261 Ok(Transformed::no(plan))
262 }
263 }
264
265 fn transform_subquery(expr: Expr) -> DfResult<Transformed<Expr>> {
266 match expr {
267 Expr::Exists(exists) => Ok(Transformed::yes(Expr::Exists(Exists {
268 subquery: Self::handle_subquery(exists.subquery)?,
269 negated: exists.negated,
270 }))),
271 Expr::InSubquery(in_subquery) => Ok(Transformed::yes(Expr::InSubquery(InSubquery {
272 expr: in_subquery.expr,
273 subquery: Self::handle_subquery(in_subquery.subquery)?,
274 negated: in_subquery.negated,
275 }))),
276 Expr::ScalarSubquery(scalar_subquery) => Ok(Transformed::yes(Expr::ScalarSubquery(
277 Self::handle_subquery(scalar_subquery)?,
278 ))),
279
280 _ => Ok(Transformed::no(expr)),
281 }
282 }
283
284 fn handle_subquery(subquery: Subquery) -> DfResult<Subquery> {
285 let mut rewriter = PlanRewriter::default();
286 let mut rewrote_subquery = subquery
287 .subquery
288 .as_ref()
289 .clone()
290 .rewrite(&mut rewriter)?
291 .data;
292 if matches!(rewrote_subquery, LogicalPlan::Extension(_)) {
294 let output_schema = rewrote_subquery.schema().clone();
295 let project_exprs = output_schema
296 .fields()
297 .iter()
298 .map(|f| col_fn(f.name()))
299 .collect::<Vec<_>>();
300 rewrote_subquery = LogicalPlanBuilder::from(rewrote_subquery)
301 .project(project_exprs)?
302 .build()?;
303 }
304
305 Ok(Subquery {
306 subquery: Arc::new(rewrote_subquery),
307 outer_ref_columns: subquery.outer_ref_columns,
308 spans: Default::default(),
309 })
310 }
311
312 fn assign_merge_scan_remote_dyn_filter_producer_ids(
313 plan: LogicalPlan,
314 ) -> DfResult<LogicalPlan> {
315 let mut assigner = MergeScanRemoteDynFilterProducerIdAssigner::default();
316 Ok(plan.rewrite_with_subqueries(&mut assigner)?.data)
317 }
318}
319
320#[derive(Debug, Default)]
321struct RemoteDynFilterProducerIdAllocator {
322 next_remote_dyn_filter_producer_id: u64,
323}
324
325impl RemoteDynFilterProducerIdAllocator {
326 fn allocate(&mut self) -> RemoteDynFilterProducerId {
327 self.next_remote_dyn_filter_producer_id += 1;
328 RemoteDynFilterProducerId::new(self.next_remote_dyn_filter_producer_id)
329 }
330}
331
332#[derive(Debug, Default)]
334struct MergeScanRemoteDynFilterProducerIdAssigner {
335 remote_dyn_filter_producer_id_allocator: RemoteDynFilterProducerIdAllocator,
336}
337
338impl TreeNodeRewriter for MergeScanRemoteDynFilterProducerIdAssigner {
339 type Node = LogicalPlan;
340
341 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
342 let LogicalPlan::Extension(extension) = &node else {
343 return Ok(Transformed::no(node));
344 };
345 let Some(merge_scan) = extension
346 .node
347 .as_any()
348 .downcast_ref::<MergeScanLogicalPlan>()
349 else {
350 return Ok(Transformed::no(node));
351 };
352
353 Ok(Transformed::yes(
354 merge_scan
355 .clone()
356 .with_remote_dyn_filter_producer_id(
357 self.remote_dyn_filter_producer_id_allocator.allocate(),
358 )
359 .into_logical_plan(),
360 ))
361 }
362}
363
364#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
366enum RewriterStatus {
367 #[default]
368 Unexpanded,
369 Expanded,
370}
371
372#[derive(Debug, Default)]
373struct PlanRewriter {
374 level: usize,
376 stack: Vec<(LogicalPlan, usize)>,
378 stage: Vec<LogicalPlan>,
380 status: RewriterStatus,
381 partition_cols: Option<AliasMapping>,
383 column_requirements: Vec<(HashSet<Column>, usize)>,
409 expand_on_next_call: bool,
414 expand_on_next_part_cond_trans_commutative: bool,
426 new_child_plan: Option<LogicalPlan>,
427}
428
429impl PlanRewriter {
430 fn get_parent(&self) -> Option<&LogicalPlan> {
431 self.stack
433 .iter()
434 .rev()
435 .find(|(_, level)| *level == self.level - 1)
436 .map(|(node, _)| node)
437 }
438
439 fn should_expand(&mut self, plan: &LogicalPlan) -> DfResult<bool> {
441 debug!(
442 "Check should_expand at level: {} with Stack:\n{}, ",
443 self.level,
444 self.stack
445 .iter()
446 .map(|(p, l)| format!("{l}:{}{}", " ".repeat(l - 1), p.display()))
447 .collect::<Vec<String>>()
448 .join("\n"),
449 );
450 if let Err(e) = DFLogicalSubstraitConvertor.encode(plan, DefaultSerializer) {
451 debug!(
452 "PlanRewriter: plan cannot be converted to substrait with error={e:?}, expanding now: {plan}"
453 );
454 return Ok(true);
455 }
456
457 if self.expand_on_next_call {
458 self.expand_on_next_call = false;
459 debug!("PlanRewriter: expand_on_next_call is true, expanding now");
460 return Ok(true);
461 }
462
463 if self.expand_on_next_part_cond_trans_commutative {
464 let comm = Categorizer::check_plan(plan, self.partition_cols.clone())?;
465 match comm {
466 Commutativity::PartialCommutative => {
467 self.expand_on_next_part_cond_trans_commutative = false;
473 self.expand_on_next_call = true;
474 }
475 Commutativity::ConditionalCommutative(_)
476 | Commutativity::TransformedCommutative { .. } => {
477 self.expand_on_next_part_cond_trans_commutative = false;
480 debug!(
481 "PlanRewriter: meet a new conditional/transformed commutative plan, expanding now: {plan}"
482 );
483 return Ok(true);
484 }
485 _ => (),
486 }
487 }
488
489 match Categorizer::check_plan(plan, self.partition_cols.clone())? {
490 Commutativity::Commutative => {
491 if let LogicalPlan::Extension(ext_a) = plan
496 && ext_a.node.name() == SeriesDivide::name()
497 && let Some(LogicalPlan::Extension(ext_b)) = self.stage.last()
498 && ext_b.node.name() == MergeSortLogicalPlan::name()
499 {
500 self.stage.pop();
504 self.expand_on_next_part_cond_trans_commutative = false;
505 self.column_requirements.clear();
506 }
507 }
508 Commutativity::PartialCommutative => {
509 if let Some(plan) = partial_commutative_transformer(plan) {
510 self.update_column_requirements(&plan, self.level - 1);
512 self.expand_on_next_part_cond_trans_commutative = true;
513 self.stage.push(plan)
514 }
515 }
516 Commutativity::ConditionalCommutative(transformer) => {
517 if let Some(transformer) = transformer
518 && let Some(plan) = transformer(plan)
519 {
520 self.update_column_requirements(&plan, self.level - 1);
522 self.expand_on_next_part_cond_trans_commutative = true;
523 self.stage.push(plan)
524 }
525 }
526 Commutativity::TransformedCommutative { transformer } => {
527 if let Some(transformer) = transformer {
528 let transformer_actions = transformer(plan)?;
529 debug!(
530 "PlanRewriter: transformed plan: {}\n from {plan}",
531 transformer_actions
532 .extra_parent_plans
533 .iter()
534 .enumerate()
535 .map(|(i, p)| format!(
536 "Extra {i}-th parent plan from parent to child = {}",
537 p.display()
538 ))
539 .collect::<Vec<_>>()
540 .join("\n")
541 );
542 if let Some(new_child_plan) = &transformer_actions.new_child_plan {
543 debug!("PlanRewriter: new child plan: {}", new_child_plan);
544 }
545 if let Some(last_stage) = transformer_actions.extra_parent_plans.last() {
546 self.update_column_requirements(last_stage, self.level - 1);
549 }
550 self.stage
551 .extend(transformer_actions.extra_parent_plans.into_iter().rev());
552 self.expand_on_next_call = true;
553 self.new_child_plan = transformer_actions.new_child_plan;
554 }
555 }
556 Commutativity::NonCommutative
557 | Commutativity::Unimplemented
558 | Commutativity::Unsupported => {
559 debug!("PlanRewriter: meet a non-commutative plan, expanding now: {plan}");
560 return Ok(true);
561 }
562 }
563
564 Ok(false)
565 }
566
567 fn update_column_requirements(&mut self, plan: &LogicalPlan, plan_level: usize) {
571 debug!(
572 "PlanRewriter: update column requirements for plan: {plan}\n with old column_requirements: {:?}",
573 self.column_requirements
574 );
575 let mut container = HashSet::new();
576 for expr in plan.expressions() {
577 let _ = expr_to_columns(&expr, &mut container);
579 }
580
581 self.column_requirements.push((container, plan_level));
582 debug!(
583 "PlanRewriter: updated column requirements: {:?}",
584 self.column_requirements
585 );
586 }
587
588 fn is_expanded(&self) -> bool {
589 self.status == RewriterStatus::Expanded
590 }
591
592 fn set_expanded(&mut self) {
593 self.status = RewriterStatus::Expanded;
594 }
595
596 fn set_unexpanded(&mut self) {
597 self.status = RewriterStatus::Unexpanded;
598 }
599
600 fn maybe_set_partitions(&mut self, plan: &LogicalPlan) -> DfResult<()> {
601 if let Some(part_cols) = &mut self.partition_cols {
602 let child = plan.inputs().first().cloned().ok_or_else(|| {
604 datafusion_common::DataFusionError::Internal(format!(
605 "PlanRewriter: maybe_set_partitions: plan has no child: {plan}"
606 ))
607 })?;
608
609 for (_col_name, alias_set) in part_cols.iter_mut() {
610 let aliased_cols = aliased_columns_for(
611 &alias_set.clone().into_iter().collect(),
612 plan,
613 Some(child),
614 )?;
615 *alias_set = aliased_cols.into_values().flatten().collect();
616 }
617
618 debug!(
619 "PlanRewriter: maybe_set_partitions: updated partition columns: {:?} at plan: {}",
620 part_cols,
621 plan.display()
622 );
623
624 return Ok(());
625 }
626
627 if let LogicalPlan::TableScan(table_scan) = plan
628 && let Some(source) = table_scan
629 .source
630 .as_any()
631 .downcast_ref::<DefaultTableSource>()
632 && let Some(provider) = source
633 .table_provider
634 .as_any()
635 .downcast_ref::<DfTableProviderAdapter>()
636 {
637 let table = provider.table();
638 if table.table_type() == TableType::Base {
639 let info = table.table_info();
640 let partition_key_indices = info.meta.partition_key_indices.clone();
641 let schema = info.meta.schema.clone();
642 let mut partition_cols = partition_key_indices
643 .iter()
644 .map(|index| schema.column_name_by_index(*index).to_string())
645 .collect::<Vec<String>>();
646 debug!(
647 "PlanRewriter: loaded table partition metadata, table: {}, table_id: {}, partition_key_indices: {:?}, partition_columns: {:?}",
648 info.name, info.ident.table_id, info.meta.partition_key_indices, partition_cols,
649 );
650
651 let partition_rules = table.partition_rules();
652 let exist_phy_part_cols_not_in_logical_table = partition_rules
653 .map(|r| !r.extra_phy_cols_not_in_logical_table.is_empty())
654 .unwrap_or(false);
655
656 if exist_phy_part_cols_not_in_logical_table && partition_cols.is_empty() {
657 partition_cols.push(OTHER_PHY_PART_COL_PLACEHOLDER.to_string());
665 }
666 self.partition_cols = Some(
667 partition_cols
668 .into_iter()
669 .map(|c| {
670 if c == OTHER_PHY_PART_COL_PLACEHOLDER {
671 return Ok((c.clone(), BTreeSet::new()));
673 }
674 let index =
675 if let Some(c) = plan.schema().index_of_column_by_name(None, &c){
676 c
677 } else {
678 return Ok((c.clone(), BTreeSet::new()))
681 };
682 let column = plan.schema().columns().get(index).cloned().ok_or_else(|| {
683 datafusion_common::DataFusionError::Internal(format!(
684 "PlanRewriter: maybe_set_partitions: column index {index} out of bounds in schema of plan: {plan}"
685 ))
686 })?;
687 Ok((c.clone(), BTreeSet::from([column])))
688 })
689 .collect::<DfResult<AliasMapping>>()?,
690 );
691 }
692 }
693
694 Ok(())
695 }
696
697 fn pop_stack(&mut self) {
699 self.level -= 1;
700 self.stack.pop();
701 }
702
703 fn expand(&mut self, mut on_node: LogicalPlan) -> DfResult<LogicalPlan> {
704 let schema = on_node.schema().clone();
706 if let Some(new_child_plan) = self.new_child_plan.take() {
707 on_node = new_child_plan;
709 }
710 let mut rewriter = EnforceDistRequirementRewriter::new(
711 std::mem::take(&mut self.column_requirements),
712 self.level,
713 );
714 debug!(
715 "PlanRewriter: enforce column requirements for node: {on_node} with rewriter: {rewriter:?}"
716 );
717 on_node = on_node.rewrite(&mut rewriter)?.data;
718 debug!(
719 "PlanRewriter: after enforced column requirements with rewriter: {rewriter:?} for node:\n{on_node}"
720 );
721
722 debug!(
723 "PlanRewriter: expand on node: {on_node} with partition col alias mapping: {:?}",
724 self.partition_cols
725 );
726
727 let mut node = MergeScanLogicalPlan::new(
729 on_node.clone(),
730 false,
731 self.partition_cols.clone().unwrap_or_default(),
734 )
735 .into_logical_plan();
736
737 for new_stage in self.stage.drain(..) {
739 let new_stage = if let LogicalPlan::Extension(ext) = &new_stage
741 && let Some(merge_sort) = ext.node.as_any().downcast_ref::<MergeSortLogicalPlan>()
742 {
743 rewrite_merge_sort_exprs(merge_sort, &on_node)?
745 } else {
746 new_stage
747 };
748 node = new_stage
749 .with_new_exprs(new_stage.expressions_consider_join(), vec![node.clone()])?;
750 }
751 self.set_expanded();
752
753 let node = LogicalPlanBuilder::from(node)
756 .project(schema.iter().map(|(qualifier, field)| {
757 Expr::Column(Column::new(qualifier.cloned(), field.name()))
758 }))?
759 .build()?;
760
761 Ok(node)
762 }
763}
764
765#[derive(Debug)]
773struct EnforceDistRequirementRewriter {
774 column_requirements: Vec<(HashSet<Column>, usize)>,
778 cur_level: usize,
789 plan_per_level: BTreeMap<usize, LogicalPlan>,
790}
791
792impl EnforceDistRequirementRewriter {
793 fn new(column_requirements: Vec<(HashSet<Column>, usize)>, cur_level: usize) -> Self {
794 debug!(
795 "Create EnforceDistRequirementRewriter with column_requirements: {:?} at cur_level: {}",
796 column_requirements, cur_level
797 );
798 Self {
799 column_requirements,
800 cur_level,
801 plan_per_level: BTreeMap::new(),
802 }
803 }
804
805 fn get_current_applicable_column_requirements(
809 &self,
810 node: &LogicalPlan,
811 ) -> DfResult<BTreeMap<(Column, usize), BTreeSet<Column>>> {
812 let col_req_per_level = self
813 .column_requirements
814 .iter()
815 .filter(|(_, level)| *level >= self.cur_level)
816 .collect::<Vec<_>>();
817
818 let mut result_alias_mapping = BTreeMap::new();
821 let Some(child) = node.inputs().first().cloned() else {
822 return Ok(Default::default());
823 };
824 for (col_req, level) in col_req_per_level {
825 if let Some(original) = self.plan_per_level.get(level) {
826 let aliased_cols =
828 aliased_columns_for(&col_req.iter().cloned().collect(), node, Some(original))?;
829 for original_col in col_req {
830 let aliased_cols = aliased_cols.get(original_col).cloned();
831 if let Some(cols) = aliased_cols
832 && !cols.is_empty()
833 {
834 result_alias_mapping.insert((original_col.clone(), *level), cols);
835 } else {
836 let aliases_in_child = aliased_columns_for(
841 &[original_col.clone()].into(),
842 child,
843 Some(original),
844 )?;
845 let Some(aliases) = aliases_in_child
846 .get(original_col)
847 .cloned()
848 .filter(|a| !a.is_empty())
849 else {
850 return Err(datafusion_common::DataFusionError::Internal(format!(
851 "EnforceDistRequirementRewriter: no alias found for required column {original_col} at level {level} in current node's child plan: \n{child} from original plan: \n{original}",
852 )));
853 };
854
855 result_alias_mapping.insert((original_col.clone(), *level), aliases);
856 }
857 }
858 }
859 }
860 Ok(result_alias_mapping)
861 }
862}
863
864impl TreeNodeRewriter for EnforceDistRequirementRewriter {
865 type Node = LogicalPlan;
866
867 fn f_down(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
868 if node.inputs().len() > 1 {
870 return Err(datafusion_common::DataFusionError::Internal(
871 "EnforceDistRequirementRewriter: node with multiple inputs is not supported"
872 .to_string(),
873 ));
874 }
875 self.plan_per_level.insert(self.cur_level, node.clone());
876 self.cur_level += 1;
877 Ok(Transformed::no(node))
878 }
879
880 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
881 self.cur_level -= 1;
882 if let LogicalPlan::Projection(ref projection) = node {
886 let mut applicable_column_requirements =
887 self.get_current_applicable_column_requirements(&node)?;
888
889 debug!(
890 "EnforceDistRequirementRewriter: applicable column requirements at level {} = {:?} for node {}",
891 self.cur_level,
892 applicable_column_requirements,
893 node.display()
894 );
895
896 for expr in &projection.expr {
897 let (qualifier, name) = expr.qualified_name();
898 let column = Column::new(qualifier, name);
899 applicable_column_requirements.retain(|_col_level, alias_set| {
900 !alias_set.contains(&column)
902 });
903 }
904 if applicable_column_requirements.is_empty() {
905 return Ok(Transformed::no(node));
906 }
907
908 let mut new_exprs = projection.expr.clone();
909 for (col, alias_set) in &applicable_column_requirements {
910 new_exprs.push(Expr::Column(alias_set.first().cloned().ok_or_else(
912 || {
913 datafusion_common::DataFusionError::Internal(
914 format!("EnforceDistRequirementRewriter: alias set is empty, for column {col:?} in node {node}"),
915 )
916 },
917 )?));
918 }
919 let new_node =
920 node.with_new_exprs(new_exprs, node.inputs().into_iter().cloned().collect())?;
921 debug!(
922 "EnforceDistRequirementRewriter: added missing columns {:?} to projection node from old node: \n{node}\n Making new node: \n{new_node}",
923 applicable_column_requirements
924 );
925
926 self.plan_per_level.insert(self.cur_level, new_node.clone());
928
929 return Ok(Transformed::yes(new_node));
931 }
932 Ok(Transformed::no(node))
933 }
934}
935
936impl TreeNodeRewriter for PlanRewriter {
937 type Node = LogicalPlan;
938
939 fn f_down<'a>(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
941 self.level += 1;
942 self.stack.push((node.clone(), self.level));
943 self.stage.clear();
945 self.set_unexpanded();
946 self.partition_cols = None;
947 Ok(Transformed::no(node))
948 }
949
950 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
954 if self.is_expanded() {
956 self.pop_stack();
957 return Ok(Transformed::no(node));
958 }
959
960 if node.inputs().is_empty() && !matches!(node, LogicalPlan::TableScan(_)) {
962 self.set_expanded();
963 self.pop_stack();
964 return Ok(Transformed::no(node));
965 }
966
967 self.maybe_set_partitions(&node)?;
968
969 let Some(parent) = self.get_parent() else {
970 debug!("Plan Rewriter: expand now for no parent found for node: {node}");
971 let node = self.expand(node);
972 debug!(
973 "PlanRewriter: expanded plan: {}",
974 match &node {
975 Ok(n) => n.to_string(),
976 Err(e) => format!("Error expanding plan: {e}"),
977 }
978 );
979 let node = node?;
980 self.pop_stack();
981 return Ok(Transformed::yes(node));
982 };
983
984 let parent = parent.clone();
985
986 if self.should_expand(&parent)? {
987 debug!(
989 "PlanRewriter: should expand child:\n {node}\n Of Parent: {}",
990 parent.display()
991 );
992 let node = self.expand(node);
993 debug!(
994 "PlanRewriter: expanded plan: {}",
995 match &node {
996 Ok(n) => n.to_string(),
997 Err(e) => format!("Error expanding plan: {e}"),
998 }
999 );
1000 let node = node?;
1001 self.pop_stack();
1002 return Ok(Transformed::yes(node));
1003 }
1004
1005 self.pop_stack();
1006 Ok(Transformed::no(node))
1007 }
1008}