Skip to content

Commit

Permalink
fix transforming LogicalPlan::Explain use TreeNode::transform fai…
Browse files Browse the repository at this point in the history
…ls (apache#8400)

* fix transforming LogicalPlan::Explain use TreeNode::transform fails

* Update datafusion/expr/src/logical_plan/plan.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
  • Loading branch information
2 people authored and appletreeisyellow committed Dec 15, 2023
1 parent 61d8194 commit 8bbc7ff
Showing 1 changed file with 53 additions and 13 deletions.
66 changes: 53 additions & 13 deletions datafusion/expr/src/logical_plan/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,19 +877,19 @@ impl LogicalPlan {
input: Arc::new(inputs[0].clone()),
}))
}
LogicalPlan::Explain(_) => {
// Explain should be handled specially in the optimizers;
// If this check cannot pass it means some optimizer pass is
// trying to optimize Explain directly
if expr.is_empty() {
return plan_err!("Invalid EXPLAIN command. Expression is empty");
}

if inputs.is_empty() {
return plan_err!("Invalid EXPLAIN command. Inputs are empty");
}

Ok(self.clone())
LogicalPlan::Explain(e) => {
assert!(
expr.is_empty(),
"Invalid EXPLAIN command. Expression should empty"
);
assert_eq!(inputs.len(), 1, "Invalid EXPLAIN command. Inputs are empty");
Ok(LogicalPlan::Explain(Explain {
verbose: e.verbose,
plan: Arc::new(inputs[0].clone()),
stringified_plans: e.stringified_plans.clone(),
schema: e.schema.clone(),
logical_optimization_succeeded: e.logical_optimization_succeeded,
}))
}
LogicalPlan::Prepare(Prepare {
name, data_types, ..
Expand Down Expand Up @@ -3076,4 +3076,44 @@ digraph {
.unwrap()
.is_nullable());
}

#[test]
fn test_transform_explain() {
let schema = Schema::new(vec![
Field::new("foo", DataType::Int32, false),
Field::new("bar", DataType::Int32, false),
]);

let plan = table_scan(TableReference::none(), &schema, None)
.unwrap()
.explain(false, false)
.unwrap()
.build()
.unwrap();

let external_filter =
col("foo").eq(Expr::Literal(ScalarValue::Boolean(Some(true))));

// after transformation, because plan is not the same anymore,
// the parent plan is built again with call to LogicalPlan::with_new_inputs -> with_new_exprs
let plan = plan
.transform(&|plan| match plan {
LogicalPlan::TableScan(table) => {
let filter = Filter::try_new(
external_filter.clone(),
Arc::new(LogicalPlan::TableScan(table)),
)
.unwrap();
Ok(Transformed::Yes(LogicalPlan::Filter(filter)))
}
x => Ok(Transformed::No(x)),
})
.unwrap();

let expected = "Explain\
\n Filter: foo = Boolean(true)\
\n TableScan: ?table?";
let actual = format!("{}", plan.display_indent());
assert_eq!(expected.to_string(), actual)
}
}

0 comments on commit 8bbc7ff

Please sign in to comment.