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 promql::extension_plan::SeriesDivide;
30use substrait::{DFLogicalSubstraitConvertor, SubstraitPlan};
31use table::metadata::TableType;
32use table::table::adapter::DfTableProviderAdapter;
33
34use crate::dist_plan::RemoteDynFilterProducerId;
35use crate::dist_plan::analyzer::utils::{
36 PatchOptimizerContext, PlanTreeExpressionSimplifier, aliased_columns_for,
37 rewrite_merge_sort_exprs,
38};
39use crate::dist_plan::commutativity::{
40 Categorizer, Commutativity, partial_commutative_transformer,
41};
42use crate::dist_plan::merge_scan::MergeScanLogicalPlan;
43use crate::dist_plan::merge_sort::MergeSortLogicalPlan;
44use crate::metrics::PUSH_DOWN_FALLBACK_ERRORS_TOTAL;
45use crate::plan::ExtractExpr;
46use crate::query_engine::DefaultSerializer;
47
48#[cfg(test)]
49mod test;
50
51mod fallback;
52pub(crate) mod utils;
53
54pub(crate) use utils::AliasMapping;
55
56const OTHER_PHY_PART_COL_PLACEHOLDER: &str = "__OTHER_PHYSICAL_PART_COLS_PLACEHOLDER__";
58
59#[derive(Debug, Clone)]
60pub struct DistPlannerOptions {
61 pub allow_query_fallback: bool,
62}
63
64impl ConfigExtension for DistPlannerOptions {
65 const PREFIX: &'static str = "dist_planner";
66}
67
68impl ExtensionOptions for DistPlannerOptions {
69 fn as_any(&self) -> &dyn std::any::Any {
70 self
71 }
72
73 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
74 self
75 }
76
77 fn cloned(&self) -> Box<dyn ExtensionOptions> {
78 Box::new(self.clone())
79 }
80
81 fn set(&mut self, key: &str, value: &str) -> DfResult<()> {
82 Err(datafusion_common::DataFusionError::NotImplemented(format!(
83 "DistPlannerOptions does not support set key: {key} with value: {value}"
84 )))
85 }
86
87 fn entries(&self) -> Vec<datafusion::config::ConfigEntry> {
88 vec![datafusion::config::ConfigEntry {
89 key: "allow_query_fallback".to_string(),
90 value: Some(self.allow_query_fallback.to_string()),
91 description: "Allow query fallback to fallback plan rewriter",
92 }]
93 }
94}
95
96#[derive(Debug)]
97pub struct DistPlannerAnalyzer;
98
99impl AnalyzerRule for DistPlannerAnalyzer {
100 fn name(&self) -> &str {
101 "DistPlannerAnalyzer"
102 }
103
104 fn analyze(
105 &self,
106 plan: LogicalPlan,
107 config: &ConfigOptions,
108 ) -> datafusion_common::Result<LogicalPlan> {
109 let mut config = config.clone();
110 config.optimizer.filter_null_join_keys = true;
112 let config = Arc::new(config);
113
114 let optimizer_context = PatchOptimizerContext {
115 inner: datafusion_optimizer::OptimizerContext::new(),
116 config: config.clone(),
117 };
118
119 let plan = plan
120 .rewrite_with_subqueries(&mut PlanTreeExpressionSimplifier::new(optimizer_context))?
121 .data;
122
123 let opt = config.extensions.get::<DistPlannerOptions>();
124 let allow_fallback = opt.map(|o| o.allow_query_fallback).unwrap_or(false);
125
126 let result = match self.try_push_down(plan.clone()) {
127 Ok(plan) => plan,
128 Err(err) => {
129 if allow_fallback {
130 common_telemetry::warn!(err; "Failed to push down plan, using fallback plan rewriter for plan: {plan}");
131 PUSH_DOWN_FALLBACK_ERRORS_TOTAL.inc();
133 self.use_fallback(plan)?
134 } else {
135 return Err(err);
136 }
137 }
138 };
139
140 Ok(result)
141 }
142}
143
144impl DistPlannerAnalyzer {
145 fn try_push_down(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
147 let plan = plan.transform(&Self::inspect_plan_with_subquery)?;
148 let mut rewriter = PlanRewriter::default();
149 let result = plan.data.rewrite(&mut rewriter)?.data;
150 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
151 }
152
153 fn use_fallback(&self, plan: LogicalPlan) -> DfResult<LogicalPlan> {
155 let mut rewriter = fallback::FallbackPlanRewriter;
156 let result = plan.rewrite(&mut rewriter)?.data;
157 Self::assign_merge_scan_remote_dyn_filter_producer_ids(result)
158 }
159
160 fn inspect_plan_with_subquery(plan: LogicalPlan) -> DfResult<Transformed<LogicalPlan>> {
161 if let LogicalPlan::Limit(_) | LogicalPlan::Distinct(_) = &plan {
164 return Ok(Transformed::no(plan));
165 }
166
167 let exprs = plan
168 .expressions_consider_join()
169 .into_iter()
170 .map(|e| e.transform(&Self::transform_subquery).map(|x| x.data))
171 .collect::<DfResult<Vec<_>>>()?;
172
173 if !matches!(plan, LogicalPlan::Unnest(_)) {
175 let inputs = plan.inputs().into_iter().cloned().collect::<Vec<_>>();
176 Ok(Transformed::yes(plan.with_new_exprs(exprs, inputs)?))
177 } else {
178 Ok(Transformed::no(plan))
179 }
180 }
181
182 fn transform_subquery(expr: Expr) -> DfResult<Transformed<Expr>> {
183 match expr {
184 Expr::Exists(exists) => Ok(Transformed::yes(Expr::Exists(Exists {
185 subquery: Self::handle_subquery(exists.subquery)?,
186 negated: exists.negated,
187 }))),
188 Expr::InSubquery(in_subquery) => Ok(Transformed::yes(Expr::InSubquery(InSubquery {
189 expr: in_subquery.expr,
190 subquery: Self::handle_subquery(in_subquery.subquery)?,
191 negated: in_subquery.negated,
192 }))),
193 Expr::ScalarSubquery(scalar_subquery) => Ok(Transformed::yes(Expr::ScalarSubquery(
194 Self::handle_subquery(scalar_subquery)?,
195 ))),
196
197 _ => Ok(Transformed::no(expr)),
198 }
199 }
200
201 fn handle_subquery(subquery: Subquery) -> DfResult<Subquery> {
202 let mut rewriter = PlanRewriter::default();
203 let mut rewrote_subquery = subquery
204 .subquery
205 .as_ref()
206 .clone()
207 .rewrite(&mut rewriter)?
208 .data;
209 if matches!(rewrote_subquery, LogicalPlan::Extension(_)) {
211 let output_schema = rewrote_subquery.schema().clone();
212 let project_exprs = output_schema
213 .fields()
214 .iter()
215 .map(|f| col_fn(f.name()))
216 .collect::<Vec<_>>();
217 rewrote_subquery = LogicalPlanBuilder::from(rewrote_subquery)
218 .project(project_exprs)?
219 .build()?;
220 }
221
222 Ok(Subquery {
223 subquery: Arc::new(rewrote_subquery),
224 outer_ref_columns: subquery.outer_ref_columns,
225 spans: Default::default(),
226 })
227 }
228
229 fn assign_merge_scan_remote_dyn_filter_producer_ids(
230 plan: LogicalPlan,
231 ) -> DfResult<LogicalPlan> {
232 let mut assigner = MergeScanRemoteDynFilterProducerIdAssigner::default();
233 Ok(plan.rewrite_with_subqueries(&mut assigner)?.data)
234 }
235}
236
237#[derive(Debug, Default)]
238struct RemoteDynFilterProducerIdAllocator {
239 next_remote_dyn_filter_producer_id: u64,
240}
241
242impl RemoteDynFilterProducerIdAllocator {
243 fn allocate(&mut self) -> RemoteDynFilterProducerId {
244 self.next_remote_dyn_filter_producer_id += 1;
245 RemoteDynFilterProducerId::new(self.next_remote_dyn_filter_producer_id)
246 }
247}
248
249#[derive(Debug, Default)]
251struct MergeScanRemoteDynFilterProducerIdAssigner {
252 remote_dyn_filter_producer_id_allocator: RemoteDynFilterProducerIdAllocator,
253}
254
255impl TreeNodeRewriter for MergeScanRemoteDynFilterProducerIdAssigner {
256 type Node = LogicalPlan;
257
258 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
259 let LogicalPlan::Extension(extension) = &node else {
260 return Ok(Transformed::no(node));
261 };
262 let Some(merge_scan) = extension
263 .node
264 .as_any()
265 .downcast_ref::<MergeScanLogicalPlan>()
266 else {
267 return Ok(Transformed::no(node));
268 };
269
270 Ok(Transformed::yes(
271 merge_scan
272 .clone()
273 .with_remote_dyn_filter_producer_id(
274 self.remote_dyn_filter_producer_id_allocator.allocate(),
275 )
276 .into_logical_plan(),
277 ))
278 }
279}
280
281#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
283enum RewriterStatus {
284 #[default]
285 Unexpanded,
286 Expanded,
287}
288
289#[derive(Debug, Default)]
290struct PlanRewriter {
291 level: usize,
293 stack: Vec<(LogicalPlan, usize)>,
295 stage: Vec<LogicalPlan>,
297 status: RewriterStatus,
298 partition_cols: Option<AliasMapping>,
300 column_requirements: Vec<(HashSet<Column>, usize)>,
326 expand_on_next_call: bool,
331 expand_on_next_part_cond_trans_commutative: bool,
343 new_child_plan: Option<LogicalPlan>,
344}
345
346impl PlanRewriter {
347 fn get_parent(&self) -> Option<&LogicalPlan> {
348 self.stack
350 .iter()
351 .rev()
352 .find(|(_, level)| *level == self.level - 1)
353 .map(|(node, _)| node)
354 }
355
356 fn should_expand(&mut self, plan: &LogicalPlan) -> DfResult<bool> {
358 debug!(
359 "Check should_expand at level: {} with Stack:\n{}, ",
360 self.level,
361 self.stack
362 .iter()
363 .map(|(p, l)| format!("{l}:{}{}", " ".repeat(l - 1), p.display()))
364 .collect::<Vec<String>>()
365 .join("\n"),
366 );
367 if let Err(e) = DFLogicalSubstraitConvertor.encode(plan, DefaultSerializer) {
368 debug!(
369 "PlanRewriter: plan cannot be converted to substrait with error={e:?}, expanding now: {plan}"
370 );
371 return Ok(true);
372 }
373
374 if self.expand_on_next_call {
375 self.expand_on_next_call = false;
376 debug!("PlanRewriter: expand_on_next_call is true, expanding now");
377 return Ok(true);
378 }
379
380 if self.expand_on_next_part_cond_trans_commutative {
381 let comm = Categorizer::check_plan(plan, self.partition_cols.clone())?;
382 match comm {
383 Commutativity::PartialCommutative => {
384 self.expand_on_next_part_cond_trans_commutative = false;
390 self.expand_on_next_call = true;
391 }
392 Commutativity::ConditionalCommutative(_)
393 | Commutativity::TransformedCommutative { .. } => {
394 self.expand_on_next_part_cond_trans_commutative = false;
397 debug!(
398 "PlanRewriter: meet a new conditional/transformed commutative plan, expanding now: {plan}"
399 );
400 return Ok(true);
401 }
402 _ => (),
403 }
404 }
405
406 match Categorizer::check_plan(plan, self.partition_cols.clone())? {
407 Commutativity::Commutative => {
408 if let LogicalPlan::Extension(ext_a) = plan
413 && ext_a.node.name() == SeriesDivide::name()
414 && let Some(LogicalPlan::Extension(ext_b)) = self.stage.last()
415 && ext_b.node.name() == MergeSortLogicalPlan::name()
416 {
417 self.stage.pop();
421 self.expand_on_next_part_cond_trans_commutative = false;
422 self.column_requirements.clear();
423 }
424 }
425 Commutativity::PartialCommutative => {
426 if let Some(plan) = partial_commutative_transformer(plan) {
427 self.update_column_requirements(&plan, self.level - 1);
429 self.expand_on_next_part_cond_trans_commutative = true;
430 self.stage.push(plan)
431 }
432 }
433 Commutativity::ConditionalCommutative(transformer) => {
434 if let Some(transformer) = transformer
435 && let Some(plan) = transformer(plan)
436 {
437 self.update_column_requirements(&plan, self.level - 1);
439 self.expand_on_next_part_cond_trans_commutative = true;
440 self.stage.push(plan)
441 }
442 }
443 Commutativity::TransformedCommutative { transformer } => {
444 if let Some(transformer) = transformer {
445 let transformer_actions = transformer(plan)?;
446 debug!(
447 "PlanRewriter: transformed plan: {}\n from {plan}",
448 transformer_actions
449 .extra_parent_plans
450 .iter()
451 .enumerate()
452 .map(|(i, p)| format!(
453 "Extra {i}-th parent plan from parent to child = {}",
454 p.display()
455 ))
456 .collect::<Vec<_>>()
457 .join("\n")
458 );
459 if let Some(new_child_plan) = &transformer_actions.new_child_plan {
460 debug!("PlanRewriter: new child plan: {}", new_child_plan);
461 }
462 if let Some(last_stage) = transformer_actions.extra_parent_plans.last() {
463 self.update_column_requirements(last_stage, self.level - 1);
466 }
467 self.stage
468 .extend(transformer_actions.extra_parent_plans.into_iter().rev());
469 self.expand_on_next_call = true;
470 self.new_child_plan = transformer_actions.new_child_plan;
471 }
472 }
473 Commutativity::NonCommutative
474 | Commutativity::Unimplemented
475 | Commutativity::Unsupported => {
476 debug!("PlanRewriter: meet a non-commutative plan, expanding now: {plan}");
477 return Ok(true);
478 }
479 }
480
481 Ok(false)
482 }
483
484 fn update_column_requirements(&mut self, plan: &LogicalPlan, plan_level: usize) {
488 debug!(
489 "PlanRewriter: update column requirements for plan: {plan}\n with old column_requirements: {:?}",
490 self.column_requirements
491 );
492 let mut container = HashSet::new();
493 for expr in plan.expressions() {
494 let _ = expr_to_columns(&expr, &mut container);
496 }
497
498 self.column_requirements.push((container, plan_level));
499 debug!(
500 "PlanRewriter: updated column requirements: {:?}",
501 self.column_requirements
502 );
503 }
504
505 fn is_expanded(&self) -> bool {
506 self.status == RewriterStatus::Expanded
507 }
508
509 fn set_expanded(&mut self) {
510 self.status = RewriterStatus::Expanded;
511 }
512
513 fn set_unexpanded(&mut self) {
514 self.status = RewriterStatus::Unexpanded;
515 }
516
517 fn maybe_set_partitions(&mut self, plan: &LogicalPlan) -> DfResult<()> {
518 if let Some(part_cols) = &mut self.partition_cols {
519 let child = plan.inputs().first().cloned().ok_or_else(|| {
521 datafusion_common::DataFusionError::Internal(format!(
522 "PlanRewriter: maybe_set_partitions: plan has no child: {plan}"
523 ))
524 })?;
525
526 for (_col_name, alias_set) in part_cols.iter_mut() {
527 let aliased_cols = aliased_columns_for(
528 &alias_set.clone().into_iter().collect(),
529 plan,
530 Some(child),
531 )?;
532 *alias_set = aliased_cols.into_values().flatten().collect();
533 }
534
535 debug!(
536 "PlanRewriter: maybe_set_partitions: updated partition columns: {:?} at plan: {}",
537 part_cols,
538 plan.display()
539 );
540
541 return Ok(());
542 }
543
544 if let LogicalPlan::TableScan(table_scan) = plan
545 && let Some(source) = table_scan
546 .source
547 .as_any()
548 .downcast_ref::<DefaultTableSource>()
549 && let Some(provider) = source
550 .table_provider
551 .as_any()
552 .downcast_ref::<DfTableProviderAdapter>()
553 {
554 let table = provider.table();
555 if table.table_type() == TableType::Base {
556 let info = table.table_info();
557 let partition_key_indices = info.meta.partition_key_indices.clone();
558 let schema = info.meta.schema.clone();
559 let mut partition_cols = partition_key_indices
560 .iter()
561 .map(|index| schema.column_name_by_index(*index).to_string())
562 .collect::<Vec<String>>();
563 debug!(
564 "PlanRewriter: loaded table partition metadata, table: {}, table_id: {}, partition_key_indices: {:?}, partition_columns: {:?}",
565 info.name, info.ident.table_id, info.meta.partition_key_indices, partition_cols,
566 );
567
568 let partition_rules = table.partition_rules();
569 let exist_phy_part_cols_not_in_logical_table = partition_rules
570 .map(|r| !r.extra_phy_cols_not_in_logical_table.is_empty())
571 .unwrap_or(false);
572
573 if exist_phy_part_cols_not_in_logical_table && partition_cols.is_empty() {
574 partition_cols.push(OTHER_PHY_PART_COL_PLACEHOLDER.to_string());
582 }
583 self.partition_cols = Some(
584 partition_cols
585 .into_iter()
586 .map(|c| {
587 if c == OTHER_PHY_PART_COL_PLACEHOLDER {
588 return Ok((c.clone(), BTreeSet::new()));
590 }
591 let index =
592 if let Some(c) = plan.schema().index_of_column_by_name(None, &c){
593 c
594 } else {
595 return Ok((c.clone(), BTreeSet::new()))
598 };
599 let column = plan.schema().columns().get(index).cloned().ok_or_else(|| {
600 datafusion_common::DataFusionError::Internal(format!(
601 "PlanRewriter: maybe_set_partitions: column index {index} out of bounds in schema of plan: {plan}"
602 ))
603 })?;
604 Ok((c.clone(), BTreeSet::from([column])))
605 })
606 .collect::<DfResult<AliasMapping>>()?,
607 );
608 }
609 }
610
611 Ok(())
612 }
613
614 fn pop_stack(&mut self) {
616 self.level -= 1;
617 self.stack.pop();
618 }
619
620 fn expand(&mut self, mut on_node: LogicalPlan) -> DfResult<LogicalPlan> {
621 let schema = on_node.schema().clone();
623 if let Some(new_child_plan) = self.new_child_plan.take() {
624 on_node = new_child_plan;
626 }
627 let mut rewriter = EnforceDistRequirementRewriter::new(
628 std::mem::take(&mut self.column_requirements),
629 self.level,
630 );
631 debug!(
632 "PlanRewriter: enforce column requirements for node: {on_node} with rewriter: {rewriter:?}"
633 );
634 on_node = on_node.rewrite(&mut rewriter)?.data;
635 debug!(
636 "PlanRewriter: after enforced column requirements with rewriter: {rewriter:?} for node:\n{on_node}"
637 );
638
639 debug!(
640 "PlanRewriter: expand on node: {on_node} with partition col alias mapping: {:?}",
641 self.partition_cols
642 );
643
644 let mut node = MergeScanLogicalPlan::new(
646 on_node.clone(),
647 false,
648 self.partition_cols.clone().unwrap_or_default(),
651 )
652 .into_logical_plan();
653
654 for new_stage in self.stage.drain(..) {
656 let new_stage = if let LogicalPlan::Extension(ext) = &new_stage
658 && let Some(merge_sort) = ext.node.as_any().downcast_ref::<MergeSortLogicalPlan>()
659 {
660 rewrite_merge_sort_exprs(merge_sort, &on_node)?
662 } else {
663 new_stage
664 };
665 node = new_stage
666 .with_new_exprs(new_stage.expressions_consider_join(), vec![node.clone()])?;
667 }
668 self.set_expanded();
669
670 let node = LogicalPlanBuilder::from(node)
673 .project(schema.iter().map(|(qualifier, field)| {
674 Expr::Column(Column::new(qualifier.cloned(), field.name()))
675 }))?
676 .build()?;
677
678 Ok(node)
679 }
680}
681
682#[derive(Debug)]
690struct EnforceDistRequirementRewriter {
691 column_requirements: Vec<(HashSet<Column>, usize)>,
695 cur_level: usize,
706 plan_per_level: BTreeMap<usize, LogicalPlan>,
707}
708
709impl EnforceDistRequirementRewriter {
710 fn new(column_requirements: Vec<(HashSet<Column>, usize)>, cur_level: usize) -> Self {
711 debug!(
712 "Create EnforceDistRequirementRewriter with column_requirements: {:?} at cur_level: {}",
713 column_requirements, cur_level
714 );
715 Self {
716 column_requirements,
717 cur_level,
718 plan_per_level: BTreeMap::new(),
719 }
720 }
721
722 fn get_current_applicable_column_requirements(
726 &self,
727 node: &LogicalPlan,
728 ) -> DfResult<BTreeMap<(Column, usize), BTreeSet<Column>>> {
729 let col_req_per_level = self
730 .column_requirements
731 .iter()
732 .filter(|(_, level)| *level >= self.cur_level)
733 .collect::<Vec<_>>();
734
735 let mut result_alias_mapping = BTreeMap::new();
738 let Some(child) = node.inputs().first().cloned() else {
739 return Ok(Default::default());
740 };
741 for (col_req, level) in col_req_per_level {
742 if let Some(original) = self.plan_per_level.get(level) {
743 let aliased_cols =
745 aliased_columns_for(&col_req.iter().cloned().collect(), node, Some(original))?;
746 for original_col in col_req {
747 let aliased_cols = aliased_cols.get(original_col).cloned();
748 if let Some(cols) = aliased_cols
749 && !cols.is_empty()
750 {
751 result_alias_mapping.insert((original_col.clone(), *level), cols);
752 } else {
753 let aliases_in_child = aliased_columns_for(
758 &[original_col.clone()].into(),
759 child,
760 Some(original),
761 )?;
762 let Some(aliases) = aliases_in_child
763 .get(original_col)
764 .cloned()
765 .filter(|a| !a.is_empty())
766 else {
767 return Err(datafusion_common::DataFusionError::Internal(format!(
768 "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}",
769 )));
770 };
771
772 result_alias_mapping.insert((original_col.clone(), *level), aliases);
773 }
774 }
775 }
776 }
777 Ok(result_alias_mapping)
778 }
779}
780
781impl TreeNodeRewriter for EnforceDistRequirementRewriter {
782 type Node = LogicalPlan;
783
784 fn f_down(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
785 if node.inputs().len() > 1 {
787 return Err(datafusion_common::DataFusionError::Internal(
788 "EnforceDistRequirementRewriter: node with multiple inputs is not supported"
789 .to_string(),
790 ));
791 }
792 self.plan_per_level.insert(self.cur_level, node.clone());
793 self.cur_level += 1;
794 Ok(Transformed::no(node))
795 }
796
797 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
798 self.cur_level -= 1;
799 if let LogicalPlan::Projection(ref projection) = node {
803 let mut applicable_column_requirements =
804 self.get_current_applicable_column_requirements(&node)?;
805
806 debug!(
807 "EnforceDistRequirementRewriter: applicable column requirements at level {} = {:?} for node {}",
808 self.cur_level,
809 applicable_column_requirements,
810 node.display()
811 );
812
813 for expr in &projection.expr {
814 let (qualifier, name) = expr.qualified_name();
815 let column = Column::new(qualifier, name);
816 applicable_column_requirements.retain(|_col_level, alias_set| {
817 !alias_set.contains(&column)
819 });
820 }
821 if applicable_column_requirements.is_empty() {
822 return Ok(Transformed::no(node));
823 }
824
825 let mut new_exprs = projection.expr.clone();
826 for (col, alias_set) in &applicable_column_requirements {
827 new_exprs.push(Expr::Column(alias_set.first().cloned().ok_or_else(
829 || {
830 datafusion_common::DataFusionError::Internal(
831 format!("EnforceDistRequirementRewriter: alias set is empty, for column {col:?} in node {node}"),
832 )
833 },
834 )?));
835 }
836 let new_node =
837 node.with_new_exprs(new_exprs, node.inputs().into_iter().cloned().collect())?;
838 debug!(
839 "EnforceDistRequirementRewriter: added missing columns {:?} to projection node from old node: \n{node}\n Making new node: \n{new_node}",
840 applicable_column_requirements
841 );
842
843 self.plan_per_level.insert(self.cur_level, new_node.clone());
845
846 return Ok(Transformed::yes(new_node));
848 }
849 Ok(Transformed::no(node))
850 }
851}
852
853impl TreeNodeRewriter for PlanRewriter {
854 type Node = LogicalPlan;
855
856 fn f_down<'a>(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
858 self.level += 1;
859 self.stack.push((node.clone(), self.level));
860 self.stage.clear();
862 self.set_unexpanded();
863 self.partition_cols = None;
864 Ok(Transformed::no(node))
865 }
866
867 fn f_up(&mut self, node: Self::Node) -> DfResult<Transformed<Self::Node>> {
871 if self.is_expanded() {
873 self.pop_stack();
874 return Ok(Transformed::no(node));
875 }
876
877 if node.inputs().is_empty() && !matches!(node, LogicalPlan::TableScan(_)) {
879 self.set_expanded();
880 self.pop_stack();
881 return Ok(Transformed::no(node));
882 }
883
884 self.maybe_set_partitions(&node)?;
885
886 let Some(parent) = self.get_parent() else {
887 debug!("Plan Rewriter: expand now for no parent found for node: {node}");
888 let node = self.expand(node);
889 debug!(
890 "PlanRewriter: expanded plan: {}",
891 match &node {
892 Ok(n) => n.to_string(),
893 Err(e) => format!("Error expanding plan: {e}"),
894 }
895 );
896 let node = node?;
897 self.pop_stack();
898 return Ok(Transformed::yes(node));
899 };
900
901 let parent = parent.clone();
902
903 if self.should_expand(&parent)? {
904 debug!(
906 "PlanRewriter: should expand child:\n {node}\n Of Parent: {}",
907 parent.display()
908 );
909 let node = self.expand(node);
910 debug!(
911 "PlanRewriter: expanded plan: {}",
912 match &node {
913 Ok(n) => n.to_string(),
914 Err(e) => format!("Error expanding plan: {e}"),
915 }
916 );
917 let node = node?;
918 self.pop_stack();
919 return Ok(Transformed::yes(node));
920 }
921
922 self.pop_stack();
923 Ok(Transformed::no(node))
924 }
925}