use nodedb_cluster::rpc_codec::TypedClusterError;
use nodedb_physical::physical_plan::{PhysicalPlan, QueryOp};
pub(super) const PLAN_DECODE_FAILED: u32 = nodedb_cluster::rpc_codec::PLAN_DECODE_FAILED;
pub(super) enum SinkOutcome {
CleanEnd,
CoordinatorGone,
StreamError(TypedClusterError),
}
pub(super) fn stream_error_to_typed(err: crate::Error) -> TypedClusterError {
let message = err.to_string();
let code = u32::from(nodedb_types::error::NodeDbError::from(err).code().0);
TypedClusterError::Internal { code, message }
}
pub(super) fn plan_contains_exchange(plan: &PhysicalPlan) -> bool {
match plan {
PhysicalPlan::Query(query_op) => match query_op {
QueryOp::Exchange(op) => plan_contains_exchange(&op.child),
QueryOp::HashJoin {
left_input,
right_input,
left_bitmap,
right_bitmap,
..
} => [left_input, right_input, left_bitmap, right_bitmap]
.into_iter()
.flatten()
.any(|child| plan_contains_exchange(child)),
QueryOp::LateralTopK { outer_plan, .. } => plan_contains_exchange(outer_plan),
QueryOp::LateralLoop { outer_plan, .. } => plan_contains_exchange(outer_plan),
QueryOp::Aggregate { input, .. } => {
input.as_deref().is_some_and(plan_contains_exchange)
}
QueryOp::ProviderScan { .. }
| QueryOp::PartialAggregate { .. }
| QueryOp::PartialAggregateState { .. }
| QueryOp::ShuffleJoinConsume { .. }
| QueryOp::ShuffleAggregateConsume { .. }
| QueryOp::NestedLoopJoin { .. }
| QueryOp::SortMergeJoin { .. }
| QueryOp::FacetCounts { .. }
| QueryOp::RecursiveScan { .. }
| QueryOp::RecursiveValue { .. } => false,
},
PhysicalPlan::Vector(_)
| PhysicalPlan::Graph(_)
| PhysicalPlan::Document(_)
| PhysicalPlan::Kv(_)
| PhysicalPlan::Text(_)
| PhysicalPlan::Columnar(_)
| PhysicalPlan::Timeseries(_)
| PhysicalPlan::Spatial(_)
| PhysicalPlan::Crdt(_)
| PhysicalPlan::Meta(_)
| PhysicalPlan::Array(_)
| PhysicalPlan::ClusterArray(_) => false,
}
}