use datafusion_common::tree_node::{TreeNode, VisitRecursion};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
num::NonZeroUsize,
};
use datafusion_expr::LogicalPlan;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct LogicalPlanSignature {
node_number: NonZeroUsize,
plan_hash: u64,
}
impl LogicalPlanSignature {
pub fn new(plan: &LogicalPlan) -> Self {
let mut hasher = DefaultHasher::new();
plan.hash(&mut hasher);
Self {
node_number: get_node_number(plan),
plan_hash: hasher.finish(),
}
}
}
fn get_node_number(plan: &LogicalPlan) -> NonZeroUsize {
let mut node_number = 0;
plan.apply(&mut |_plan| {
node_number += 1;
Ok(VisitRecursion::Continue)
})
.unwrap();
NonZeroUsize::new(node_number).unwrap()
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use datafusion_common::{DFSchema, Result};
use datafusion_expr::{self, lit, LogicalPlan};
use crate::plan_signature::get_node_number;
#[test]
fn node_number_for_some_plan() -> Result<()> {
let schema = Arc::new(DFSchema::empty());
let one_node_plan =
Arc::new(LogicalPlan::EmptyRelation(datafusion_expr::EmptyRelation {
produce_one_row: false,
schema: schema.clone(),
}));
assert_eq!(1, get_node_number(&one_node_plan).get());
let two_node_plan = Arc::new(LogicalPlan::Projection(
datafusion_expr::Projection::try_new(vec![lit(1), lit(2)], one_node_plan)?,
));
assert_eq!(2, get_node_number(&two_node_plan).get());
let five_node_plan = Arc::new(LogicalPlan::Union(datafusion_expr::Union {
inputs: vec![two_node_plan.clone(), two_node_plan],
schema,
}));
assert_eq!(5, get_node_number(&five_node_plan).get());
Ok(())
}
}