Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions datafusion/physical-plan/src/limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,59 @@ impl ExecutionPlan for GlobalLimitExec {
fn supports_limit_pushdown(&self) -> bool {
true
}

#[cfg(feature = "proto")]
fn try_to_proto(
&self,
ctx: &crate::proto::ExecutionPlanEncodeCtx<'_>,
) -> Result<Option<datafusion_proto_models::protobuf::PhysicalPlanNode>> {
use datafusion_proto_models::protobuf;
let input = ctx.encode_child(self.input())?;
Ok(Some(protobuf::PhysicalPlanNode {
physical_plan_type: Some(
protobuf::physical_plan_node::PhysicalPlanType::GlobalLimit(Box::new(
protobuf::GlobalLimitExecNode {
input: Some(Box::new(input)),
skip: self.skip() as u32,
fetch: match self.fetch() {
Some(n) => n as i64,
_ => -1, // no limit
},
},
)),
),
}))
}
}

#[cfg(feature = "proto")]
impl GlobalLimitExec {
pub fn try_from_proto(
node: &datafusion_proto_models::protobuf::PhysicalPlanNode,
ctx: &crate::proto::ExecutionPlanDecodeCtx<'_>,
) -> Result<Arc<dyn ExecutionPlan>> {
use datafusion_proto_models::protobuf;
let limit = crate::expect_plan_variant!(
node,
protobuf::physical_plan_node::PhysicalPlanType::GlobalLimit,
"GlobalLimitExec",
);
let input = ctx.decode_required_child(
limit.input.as_deref(),
"GlobalLimitExec",
"input",
)?;
let fetch = if limit.fetch >= 0 {
Some(limit.fetch as usize)
} else {
None
};
Ok(Arc::new(GlobalLimitExec::new(
input,
limit.skip as usize,
fetch,
)))
}
}

/// LocalLimitExec applies a limit to a single partition
Expand Down Expand Up @@ -419,6 +472,43 @@ impl ExecutionPlan for LocalLimitExec {
fn cardinality_effect(&self) -> CardinalityEffect {
CardinalityEffect::LowerEqual
}

#[cfg(feature = "proto")]
fn try_to_proto(
&self,
ctx: &crate::proto::ExecutionPlanEncodeCtx<'_>,
) -> Result<Option<datafusion_proto_models::protobuf::PhysicalPlanNode>> {
use datafusion_proto_models::protobuf;
let input = ctx.encode_child(self.input())?;
Ok(Some(protobuf::PhysicalPlanNode {
physical_plan_type: Some(
protobuf::physical_plan_node::PhysicalPlanType::LocalLimit(Box::new(
protobuf::LocalLimitExecNode {
input: Some(Box::new(input)),
fetch: self.fetch() as u32,
},
)),
),
}))
}
}

#[cfg(feature = "proto")]
impl LocalLimitExec {
pub fn try_from_proto(
node: &datafusion_proto_models::protobuf::PhysicalPlanNode,
ctx: &crate::proto::ExecutionPlanDecodeCtx<'_>,
) -> Result<Arc<dyn ExecutionPlan>> {
use datafusion_proto_models::protobuf;
let limit = crate::expect_plan_variant!(
node,
protobuf::physical_plan_node::PhysicalPlanType::LocalLimit,
"LocalLimitExec",
);
let input =
ctx.decode_required_child(limit.input.as_deref(), "LocalLimitExec", "input")?;
Ok(Arc::new(LocalLimitExec::new(input, limit.fetch as usize)))
}
}

/// A Limit stream skips `skip` rows, and then fetch up to `fetch` rows.
Expand Down
112 changes: 52 additions & 60 deletions datafusion/proto/src/physical_plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,11 +793,11 @@ pub trait PhysicalPlanNodeExt: Sized {
PhysicalPlanType::Repartition(repart) => {
self.try_into_repartition_physical_plan(repart, ctx, proto_converter)
}
PhysicalPlanType::GlobalLimit(limit) => {
self.try_into_global_limit_physical_plan(limit, ctx, proto_converter)
PhysicalPlanType::GlobalLimit(_) => {
GlobalLimitExec::try_from_proto(self.node(), &decode_ctx)
}
PhysicalPlanType::LocalLimit(limit) => {
self.try_into_local_limit_physical_plan(limit, ctx, proto_converter)
PhysicalPlanType::LocalLimit(_) => {
LocalLimitExec::try_from_proto(self.node(), &decode_ctx)
}
PhysicalPlanType::Window(window_agg) => {
self.try_into_window_physical_plan(window_agg, ctx, proto_converter)
Expand Down Expand Up @@ -917,22 +917,6 @@ pub trait PhysicalPlanNodeExt: Sized {
);
}

if let Some(limit) = plan.downcast_ref::<GlobalLimitExec>() {
return protobuf::PhysicalPlanNode::try_from_global_limit_exec(
limit,
codec,
proto_converter,
);
}

if let Some(limit) = plan.downcast_ref::<LocalLimitExec>() {
return protobuf::PhysicalPlanNode::try_from_local_limit_exec(
limit,
codec,
proto_converter,
);
}

if let Some(exec) = plan.downcast_ref::<HashJoinExec>() {
return protobuf::PhysicalPlanNode::try_from_hash_join_exec(
exec,
Expand Down Expand Up @@ -1503,35 +1487,50 @@ pub trait PhysicalPlanNodeExt: Sized {
Ok(Arc::new(repart_exec))
}

#[deprecated(
since = "55.0.0",
note = "unused by DataFusion; `GlobalLimitExec` deserializes itself via `GlobalLimitExec::try_from_proto`"
)]
fn try_into_global_limit_physical_plan(
&self,
limit: &protobuf::GlobalLimitExecNode,
ctx: &PhysicalPlanDecodeContext<'_>,
proto_converter: &dyn PhysicalProtoConverterExtension,
) -> Result<Arc<dyn ExecutionPlan>> {
let input: Arc<dyn ExecutionPlan> =
into_physical_plan(&limit.input, ctx, proto_converter)?;
let fetch = if limit.fetch >= 0 {
Some(limit.fetch as usize)
} else {
None
let node = protobuf::PhysicalPlanNode {
physical_plan_type: Some(PhysicalPlanType::GlobalLimit(Box::new(
limit.clone(),
))),
};
Ok(Arc::new(GlobalLimitExec::new(
input,
limit.skip as usize,
fetch,
)))
let decoder = ConverterPlanDecoder {
ctx,
proto_converter,
};
let decode_ctx = ExecutionPlanDecodeCtx::new(&decoder);
GlobalLimitExec::try_from_proto(&node, &decode_ctx)
}

#[deprecated(
since = "55.0.0",
note = "unused by DataFusion; `LocalLimitExec` deserializes itself via `LocalLimitExec::try_from_proto`"
)]
fn try_into_local_limit_physical_plan(
&self,
limit: &protobuf::LocalLimitExecNode,
ctx: &PhysicalPlanDecodeContext<'_>,
proto_converter: &dyn PhysicalProtoConverterExtension,
) -> Result<Arc<dyn ExecutionPlan>> {
let input: Arc<dyn ExecutionPlan> =
into_physical_plan(&limit.input, ctx, proto_converter)?;
Ok(Arc::new(LocalLimitExec::new(input, limit.fetch as usize)))
let node = protobuf::PhysicalPlanNode {
physical_plan_type: Some(PhysicalPlanType::LocalLimit(Box::new(
limit.clone(),
))),
};
let decoder = ConverterPlanDecoder {
ctx,
proto_converter,
};
let decode_ctx = ExecutionPlanDecodeCtx::new(&decoder);
LocalLimitExec::try_from_proto(&node, &decode_ctx)
}

fn try_into_window_physical_plan(
Expand Down Expand Up @@ -2858,49 +2857,42 @@ pub trait PhysicalPlanNodeExt: Sized {
.ok_or_else(|| internal_datafusion_err!("FilterExec is not serializable"))
}

#[deprecated(
since = "55.0.0",
note = "unused by DataFusion; `GlobalLimitExec` serializes itself via `ExecutionPlan::try_to_proto`"
)]
fn try_from_global_limit_exec(
limit: &GlobalLimitExec,
codec: &dyn PhysicalExtensionCodec,
proto_converter: &dyn PhysicalProtoConverterExtension,
) -> Result<protobuf::PhysicalPlanNode> {
let input = protobuf::PhysicalPlanNode::try_from_physical_plan_with_converter(
limit.input().to_owned(),
let encoder = ConverterPlanEncoder {
codec,
proto_converter,
)?;

Ok(protobuf::PhysicalPlanNode {
physical_plan_type: Some(PhysicalPlanType::GlobalLimit(Box::new(
protobuf::GlobalLimitExecNode {
input: Some(Box::new(input)),
skip: limit.skip() as u32,
fetch: match limit.fetch() {
Some(n) => n as i64,
_ => -1, // no limit
},
},
))),
};
let encode_ctx = ExecutionPlanEncodeCtx::new(&encoder);
limit.try_to_proto(&encode_ctx)?.ok_or_else(|| {
internal_datafusion_err!("GlobalLimitExec is not serializable")
})
}

#[deprecated(
since = "55.0.0",
note = "unused by DataFusion; `LocalLimitExec` serializes itself via `ExecutionPlan::try_to_proto`"
)]
fn try_from_local_limit_exec(
limit: &LocalLimitExec,
codec: &dyn PhysicalExtensionCodec,
proto_converter: &dyn PhysicalProtoConverterExtension,
) -> Result<protobuf::PhysicalPlanNode> {
let input = protobuf::PhysicalPlanNode::try_from_physical_plan_with_converter(
limit.input().to_owned(),
let encoder = ConverterPlanEncoder {
codec,
proto_converter,
)?;
Ok(protobuf::PhysicalPlanNode {
physical_plan_type: Some(PhysicalPlanType::LocalLimit(Box::new(
protobuf::LocalLimitExecNode {
input: Some(Box::new(input)),
fetch: limit.fetch() as u32,
},
))),
})
};
let encode_ctx = ExecutionPlanEncodeCtx::new(&encoder);
limit
.try_to_proto(&encode_ctx)?
.ok_or_else(|| internal_datafusion_err!("LocalLimitExec is not serializable"))
}

fn try_from_hash_join_exec(
Expand Down
Loading