Skip to content
This repository was archived by the owner on Jan 7, 2025. It is now read-only.

Commit bd0dc0e

Browse files
authored
fix(df-bridge): enumerate join order for materialized plan (#213)
This fixes the adaptive demo in README b/c it needs to retrieve the join order. Signed-off-by: Alex Chi <[email protected]>
1 parent 61b6e49 commit bd0dc0e

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

Diff for: optd-adaptive-demo/src/bin/optd-adaptive-tpch-q8.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async fn main() -> Result<()> {
5454
};
5555

5656
exec_from_files(
57-
vec!["tpch/populate.sql".to_string()],
57+
vec!["datafusion-optd-cli/tpch-sf0_01/populate.sql".to_string()],
5858
&mut ctx,
5959
&slient_print_options,
6060
)

Diff for: optd-datafusion-bridge/src/lib.rs

+66-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use datafusion::{
1818
};
1919
use itertools::Itertools;
2020
use optd_datafusion_repr::{
21-
plan_nodes::{ConstantType, OptRelNode, PlanNode},
21+
plan_nodes::{
22+
ConstantType, OptRelNode, OptRelNodeRef, OptRelNodeTyp, PhysicalHashJoin,
23+
PhysicalNestedLoopJoin, PlanNode,
24+
},
2225
properties::schema::Catalog,
2326
DatafusionOptimizer, MemoExt,
2427
};
@@ -193,6 +196,17 @@ impl OptdQueryPlanner {
193196
},
194197
join_orders.iter().map(|x| x.to_string()).join("\n"),
195198
));
199+
let join_order = get_join_order(optimized_rel.clone());
200+
explains.push(StringifiedPlan::new(
201+
PlanType::OptimizedPhysicalPlan {
202+
optimizer_name: "optd-join-order".to_string(),
203+
},
204+
if let Some(join_order) = join_order {
205+
join_order.to_string()
206+
} else {
207+
"None".to_string()
208+
},
209+
));
196210
}
197211

198212
tracing::trace!(
@@ -241,3 +255,54 @@ impl QueryPlanner for OptdQueryPlanner {
241255
.unwrap())
242256
}
243257
}
258+
259+
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
260+
enum JoinOrder {
261+
Table(String),
262+
HashJoin(Box<Self>, Box<Self>),
263+
NestedLoopJoin(Box<Self>, Box<Self>),
264+
}
265+
266+
impl std::fmt::Display for JoinOrder {
267+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268+
match self {
269+
JoinOrder::Table(name) => write!(f, "{}", name),
270+
JoinOrder::HashJoin(left, right) => {
271+
write!(f, "(HashJoin {} {})", left, right)
272+
}
273+
JoinOrder::NestedLoopJoin(left, right) => {
274+
write!(f, "(NLJ {} {})", left, right)
275+
}
276+
}
277+
}
278+
}
279+
280+
fn get_join_order(rel_node: OptRelNodeRef) -> Option<JoinOrder> {
281+
match rel_node.typ {
282+
OptRelNodeTyp::PhysicalHashJoin(_) => {
283+
let join = PhysicalHashJoin::from_rel_node(rel_node.clone()).unwrap();
284+
let left = get_join_order(join.left().into_rel_node())?;
285+
let right = get_join_order(join.right().into_rel_node())?;
286+
Some(JoinOrder::HashJoin(Box::new(left), Box::new(right)))
287+
}
288+
OptRelNodeTyp::PhysicalNestedLoopJoin(_) => {
289+
let join = PhysicalNestedLoopJoin::from_rel_node(rel_node.clone()).unwrap();
290+
let left = get_join_order(join.left().into_rel_node())?;
291+
let right = get_join_order(join.right().into_rel_node())?;
292+
Some(JoinOrder::NestedLoopJoin(Box::new(left), Box::new(right)))
293+
}
294+
OptRelNodeTyp::PhysicalScan => {
295+
let scan =
296+
optd_datafusion_repr::plan_nodes::PhysicalScan::from_rel_node(rel_node).unwrap();
297+
Some(JoinOrder::Table(scan.table().to_string()))
298+
}
299+
_ => {
300+
for child in &rel_node.children {
301+
if let Some(res) = get_join_order(child.clone()) {
302+
return Some(res);
303+
}
304+
}
305+
None
306+
}
307+
}
308+
}

0 commit comments

Comments
 (0)