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 promql::extension_plan::SeriesDivide;
40use substrait::{DFLogicalSubstraitConvertor, SubstraitPlan};
41use table::metadata::TableType;
42use table::table::adapter::DfTableProviderAdapter;
43
44use crate::dist_plan::RemoteDynFilterProducerId;
45use crate::dist_plan::analyzer::utils::{
46 PatchOptimizerContext, PlanTreeExpressionSimplifier, aliased_columns_for,
47 rewrite_merge_sort_exprs,
48};
49use crate::dist_plan::commutativity::{
50 Categorizer, Commutativity, partial_commutative_transformer,
51};
52use crate::dist_plan::merge_scan::MergeScanLogicalPlan;
53use crate::dist_plan::merge_sort::MergeSortLogicalPlan;
54use crate::metrics::PUSH_DOWN_FALLBACK_ERRORS_TOTAL;
55use crate::plan::ExtractExpr;
56use crate::query_engine::DefaultSerializer;
57
58#[cfg(test)]
59mod test;
60
61mod fallback;
62pub(crate) mod utils;
63
64pub(crate) use utils::AliasMapping;
65
66const OTHER_PHY_PART_COL_PLACEHOLDER: &str = "__OTHER_PHYSICAL_PART_COLS_PLACEHOLDER__";
68
69#[derive(Debug, Clone)]
70pub struct DistPlannerOptions {
71 pub allow_query_fallback: bool,
72}
73
74impl ConfigExtension for DistPlannerOptions {
75 const PREFIX: &'static str = "dist_planner";
76}
77
78impl ExtensionOptions for DistPlannerOptions {
79 fn as_any(&self) -> &dyn std::any::Any {
80 self
81 }
82
83 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
84 self
85 }
86
87 fn cloned(&self) -> Box<dyn ExtensionOptions> {
88 Box::new(self.clone())
89 }
90
91 fn set(&mut self, key: &str, value: &str) -> DfResult<()> {
92 Err(datafusion_common::DataFusionError::NotImplemented(format!(
93 "DistPlannerOptions does not support set key: {key} with value: {value}"
94 )))
95 }
96
97 fn entries(&self) -> Vec<datafusion::config::ConfigEntry> {
98 vec![datafusion::config::ConfigEntry {
99 key: "allow_query_fallback".to_string(),
100 value: Some(self.allow_query_fallback.to_string()),
101 description: "Allow query fallback to fallback plan rewriter",
102 }]
103 }
104}
105
106#[derive(Debug)]
107pub struct DistPlannerAnalyzer;
108
109impl AnalyzerRule for DistPlannerAnalyzer {
110 fn name(&self) -> &str {
111 "DistPlannerAnalyzer"
112 }
113
114 fn analyze(
115 &self,
116 plan: LogicalPlan,
117 config: &ConfigOptions,
118 ) -> datafusion_common::Result<LogicalPlan> {
119 let mut config = config.clone();
120 config.optimizer.filter_null_join_keys = true;
122 let config = Arc::new(config);
123 let opt = config.extensions.get::<DistPlannerOptions>();
124 let allow_fallback = opt.map(|o| o.allow_query_fallback).unwrap_or(false);
125
126 let optimizer_context = PatchOptimizerContext {
127 inner: datafusion_optimizer::OptimizerContext::new(),
128 config: config.clone(),
129 };
130
131 let plan = plan
132 .rewrite_with_subqueries(&mut PlanTreeExpressionSimplifier::new(optimizer_context))?
133 .data;
134 let fallback_plan = plan.clone();
135
136 let optimizer_context = PatchOptimizerContext {
143 inner: datafusion_optimizer::OptimizerContext::new(),
144 config: config.clone(),
145 };
146 let plan = match pre_merge_scan_optimizer().optimize(plan, &optimizer_context, |_, _| {}) {
147 Ok(plan) => plan,
148 Err(err) => {
149 if allow_fallback {
150 common_telemetry::warn!(err; "Failed to pre-optimize plan, using fallback plan rewriter for plan: {fallback_plan}");
151 PUSH_DOWN_FALLBACK_ERRORS_TOTAL.inc();
152 return self.use_fallback(fallback_plan);
153 } else {
154 return Err(err);
155 }
156 }
157 };
158
159 let result = match self.try_push_down(plan.clone()) {
160 Ok(plan) => plan,
161 Err(err) => {
162 if allow_fallback {
163 common_telemetry::warn!(err; "Failed to push down plan, using fallback plan rewriter for plan: {plan}");
164 PUSH_DOWN_FALLBACK_ERRORS_TOTAL.inc();
166 self.use_fallback(fallback_plan)?
167 } else {
168 return Err(err);
169 }
170 }
171 };
172
173 Ok(result)
174 }
175}
176
177fn pre_merge_scan_optimizer() -> Optimizer {
201 Optimizer::with_rules(vec![
202 Arc::new(RewriteSetComparison::new()),
203 Arc::new(DecorrelatePredicateSubquery::new()),
204 Arc::new(ScalarSubqueryToJoin::new()),
205 Arc::new(DecorrelateLateralJoin::new()),
206 Arc::new(ExtractEquijoinPredicate::new()),
207 Arc::new(EliminateFilter::new()),
208 Arc::new(PropagateEmptyRelation::new()),
209 Arc::new(FilterNullJoinKeys::default()),
210 Arc::new(PushDownFilter::new()),
211 ])
212}
213
214impl DistPlannerAnalyzer {
215 fn try_push_down(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
217 let plan = plan.transform(&Self::inspect_plan_with_subquery)?;
218 let mut rewriter = PlanRewriter::default();
219 let result = plan.data.rewrite(&mut rewriter)?.data;
220 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
221 }
222
223 fn use_fallback(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
225 let mut rewriter = fallback::FallbackPlanRewriter;
226 let result = plan.rewrite(&mut rewriter)?.data;
227 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
228 }
229
230 fn inspect_plan_with_subquery(plan: LogicalPlan) -> DfResult<Transformed<LogicalPlan>> {
231 if let LogicalPlan::Limit(_) | LogicalPlan::Distinct(_) = &plan {
234 return Ok(Transformed::no(plan));
235 }
236
237 let exprs = plan
238 .expressions_consider_join()
239 .into_iter()
240 .map(|e| e.transform(&Self::transform_subquery).map(|x| x.data))
241 .collect::<DfResult<Vec<_>>>()?;
242
243 if !matches!(plan, LogicalPlan::Unnest(_)) {
245 let inputs = plan.inputs().into_iter().cloned().collect::<Vec<_>>();
246 Ok(Transformed::yes(plan.with_new_exprs(exprs, inputs)?))
247 } else {
248 Ok(Transformed::no(plan))
249 }
250 }
251
252 fn transform_subquery(expr: Expr) -> DfResult<Transformed<Expr>> {
253 match expr {
254 Expr::Exists(exists) => Ok(Transformed::yes(Expr::Exists(Exists {
255 subquery: Self::handle_subquery(exists.subquery)?,
256 negated: exists.negated,
257 }))),
258 Expr::InSubquery(in_subquery) => Ok(Transformed::yes(Expr::InSubquery(InSubquery {
259 expr: in_subquery.expr,
260 subquery: Self::handle_subquery(in_subquery.subquery)?,
261 negated: in_subquery.negated,
262 }))),
263 Expr::ScalarSubquery(scalar_subquery) => Ok(Transformed::yes(Expr::ScalarSubquery(
264 Self::handle_subquery(scalar_subquery)?,
265 ))),
266
267 _ => Ok(Transformed::no(expr)),
268 }
269 }
270
271 fn handle_subquery(subquery: Subquery) -> DfResult<Subquery> {
272 let mut rewriter = PlanRewriter::default();
273 let mut rewrote_subquery = subquery
274 .subquery
275 .as_ref()
276 .clone()
277 .rewrite(&mut rewriter)?
278 .data;
279 if matches!(rewrote_subquery, LogicalPlan::Extension(_)) {
281 let output_schema = rewrote_subquery.schema().clone();
282 let project_exprs = output_schema
283 .fields()
284 .iter()
285 .map(|f| col_fn(f.name()))
286 .collect::<Vec<_>>();
287 rewrote_subquery = LogicalPlanBuilder::from(rewrote_subquery)
288 .project(project_exprs)?
289 .build()?;
290 }
291
292 Ok(Subquery {
293 subquery: Arc::new(rewrote_subquery),
294 outer_ref_columns: subquery.outer_ref_columns,
295 spans: Default::default(),
296 })
297 }
298
299 fn assign_merge_scan_remote_dyn_filter_producer_ids(
300 plan: LogicalPlan,
301 ) -> DfResult<LogicalPlan> {
302 let mut assigner = MergeScanRemoteDynFilterProducerIdAssigner::default();
303 Ok(plan.rewrite_with_subqueries(&mut assigner)?.data)
304 }
305}
306
307#[derive(Debug, Default)]
308struct RemoteDynFilterProducerIdAllocator {
309 next_remote_dyn_filter_producer_id: u64,
310}
311
312impl RemoteDynFilterProducerIdAllocator {
313 fn allocate(&mut self) -> RemoteDynFilterProducerId {
314 self.next_remote_dyn_filter_producer_id += 1;
315 RemoteDynFilterProducerId::new(self.next_remote_dyn_filter_producer_id)
316 }
317}
318
319#[derive(Debug, Default)]
321struct MergeScanRemoteDynFilterProducerIdAssigner {
322 remote_dyn_filter_producer_id_allocator: RemoteDynFilterProducerIdAllocator,
323}
324
325impl TreeNodeRewriter for MergeScanRemoteDynFilterProducerIdAssigner {
326 type Node = LogicalPlan;
327
328 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
329 let LogicalPlan::Extension(extension) = &node else {
330 return Ok(Transformed::no(node));
331 };
332 let Some(merge_scan) = extension
333 .node
334 .as_any()
335 .downcast_ref::<MergeScanLogicalPlan>()
336 else {
337 return Ok(Transformed::no(node));
338 };
339
340 Ok(Transformed::yes(
341 merge_scan
342 .clone()
343 .with_remote_dyn_filter_producer_id(
344 self.remote_dyn_filter_producer_id_allocator.allocate(),
345 )
346 .into_logical_plan(),
347 ))
348 }
349}
350
351#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
353enum RewriterStatus {
354 #[default]
355 Unexpanded,
356 Expanded,
357}
358
359#[derive(Debug, Default)]
360struct PlanRewriter {
361 level: usize,
363 stack: Vec<(LogicalPlan, usize)>,
365 stage: Vec<LogicalPlan>,
367 status: RewriterStatus,
368 partition_cols: Option<AliasMapping>,
370 column_requirements: Vec<(HashSet<Column>, usize)>,
396 expand_on_next_call: bool,
401 expand_on_next_part_cond_trans_commutative: bool,
413 new_child_plan: Option<LogicalPlan>,
414}
415
416impl PlanRewriter {
417 fn get_parent(&self) -> Option<&LogicalPlan> {
418 self.stack
420 .iter()
421 .rev()
422 .find(|(_, level)| *level == self.level - 1)
423 .map(|(node, _)| node)
424 }
425
426 fn should_expand(&mut self, plan: &LogicalPlan) -> DfResult<bool> {
428 debug!(
429 "Check should_expand at level: {} with Stack:\n{}, ",
430 self.level,
431 self.stack
432 .iter()
433 .map(|(p, l)| format!("{l}:{}{}", " ".repeat(l - 1), p.display()))
434 .collect::<Vec<String>>()
435 .join("\n"),
436 );
437 if let Err(e) = DFLogicalSubstraitConvertor.encode(plan, DefaultSerializer) {
438 debug!(
439 "PlanRewriter: plan cannot be converted to substrait with error={e:?}, expanding now: {plan}"
440 );
441 return Ok(true);
442 }
443
444 if self.expand_on_next_call {
445 self.expand_on_next_call = false;
446 debug!("PlanRewriter: expand_on_next_call is true, expanding now");
447 return Ok(true);
448 }
449
450 if self.expand_on_next_part_cond_trans_commutative {
451 let comm = Categorizer::check_plan(plan, self.partition_cols.clone())?;
452 match comm {
453 Commutativity::PartialCommutative => {
454 self.expand_on_next_part_cond_trans_commutative = false;
460 self.expand_on_next_call = true;
461 }
462 Commutativity::ConditionalCommutative(_)
463 | Commutativity::TransformedCommutative { .. } => {
464 self.expand_on_next_part_cond_trans_commutative = false;
467 debug!(
468 "PlanRewriter: meet a new conditional/transformed commutative plan, expanding now: {plan}"
469 );
470 return Ok(true);
471 }
472 _ => (),
473 }
474 }
475
476 match Categorizer::check_plan(plan, self.partition_cols.clone())? {
477 Commutativity::Commutative => {
478 if let LogicalPlan::Extension(ext_a) = plan
483 && ext_a.node.name() == SeriesDivide::name()
484 && let Some(LogicalPlan::Extension(ext_b)) = self.stage.last()
485 && ext_b.node.name() == MergeSortLogicalPlan::name()
486 {
487 self.stage.pop();
491 self.expand_on_next_part_cond_trans_commutative = false;
492 self.column_requirements.clear();
493 }
494 }
495 Commutativity::PartialCommutative => {
496 if let Some(plan) = partial_commutative_transformer(plan) {
497 self.update_column_requirements(&plan, self.level - 1);
499 self.expand_on_next_part_cond_trans_commutative = true;
500 self.stage.push(plan)
501 }
502 }
503 Commutativity::ConditionalCommutative(transformer) => {
504 if let Some(transformer) = transformer
505 && let Some(plan) = transformer(plan)
506 {
507 self.update_column_requirements(&plan, self.level - 1);
509 self.expand_on_next_part_cond_trans_commutative = true;
510 self.stage.push(plan)
511 }
512 }
513 Commutativity::TransformedCommutative { transformer } => {
514 if let Some(transformer) = transformer {
515 let transformer_actions = transformer(plan)?;
516 debug!(
517 "PlanRewriter: transformed plan: {}\n from {plan}",
518 transformer_actions
519 .extra_parent_plans
520 .iter()
521 .enumerate()
522 .map(|(i, p)| format!(
523 "Extra {i}-th parent plan from parent to child = {}",
524 p.display()
525 ))
526 .collect::<Vec<_>>()
527 .join("\n")
528 );
529 if let Some(new_child_plan) = &transformer_actions.new_child_plan {
530 debug!("PlanRewriter: new child plan: {}", new_child_plan);
531 }
532 if let Some(last_stage) = transformer_actions.extra_parent_plans.last() {
533 self.update_column_requirements(last_stage, self.level - 1);
536 }
537 self.stage
538 .extend(transformer_actions.extra_parent_plans.into_iter().rev());
539 self.expand_on_next_call = true;
540 self.new_child_plan = transformer_actions.new_child_plan;
541 }
542 }
543 Commutativity::NonCommutative
544 | Commutativity::Unimplemented
545 | Commutativity::Unsupported => {
546 debug!("PlanRewriter: meet a non-commutative plan, expanding now: {plan}");
547 return Ok(true);
548 }
549 }
550
551 Ok(false)
552 }
553
554 fn update_column_requirements(&mut self, plan: &LogicalPlan, plan_level: usize) {
558 debug!(
559 "PlanRewriter: update column requirements for plan: {plan}\n with old column_requirements: {:?}",
560 self.column_requirements
561 );
562 let mut container = HashSet::new();
563 for expr in plan.expressions() {
564 let _ = expr_to_columns(&expr, &mut container);
566 }
567
568 self.column_requirements.push((container, plan_level));
569 debug!(
570 "PlanRewriter: updated column requirements: {:?}",
571 self.column_requirements
572 );
573 }
574
575 fn is_expanded(&self) -> bool {
576 self.status == RewriterStatus::Expanded
577 }
578
579 fn set_expanded(&mut self) {
580 self.status = RewriterStatus::Expanded;
581 }
582
583 fn set_unexpanded(&mut self) {
584 self.status = RewriterStatus::Unexpanded;
585 }
586
587 fn maybe_set_partitions(&mut self, plan: &LogicalPlan) -> DfResult<()> {
588 if let Some(part_cols) = &mut self.partition_cols {
589 let child = plan.inputs().first().cloned().ok_or_else(|| {
591 datafusion_common::DataFusionError::Internal(format!(
592 "PlanRewriter: maybe_set_partitions: plan has no child: {plan}"
593 ))
594 })?;
595
596 for (_col_name, alias_set) in part_cols.iter_mut() {
597 let aliased_cols = aliased_columns_for(
598 &alias_set.clone().into_iter().collect(),
599 plan,
600 Some(child),
601 )?;
602 *alias_set = aliased_cols.into_values().flatten().collect();
603 }
604
605 debug!(
606 "PlanRewriter: maybe_set_partitions: updated partition columns: {:?} at plan: {}",
607 part_cols,
608 plan.display()
609 );
610
611 return Ok(());
612 }
613
614 if let LogicalPlan::TableScan(table_scan) = plan
615 && let Some(source) = table_scan
616 .source
617 .as_any()
618 .downcast_ref::<DefaultTableSource>()
619 && let Some(provider) = source
620 .table_provider
621 .as_any()
622 .downcast_ref::<DfTableProviderAdapter>()
623 {
624 let table = provider.table();
625 if table.table_type() == TableType::Base {
626 let info = table.table_info();
627 let partition_key_indices = info.meta.partition_key_indices.clone();
628 let schema = info.meta.schema.clone();
629 let mut partition_cols = partition_key_indices
630 .iter()
631 .map(|index| schema.column_name_by_index(*index).to_string())
632 .collect::<Vec<String>>();
633 debug!(
634 "PlanRewriter: loaded table partition metadata, table: {}, table_id: {}, partition_key_indices: {:?}, partition_columns: {:?}",
635 info.name, info.ident.table_id, info.meta.partition_key_indices, partition_cols,
636 );
637
638 let partition_rules = table.partition_rules();
639 let exist_phy_part_cols_not_in_logical_table = partition_rules
640 .map(|r| !r.extra_phy_cols_not_in_logical_table.is_empty())
641 .unwrap_or(false);
642
643 if exist_phy_part_cols_not_in_logical_table && partition_cols.is_empty() {
644 partition_cols.push(OTHER_PHY_PART_COL_PLACEHOLDER.to_string());
652 }
653 self.partition_cols = Some(
654 partition_cols
655 .into_iter()
656 .map(|c| {
657 if c == OTHER_PHY_PART_COL_PLACEHOLDER {
658 return Ok((c.clone(), BTreeSet::new()));
660 }
661 let index =
662 if let Some(c) = plan.schema().index_of_column_by_name(None, &c){
663 c
664 } else {
665 return Ok((c.clone(), BTreeSet::new()))
668 };
669 let column = plan.schema().columns().get(index).cloned().ok_or_else(|| {
670 datafusion_common::DataFusionError::Internal(format!(
671 "PlanRewriter: maybe_set_partitions: column index {index} out of bounds in schema of plan: {plan}"
672 ))
673 })?;
674 Ok((c.clone(), BTreeSet::from([column])))
675 })
676 .collect::<DfResult<AliasMapping>>()?,
677 );
678 }
679 }
680
681 Ok(())
682 }
683
684 fn pop_stack(&mut self) {
686 self.level -= 1;
687 self.stack.pop();
688 }
689
690 fn expand(&mut self, mut on_node: LogicalPlan) -> DfResult<LogicalPlan> {
691 let schema = on_node.schema().clone();
693 if let Some(new_child_plan) = self.new_child_plan.take() {
694 on_node = new_child_plan;
696 }
697 let mut rewriter = EnforceDistRequirementRewriter::new(
698 std::mem::take(&mut self.column_requirements),
699 self.level,
700 );
701 debug!(
702 "PlanRewriter: enforce column requirements for node: {on_node} with rewriter: {rewriter:?}"
703 );
704 on_node = on_node.rewrite(&mut rewriter)?.data;
705 debug!(
706 "PlanRewriter: after enforced column requirements with rewriter: {rewriter:?} for node:\n{on_node}"
707 );
708
709 debug!(
710 "PlanRewriter: expand on node: {on_node} with partition col alias mapping: {:?}",
711 self.partition_cols
712 );
713
714 let mut node = MergeScanLogicalPlan::new(
716 on_node.clone(),
717 false,
718 self.partition_cols.clone().unwrap_or_default(),
721 )
722 .into_logical_plan();
723
724 for new_stage in self.stage.drain(..) {
726 let new_stage = if let LogicalPlan::Extension(ext) = &new_stage
728 && let Some(merge_sort) = ext.node.as_any().downcast_ref::<MergeSortLogicalPlan>()
729 {
730 rewrite_merge_sort_exprs(merge_sort, &on_node)?
732 } else {
733 new_stage
734 };
735 node = new_stage
736 .with_new_exprs(new_stage.expressions_consider_join(), vec![node.clone()])?;
737 }
738 self.set_expanded();
739
740 let node = LogicalPlanBuilder::from(node)
743 .project(schema.iter().map(|(qualifier, field)| {
744 Expr::Column(Column::new(qualifier.cloned(), field.name()))
745 }))?
746 .build()?;
747
748 Ok(node)
749 }
750}
751
752#[derive(Debug)]
760struct EnforceDistRequirementRewriter {
761 column_requirements: Vec<(HashSet<Column>, usize)>,
765 cur_level: usize,
776 plan_per_level: BTreeMap<usize, LogicalPlan>,
777}
778
779impl EnforceDistRequirementRewriter {
780 fn new(column_requirements: Vec<(HashSet<Column>, usize)>, cur_level: usize) -> Self {
781 debug!(
782 "Create EnforceDistRequirementRewriter with column_requirements: {:?} at cur_level: {}",
783 column_requirements, cur_level
784 );
785 Self {
786 column_requirements,
787 cur_level,
788 plan_per_level: BTreeMap::new(),
789 }
790 }
791
792 fn get_current_applicable_column_requirements(
796 &self,
797 node: &LogicalPlan,
798 ) -> DfResult<BTreeMap<(Column, usize), BTreeSet<Column>>> {
799 let col_req_per_level = self
800 .column_requirements
801 .iter()
802 .filter(|(_, level)| *level >= self.cur_level)
803 .collect::<Vec<_>>();
804
805 let mut result_alias_mapping = BTreeMap::new();
808 let Some(child) = node.inputs().first().cloned() else {
809 return Ok(Default::default());
810 };
811 for (col_req, level) in col_req_per_level {
812 if let Some(original) = self.plan_per_level.get(level) {
813 let aliased_cols =
815 aliased_columns_for(&col_req.iter().cloned().collect(), node, Some(original))?;
816 for original_col in col_req {
817 let aliased_cols = aliased_cols.get(original_col).cloned();
818 if let Some(cols) = aliased_cols
819 && !cols.is_empty()
820 {
821 result_alias_mapping.insert((original_col.clone(), *level), cols);
822 } else {
823 let aliases_in_child = aliased_columns_for(
828 &[original_col.clone()].into(),
829 child,
830 Some(original),
831 )?;
832 let Some(aliases) = aliases_in_child
833 .get(original_col)
834 .cloned()
835 .filter(|a| !a.is_empty())
836 else {
837 return Err(datafusion_common::DataFusionError::Internal(format!(
838 "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}",
839 )));
840 };
841
842 result_alias_mapping.insert((original_col.clone(), *level), aliases);
843 }
844 }
845 }
846 }
847 Ok(result_alias_mapping)
848 }
849}
850
851impl TreeNodeRewriter for EnforceDistRequirementRewriter {
852 type Node = LogicalPlan;
853
854 fn f_down(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
855 if node.inputs().len() > 1 {
857 return Err(datafusion_common::DataFusionError::Internal(
858 "EnforceDistRequirementRewriter: node with multiple inputs is not supported"
859 .to_string(),
860 ));
861 }
862 self.plan_per_level.insert(self.cur_level, node.clone());
863 self.cur_level += 1;
864 Ok(Transformed::no(node))
865 }
866
867 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
868 self.cur_level -= 1;
869 if let LogicalPlan::Projection(ref projection) = node {
873 let mut applicable_column_requirements =
874 self.get_current_applicable_column_requirements(&node)?;
875
876 debug!(
877 "EnforceDistRequirementRewriter: applicable column requirements at level {} = {:?} for node {}",
878 self.cur_level,
879 applicable_column_requirements,
880 node.display()
881 );
882
883 for expr in &projection.expr {
884 let (qualifier, name) = expr.qualified_name();
885 let column = Column::new(qualifier, name);
886 applicable_column_requirements.retain(|_col_level, alias_set| {
887 !alias_set.contains(&column)
889 });
890 }
891 if applicable_column_requirements.is_empty() {
892 return Ok(Transformed::no(node));
893 }
894
895 let mut new_exprs = projection.expr.clone();
896 for (col, alias_set) in &applicable_column_requirements {
897 new_exprs.push(Expr::Column(alias_set.first().cloned().ok_or_else(
899 || {
900 datafusion_common::DataFusionError::Internal(
901 format!("EnforceDistRequirementRewriter: alias set is empty, for column {col:?} in node {node}"),
902 )
903 },
904 )?));
905 }
906 let new_node =
907 node.with_new_exprs(new_exprs, node.inputs().into_iter().cloned().collect())?;
908 debug!(
909 "EnforceDistRequirementRewriter: added missing columns {:?} to projection node from old node: \n{node}\n Making new node: \n{new_node}",
910 applicable_column_requirements
911 );
912
913 self.plan_per_level.insert(self.cur_level, new_node.clone());
915
916 return Ok(Transformed::yes(new_node));
918 }
919 Ok(Transformed::no(node))
920 }
921}
922
923impl TreeNodeRewriter for PlanRewriter {
924 type Node = LogicalPlan;
925
926 fn f_down<'a>(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
928 self.level += 1;
929 self.stack.push((node.clone(), self.level));
930 self.stage.clear();
932 self.set_unexpanded();
933 self.partition_cols = None;
934 Ok(Transformed::no(node))
935 }
936
937 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
941 if self.is_expanded() {
943 self.pop_stack();
944 return Ok(Transformed::no(node));
945 }
946
947 if node.inputs().is_empty() && !matches!(node, LogicalPlan::TableScan(_)) {
949 self.set_expanded();
950 self.pop_stack();
951 return Ok(Transformed::no(node));
952 }
953
954 self.maybe_set_partitions(&node)?;
955
956 let Some(parent) = self.get_parent() else {
957 debug!("Plan Rewriter: expand now for no parent found for node: {node}");
958 let node = self.expand(node);
959 debug!(
960 "PlanRewriter: expanded plan: {}",
961 match &node {
962 Ok(n) => n.to_string(),
963 Err(e) => format!("Error expanding plan: {e}"),
964 }
965 );
966 let node = node?;
967 self.pop_stack();
968 return Ok(Transformed::yes(node));
969 };
970
971 let parent = parent.clone();
972
973 if self.should_expand(&parent)? {
974 debug!(
976 "PlanRewriter: should expand child:\n {node}\n Of Parent: {}",
977 parent.display()
978 );
979 let node = self.expand(node);
980 debug!(
981 "PlanRewriter: expanded plan: {}",
982 match &node {
983 Ok(n) => n.to_string(),
984 Err(e) => format!("Error expanding plan: {e}"),
985 }
986 );
987 let node = node?;
988 self.pop_stack();
989 return Ok(Transformed::yes(node));
990 }
991
992 self.pop_stack();
993 Ok(Transformed::no(node))
994 }
995}