1use std::any::Any;
19use std::cell::RefCell;
20use std::collections::HashMap;
21use std::fmt::Debug;
22use std::sync::Arc;
23
24use arrow::datatypes::{IntervalMonthDayNanoType, Schema, SchemaRef};
25use datafusion_catalog::memory::MemorySourceConfig;
26use datafusion_common::{
27 DataFusionError, Result, internal_datafusion_err, internal_err, not_impl_err,
28};
29use datafusion_datasource_arrow::source::ArrowSource;
30#[cfg(feature = "avro")]
31use datafusion_datasource_avro::source::AvroSource;
32use datafusion_datasource_csv::file_format::CsvSink;
33use datafusion_datasource_csv::source::CsvSource;
34use datafusion_datasource_json::file_format::JsonSink;
35use datafusion_datasource_json::source::JsonSource;
36#[cfg(feature = "parquet")]
37use datafusion_datasource_parquet::file_format::ParquetSink;
38#[cfg(feature = "parquet")]
39use datafusion_datasource_parquet::source::ParquetSource;
40use datafusion_execution::{FunctionRegistry, TaskContext};
41use datafusion_expr::physical_planning_context::ScalarSubqueryResults;
42use datafusion_expr::{AggregateUDF, HigherOrderUDF, ScalarUDF, WindowUDF};
43use datafusion_functions_table::generate_series::{
44 Empty, GenSeriesArgs, GenerateSeriesTable, GenericSeriesState, TimestampValue,
45};
46use datafusion_physical_expr_common::physical_expr::proto_decode::PhysicalExprDecodeCtx;
47use datafusion_physical_expr_common::physical_expr::proto_encode::PhysicalExprEncodeCtx;
48use datafusion_physical_plan::aggregates::AggregateExec;
49use datafusion_physical_plan::analyze::AnalyzeExec;
50use datafusion_physical_plan::async_func::AsyncFuncExec;
51use datafusion_physical_plan::buffer::BufferExec;
52#[expect(
53 deprecated,
54 reason = "`CoalesceBatchesExec` remains supported for protobuf compatibility"
55)]
56use datafusion_physical_plan::coalesce_batches::CoalesceBatchesExec;
57use datafusion_physical_plan::coalesce_partitions::CoalescePartitionsExec;
58use datafusion_physical_plan::coop::CooperativeExec;
59use datafusion_physical_plan::empty::EmptyExec;
60use datafusion_physical_plan::explain::ExplainExec;
61use datafusion_physical_plan::filter::FilterExec;
62use datafusion_physical_plan::joins::{
63 CrossJoinExec, HashJoinExec, NestedLoopJoinExec, SortMergeJoinExec,
64 SymmetricHashJoinExec,
65};
66use datafusion_physical_plan::limit::{GlobalLimitExec, LocalLimitExec};
67use datafusion_physical_plan::memory::LazyMemoryExec;
68use datafusion_physical_plan::placeholder_row::PlaceholderRowExec;
69use datafusion_physical_plan::projection::ProjectionExec;
70use datafusion_physical_plan::proto::{
71 ExecutionPlanDecode, ExecutionPlanDecodeCtx, ExecutionPlanEncode,
72 ExecutionPlanEncodeCtx,
73};
74use datafusion_physical_plan::repartition::RepartitionExec;
75use datafusion_physical_plan::scalar_subquery::ScalarSubqueryExec;
76use datafusion_physical_plan::sorts::sort::SortExec;
77use datafusion_physical_plan::sorts::sort_preserving_merge::SortPreservingMergeExec;
78use datafusion_physical_plan::union::{InterleaveExec, UnionExec};
79use datafusion_physical_plan::unnest::UnnestExec;
80use datafusion_physical_plan::windows::WindowAggExec;
81use datafusion_physical_plan::{ExecutionPlan, PhysicalExpr};
82use prost::Message;
83use prost::bytes::BufMut;
84
85use crate::convert_required;
86use crate::physical_plan::from_proto::parse_physical_expr_with_converter;
87use crate::physical_plan::to_proto::serialize_physical_expr_with_converter;
88use crate::protobuf::physical_plan_node::PhysicalPlanType;
89use crate::protobuf::{self, proto_error};
90
91pub mod from_proto;
92pub mod to_proto;
93
94const HUMAN_DISPLAY_ALIAS_PREFIX: &str = "\u{1f}datafusion_human_display_alias_v1:";
95
96fn encode_human_display_alias(human_display: &str, alias: &str) -> String {
97 format!(
98 "{HUMAN_DISPLAY_ALIAS_PREFIX}{}:{alias}{human_display}",
99 alias.len()
100 )
101}
102
103#[cfg(test)]
104mod file_scan_config_serde {
105 use super::*;
106 use arrow::datatypes::{DataType, Field};
107 use datafusion_common::{Constraint, Constraints, ScalarValue, Statistics};
108 use datafusion_datasource::file::FileSource;
109 use datafusion_datasource::file_groups::FileGroup;
110 use datafusion_datasource::file_scan_config::{
111 FileScanConfig, FileScanConfigBuilder,
112 };
113 use datafusion_datasource::file_stream::FileOpener;
114 use datafusion_datasource::{PartitionedFile, TableSchema};
115 use datafusion_execution::object_store::ObjectStoreUrl;
116 use datafusion_physical_expr::expressions::Column;
117 use datafusion_physical_expr::projection::{
118 ProjectionExpr as FileProjectionExpr, ProjectionExprs as FileProjectionExprs,
119 };
120 use datafusion_physical_expr::{
121 LexOrdering, Partitioning, PhysicalSortExpr, RangePartitioning, SplitPoint,
122 };
123 use datafusion_physical_plan::metrics::ExecutionPlanMetricsSet;
124 use object_store::ObjectStore;
125
126 #[derive(Clone)]
127 struct SerdeTestSource {
128 metrics: ExecutionPlanMetricsSet,
129 table_schema: TableSchema,
130 projection: Option<FileProjectionExprs>,
131 }
132
133 impl SerdeTestSource {
134 fn new(
135 table_schema: TableSchema,
136 projection: Option<FileProjectionExprs>,
137 ) -> Self {
138 Self {
139 metrics: ExecutionPlanMetricsSet::new(),
140 table_schema,
141 projection,
142 }
143 }
144 }
145
146 impl FileSource for SerdeTestSource {
147 fn create_file_opener(
148 &self,
149 _object_store: Arc<dyn ObjectStore>,
150 _base_config: &FileScanConfig,
151 _partition: usize,
152 ) -> Result<Arc<dyn FileOpener>> {
153 internal_err!("not needed for FileScanConfig serde tests")
154 }
155
156 fn table_schema(&self) -> &TableSchema {
157 &self.table_schema
158 }
159
160 fn with_batch_size(&self, _batch_size: usize) -> Arc<dyn FileSource> {
161 Arc::new(self.clone())
162 }
163
164 fn metrics(&self) -> &ExecutionPlanMetricsSet {
165 &self.metrics
166 }
167
168 fn file_type(&self) -> &str {
169 "serde-test"
170 }
171
172 fn apply_expressions(
173 &self,
174 f: &mut dyn FnMut(
175 &Arc<dyn PhysicalExpr>,
176 )
177 -> Result<datafusion_common::tree_node::TreeNodeRecursion>,
178 ) -> Result<datafusion_common::tree_node::TreeNodeRecursion> {
179 datafusion_physical_plan::apply_expression_roots(
180 self.projection.iter().flatten(),
181 f,
182 )
183 }
184
185 fn try_pushdown_projection(
186 &self,
187 projection: &FileProjectionExprs,
188 ) -> Result<Option<Arc<dyn FileSource>>> {
189 Ok(Some(Arc::new(Self {
190 projection: Some(projection.clone()),
191 ..self.clone()
192 })))
193 }
194
195 fn projection(&self) -> Option<&FileProjectionExprs> {
196 self.projection.as_ref()
197 }
198 }
199
200 fn populated_projection() -> FileProjectionExprs {
201 FileProjectionExprs::new(vec![FileProjectionExpr::new(
202 Arc::new(Column::new("value", 0)),
203 "projected_value",
204 )])
205 }
206
207 fn test_config(output_partitioning: Option<Partitioning>) -> FileScanConfig {
208 test_config_with_projection(output_partitioning, Some(populated_projection()))
209 }
210
211 fn test_config_with_projection(
212 output_partitioning: Option<Partitioning>,
213 projection: Option<FileProjectionExprs>,
214 ) -> FileScanConfig {
215 let file_schema = Arc::new(
216 Schema::new(vec![
217 Field::new("value", DataType::Int32, false),
218 Field::new("label", DataType::Utf8, true),
219 ])
220 .with_metadata(HashMap::from([(
221 "serde_test_key".to_string(),
222 "serde_test_value".to_string(),
223 )])),
224 );
225 let table_schema = TableSchema::builder(Arc::clone(&file_schema))
226 .with_table_partition_cols(vec![Arc::new(Field::new(
227 "part",
228 DataType::Utf8,
229 false,
230 ))])
231 .build();
232 let table_statistics = Statistics::new_unknown(table_schema.table_schema());
233 let source = Arc::new(SerdeTestSource::new(table_schema, projection));
234 let first_file = PartitionedFile::new("data/part=a/file.arrow", 1024)
235 .with_partition_values(vec![ScalarValue::Utf8(Some("a".to_string()))])
236 .with_range(10, 900)
237 .with_arrow_schema(Arc::clone(&file_schema))
238 .with_statistics(Arc::new(table_statistics.clone()));
239 let second_file = PartitionedFile::new("data/part=b/file.arrow", 2048)
240 .with_partition_values(vec![ScalarValue::Utf8(Some("b".to_string()))]);
241 let third_file = PartitionedFile::new("data/part=c/file.arrow", 4096)
242 .with_partition_values(vec![ScalarValue::Utf8(Some("c".to_string()))])
243 .with_arrow_schema(Arc::clone(&file_schema));
244 let ordering = LexOrdering::new(vec![PhysicalSortExpr::new_default(Arc::new(
245 Column::new("value", 0),
246 ))])
247 .expect("single expression ordering");
248
249 FileScanConfigBuilder::new(ObjectStoreUrl::local_filesystem(), source)
250 .with_file_groups(vec![
251 FileGroup::new(vec![first_file, second_file]),
252 FileGroup::new(vec![third_file]),
253 ])
254 .with_constraints(Constraints::new_unverified(vec![Constraint::PrimaryKey(
255 vec![0],
256 )]))
257 .with_statistics(table_statistics)
258 .with_limit(Some(17))
259 .with_batch_size(Some(256))
260 .with_output_ordering(vec![ordering])
261 .with_output_partitioning(output_partitioning)
262 .build()
263 }
264
265 fn hash_partitioning() -> Partitioning {
266 Partitioning::Hash(vec![Arc::new(Column::new("value", 0))], 3)
267 }
268
269 fn range_partitioning() -> Partitioning {
270 let ordering = LexOrdering::new(vec![PhysicalSortExpr::new_default(Arc::new(
271 Column::new("value", 0),
272 ))])
273 .expect("single expression ordering");
274 Partitioning::Range(RangePartitioning::new(
275 ordering,
276 vec![SplitPoint::new(vec![ScalarValue::Int32(Some(10))])],
277 ))
278 }
279
280 fn decode_source(conf: &protobuf::FileScanExecConf) -> Result<Arc<dyn FileSource>> {
281 Ok(Arc::new(SerdeTestSource::new(
282 FileScanConfig::parse_table_schema_from_proto(conf)?,
283 None,
284 )))
285 }
286
287 struct FileScanSerdeHarness {
288 codec: DefaultPhysicalExtensionCodec,
289 converter: DefaultPhysicalProtoConverter,
290 task_ctx: TaskContext,
291 }
292
293 impl FileScanSerdeHarness {
294 fn new() -> Self {
295 Self {
296 codec: DefaultPhysicalExtensionCodec {},
297 converter: DefaultPhysicalProtoConverter {},
298 task_ctx: TaskContext::default(),
299 }
300 }
301
302 fn encode(&self, config: &FileScanConfig) -> Result<protobuf::FileScanExecConf> {
303 let encoder = ConverterPlanEncoder {
304 codec: &self.codec,
305 proto_converter: &self.converter,
306 };
307 config.try_to_proto(&ExecutionPlanEncodeCtx::new(&encoder))
308 }
309
310 fn decode(&self, conf: &protobuf::FileScanExecConf) -> Result<FileScanConfig> {
311 self.decode_with_source(conf, decode_source(conf)?)
312 }
313
314 fn decode_with_source(
315 &self,
316 conf: &protobuf::FileScanExecConf,
317 file_source: Arc<dyn FileSource>,
318 ) -> Result<FileScanConfig> {
319 let physical_decode_ctx =
320 PhysicalPlanDecodeContext::new(&self.task_ctx, &self.codec);
321 let decoder = ConverterPlanDecoder {
322 ctx: &physical_decode_ctx,
323 proto_converter: &self.converter,
324 };
325 FileScanConfig::try_from_proto(
326 conf,
327 &ExecutionPlanDecodeCtx::new(&decoder),
328 file_source,
329 )
330 }
331 }
332
333 #[test]
334 fn new_file_scan_config_serde_roundtrips_all_partitioning_variants() -> Result<()> {
335 let serde = FileScanSerdeHarness::new();
336
337 for config in [
338 test_config(None),
339 test_config(Some(Partitioning::RoundRobinBatch(2))),
340 test_config(Some(hash_partitioning())),
341 test_config(Some(range_partitioning())),
342 test_config(Some(Partitioning::UnknownPartitioning(4))),
343 ] {
344 let encoded = serde.encode(&config)?;
345 let reencoded = serde.encode(&serde.decode(&encoded)?)?;
346 assert_eq!(reencoded.output_partitioning, encoded.output_partitioning);
347 }
348
349 Ok(())
350 }
351
352 #[test]
353 fn new_file_scan_config_serde_preserves_complete_fixture() -> Result<()> {
354 let serde = FileScanSerdeHarness::new();
355 let config = test_config(None);
356 let decoded = serde.decode(&serde.encode(&config)?)?;
357
358 assert_eq!(decoded.constraints, config.constraints);
359 assert_eq!(
360 decoded.file_schema().metadata,
361 config.file_schema().metadata
362 );
363 assert_eq!(decoded.file_groups.len(), 2);
364 assert_eq!(decoded.file_groups[0].len(), 2);
365 assert_eq!(decoded.file_groups[1].len(), 1);
366 assert!(decoded.file_groups[0].files()[0].arrow_schema.is_some());
367 assert!(decoded.file_groups[0].files()[1].arrow_schema.is_none());
368
369 Ok(())
370 }
371
372 #[test]
373 fn new_file_scan_config_serde_preserves_projection_presence() -> Result<()> {
374 let serde = FileScanSerdeHarness::new();
375
376 let absent = serde.encode(&test_config_with_projection(None, None))?;
377 assert!(absent.projection_exprs.is_none());
378 assert!(serde.decode(&absent)?.file_source().projection().is_none());
379
380 let empty = serde.encode(&test_config_with_projection(
381 None,
382 Some(FileProjectionExprs::new(vec![])),
383 ))?;
384 assert!(
385 empty
386 .projection_exprs
387 .as_ref()
388 .is_some_and(|projection| projection.projections.is_empty())
389 );
390 assert!(
391 serde
392 .decode(&empty)?
393 .file_source()
394 .projection()
395 .is_some_and(|projection| projection.as_ref().is_empty())
396 );
397
398 Ok(())
399 }
400
401 #[test]
402 fn new_file_scan_config_decode_rejects_malformed_required_fields() -> Result<()> {
403 let serde = FileScanSerdeHarness::new();
404 let valid = serde.encode(&test_config(None))?;
405 let file_source = decode_source(&valid)?;
406
407 for (field, malformed) in [
408 (
409 "schema",
410 protobuf::FileScanExecConf {
411 schema: None,
412 ..valid.clone()
413 },
414 ),
415 (
416 "constraints",
417 protobuf::FileScanExecConf {
418 constraints: None,
419 ..valid.clone()
420 },
421 ),
422 (
423 "statistics",
424 protobuf::FileScanExecConf {
425 statistics: None,
426 ..valid.clone()
427 },
428 ),
429 ] {
430 let err = serde
431 .decode_with_source(&malformed, Arc::clone(&file_source))
432 .expect_err("missing required field must fail");
433 assert!(err.to_string().contains(field), "unexpected error: {err}");
434 }
435
436 let mut missing_projection_expr = valid.clone();
437 missing_projection_expr
438 .projection_exprs
439 .as_mut()
440 .expect("test config has projection expressions")
441 .projections[0]
442 .expr = None;
443 let err = serde
444 .decode_with_source(&missing_projection_expr, file_source)
445 .expect_err("missing projection expression must fail");
446 assert!(
447 err.to_string()
448 .contains("ProjectionExpr missing expr field"),
449 "unexpected error: {err}"
450 );
451
452 Ok(())
453 }
454
455 #[test]
456 fn new_file_scan_config_decode_rejects_invalid_range_ordering() -> Result<()> {
457 let serde = FileScanSerdeHarness::new();
458 let mut proto = serde.encode(&test_config(Some(range_partitioning())))?;
459
460 let mut duplicate_ordering = proto.clone();
461 let range = match duplicate_ordering
462 .output_partitioning
463 .as_mut()
464 .and_then(|p| p.partition_method.as_mut())
465 {
466 Some(protobuf::partitioning::PartitionMethod::Range(range)) => range,
467 other => panic!("expected range partitioning, got {other:?}"),
468 };
469 range.sort_expr.push(range.sort_expr[0].clone());
470
471 let err = serde
472 .decode(&duplicate_ordering)
473 .expect_err("duplicate range ordering must fail");
474 assert!(
475 err.to_string().contains("duplicate expressions"),
476 "unexpected error: {err}"
477 );
478
479 let range = match proto
480 .output_partitioning
481 .as_mut()
482 .and_then(|p| p.partition_method.as_mut())
483 {
484 Some(protobuf::partitioning::PartitionMethod::Range(range)) => range,
485 other => panic!("expected range partitioning, got {other:?}"),
486 };
487 range.sort_expr.clear();
488
489 let err = serde
490 .decode(&proto)
491 .expect_err("empty range ordering must fail");
492 assert!(
493 err.to_string().contains("requires non-empty ordering"),
494 "unexpected error: {err}"
495 );
496
497 Ok(())
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::*;
504
505 mod function_serde {
513 use super::*;
514 use arrow::datatypes::{DataType, Field, FieldRef};
515 use datafusion_common::plan_err;
516 use datafusion_execution::config::SessionConfig;
517 use datafusion_execution::runtime_env::RuntimeEnv;
518 use datafusion_expr::function::AccumulatorArgs;
519 use datafusion_expr::{
520 Accumulator, AggregateUDFImpl, ColumnarValue, PartitionEvaluator,
521 ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility, WindowUDFImpl,
522 };
523 use datafusion_functions_window_common::field::WindowUDFFieldArgs;
524 use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
525
526 #[derive(Debug, PartialEq, Eq, Hash)]
527 struct TestUdf {
528 signature: Signature,
529 }
530
531 impl TestUdf {
532 fn new() -> Self {
533 Self {
534 signature: Signature::exact(
535 vec![DataType::Int64],
536 Volatility::Immutable,
537 ),
538 }
539 }
540 }
541
542 impl ScalarUDFImpl for TestUdf {
543 fn name(&self) -> &str {
544 "test_udf"
545 }
546 fn signature(&self) -> &Signature {
547 &self.signature
548 }
549 fn return_type(&self, _args: &[DataType]) -> Result<DataType> {
550 Ok(DataType::Int64)
551 }
552 fn invoke_with_args(
553 &self,
554 _args: ScalarFunctionArgs,
555 ) -> Result<ColumnarValue> {
556 plan_err!("test only")
557 }
558 }
559
560 #[derive(Debug, PartialEq, Eq, Hash)]
561 struct TestUdaf {
562 signature: Signature,
563 }
564
565 impl TestUdaf {
566 fn new() -> Self {
567 Self {
568 signature: Signature::exact(
569 vec![DataType::Int64],
570 Volatility::Immutable,
571 ),
572 }
573 }
574 }
575
576 impl AggregateUDFImpl for TestUdaf {
577 fn name(&self) -> &str {
578 "test_udaf"
579 }
580 fn signature(&self) -> &Signature {
581 &self.signature
582 }
583 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
584 Ok(DataType::Int64)
585 }
586 fn accumulator(
587 &self,
588 _acc_args: AccumulatorArgs,
589 ) -> Result<Box<dyn Accumulator>> {
590 plan_err!("test only")
591 }
592 }
593
594 #[derive(Debug, PartialEq, Eq, Hash)]
595 struct TestUdwf {
596 signature: Signature,
597 }
598
599 impl TestUdwf {
600 fn new() -> Self {
601 Self {
602 signature: Signature::exact(
603 vec![DataType::Int64],
604 Volatility::Immutable,
605 ),
606 }
607 }
608 }
609
610 impl WindowUDFImpl for TestUdwf {
611 fn name(&self) -> &str {
612 "test_udwf"
613 }
614 fn signature(&self) -> &Signature {
615 &self.signature
616 }
617 fn partition_evaluator(
618 &self,
619 _partition_evaluator_args: PartitionEvaluatorArgs,
620 ) -> Result<Box<dyn PartitionEvaluator>> {
621 plan_err!("test only")
622 }
623 fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
624 Ok(Field::new(field_args.name(), DataType::Int64, true).into())
625 }
626 }
627
628 #[derive(Debug)]
632 struct PayloadCodec;
633
634 impl PhysicalExtensionCodec for PayloadCodec {
635 fn try_decode(
636 &self,
637 _buf: &[u8],
638 _inputs: &[Arc<dyn ExecutionPlan>],
639 _ctx: &TaskContext,
640 _proto_converter: &dyn PhysicalProtoConverterExtension,
641 ) -> Result<Arc<dyn ExecutionPlan>> {
642 internal_err!("not needed for these tests")
643 }
644
645 fn try_encode(
646 &self,
647 _node: Arc<dyn ExecutionPlan>,
648 _buf: &mut Vec<u8>,
649 _proto_converter: &dyn PhysicalProtoConverterExtension,
650 ) -> Result<()> {
651 internal_err!("not needed for these tests")
652 }
653
654 fn try_encode_udf(&self, node: &ScalarUDF, buf: &mut Vec<u8>) -> Result<()> {
655 buf.extend_from_slice(node.name().as_bytes());
656 Ok(())
657 }
658
659 fn try_decode_udf(&self, name: &str, buf: &[u8]) -> Result<Arc<ScalarUDF>> {
660 assert_eq!(name, "test_udf");
661 assert_eq!(buf, name.as_bytes());
662 Ok(Arc::new(ScalarUDF::from(TestUdf::new())))
663 }
664
665 fn try_encode_udaf(
666 &self,
667 node: &AggregateUDF,
668 buf: &mut Vec<u8>,
669 ) -> Result<()> {
670 buf.extend_from_slice(node.name().as_bytes());
671 Ok(())
672 }
673
674 fn try_decode_udaf(
675 &self,
676 name: &str,
677 buf: &[u8],
678 ) -> Result<Arc<AggregateUDF>> {
679 assert_eq!(name, "test_udaf");
680 assert_eq!(buf, name.as_bytes());
681 Ok(Arc::new(AggregateUDF::from(TestUdaf::new())))
682 }
683
684 fn try_encode_udwf(&self, node: &WindowUDF, buf: &mut Vec<u8>) -> Result<()> {
685 buf.extend_from_slice(node.name().as_bytes());
686 Ok(())
687 }
688
689 fn try_decode_udwf(&self, name: &str, buf: &[u8]) -> Result<Arc<WindowUDF>> {
690 assert_eq!(name, "test_udwf");
691 assert_eq!(buf, name.as_bytes());
692 Ok(Arc::new(WindowUDF::from(TestUdwf::new())))
693 }
694 }
695
696 #[derive(Debug)]
699 struct EmptyPayloadOnlyCodec;
700
701 impl PhysicalExtensionCodec for EmptyPayloadOnlyCodec {
702 fn try_decode(
703 &self,
704 _buf: &[u8],
705 _inputs: &[Arc<dyn ExecutionPlan>],
706 _ctx: &TaskContext,
707 _proto_converter: &dyn PhysicalProtoConverterExtension,
708 ) -> Result<Arc<dyn ExecutionPlan>> {
709 internal_err!("not needed for these tests")
710 }
711
712 fn try_encode(
713 &self,
714 _node: Arc<dyn ExecutionPlan>,
715 _buf: &mut Vec<u8>,
716 _proto_converter: &dyn PhysicalProtoConverterExtension,
717 ) -> Result<()> {
718 internal_err!("not needed for these tests")
719 }
720
721 fn try_decode_udf(&self, _name: &str, buf: &[u8]) -> Result<Arc<ScalarUDF>> {
722 assert!(buf.is_empty());
723 Ok(Arc::new(ScalarUDF::from(TestUdf::new())))
724 }
725
726 fn try_decode_udaf(
727 &self,
728 _name: &str,
729 buf: &[u8],
730 ) -> Result<Arc<AggregateUDF>> {
731 assert!(buf.is_empty());
732 Ok(Arc::new(AggregateUDF::from(TestUdaf::new())))
733 }
734
735 fn try_decode_udwf(&self, _name: &str, buf: &[u8]) -> Result<Arc<WindowUDF>> {
736 assert!(buf.is_empty());
737 Ok(Arc::new(WindowUDF::from(TestUdwf::new())))
738 }
739 }
740
741 fn encode_ctx_over<'a>(
742 codec: &'a dyn PhysicalExtensionCodec,
743 proto_converter: &'a dyn PhysicalProtoConverterExtension,
744 ) -> ConverterPlanEncoder<'a> {
745 ConverterPlanEncoder {
746 codec,
747 proto_converter,
748 }
749 }
750
751 #[test]
752 fn encode_by_name_functions_produce_no_payload() -> Result<()> {
753 let codec = DefaultPhysicalExtensionCodec {};
754 let converter = DefaultPhysicalProtoConverter {};
755 let encoder = encode_ctx_over(&codec, &converter);
756 let ctx = ExecutionPlanEncodeCtx::new(&encoder);
757
758 assert!(ctx.encode_udf(&ScalarUDF::from(TestUdf::new()))?.is_none());
759 assert!(
760 ctx.encode_udaf(&AggregateUDF::from(TestUdaf::new()))?
761 .is_none()
762 );
763 assert!(
764 ctx.encode_udwf(&WindowUDF::from(TestUdwf::new()))?
765 .is_none()
766 );
767 Ok(())
768 }
769
770 #[test]
771 fn encode_functions_surface_codec_payload() -> Result<()> {
772 let codec = PayloadCodec;
773 let converter = DefaultPhysicalProtoConverter {};
774 let encoder = encode_ctx_over(&codec, &converter);
775 let ctx = ExecutionPlanEncodeCtx::new(&encoder);
776
777 assert_eq!(
778 ctx.encode_udf(&ScalarUDF::from(TestUdf::new()))?.as_deref(),
779 Some(b"test_udf".as_slice())
780 );
781 assert_eq!(
782 ctx.encode_udaf(&AggregateUDF::from(TestUdaf::new()))?
783 .as_deref(),
784 Some(b"test_udaf".as_slice())
785 );
786 assert_eq!(
787 ctx.encode_udwf(&WindowUDF::from(TestUdwf::new()))?
788 .as_deref(),
789 Some(b"test_udwf".as_slice())
790 );
791 Ok(())
792 }
793
794 #[test]
795 fn decode_functions_prefer_explicit_payload() -> Result<()> {
796 let task_ctx = TaskContext::default();
797 let codec = PayloadCodec;
798 let decode_context = PhysicalPlanDecodeContext::new(&task_ctx, &codec);
799 let converter = DefaultPhysicalProtoConverter {};
800 let decoder = ConverterPlanDecoder {
801 ctx: &decode_context,
802 proto_converter: &converter,
803 };
804 let ctx = ExecutionPlanDecodeCtx::new(&decoder);
805
806 assert_eq!(
807 ctx.decode_udf("test_udf", Some(b"test_udf"))?.name(),
808 "test_udf"
809 );
810 assert_eq!(
811 ctx.decode_udaf("test_udaf", Some(b"test_udaf"))?.name(),
812 "test_udaf"
813 );
814 assert_eq!(
815 ctx.decode_udwf("test_udwf", Some(b"test_udwf"))?.name(),
816 "test_udwf"
817 );
818 Ok(())
819 }
820
821 #[test]
822 fn decode_functions_by_name_resolve_from_registry() -> Result<()> {
823 let udf = Arc::new(ScalarUDF::from(TestUdf::new()));
824 let udaf = Arc::new(AggregateUDF::from(TestUdaf::new()));
825 let udwf = Arc::new(WindowUDF::from(TestUdwf::new()));
826 let task_ctx = TaskContext::new(
827 None,
828 "test".to_string(),
829 SessionConfig::new(),
830 HashMap::from([("test_udf".to_string(), Arc::clone(&udf))]),
831 HashMap::new(),
832 HashMap::from([("test_udaf".to_string(), Arc::clone(&udaf))]),
833 HashMap::from([("test_udwf".to_string(), Arc::clone(&udwf))]),
834 Arc::new(RuntimeEnv::default()),
835 );
836 let codec = DefaultPhysicalExtensionCodec {};
839 let decode_context = PhysicalPlanDecodeContext::new(&task_ctx, &codec);
840 let converter = DefaultPhysicalProtoConverter {};
841 let decoder = ConverterPlanDecoder {
842 ctx: &decode_context,
843 proto_converter: &converter,
844 };
845 let ctx = ExecutionPlanDecodeCtx::new(&decoder);
846
847 assert!(Arc::ptr_eq(&ctx.decode_udf("test_udf", None)?, &udf));
848 assert!(Arc::ptr_eq(&ctx.decode_udaf("test_udaf", None)?, &udaf));
849 assert!(Arc::ptr_eq(&ctx.decode_udwf("test_udwf", None)?, &udwf));
850 assert_eq!(ctx.task_ctx().session_id(), "test");
851 Ok(())
852 }
853
854 #[test]
855 fn decode_functions_by_name_fall_back_to_codec_on_registry_miss() -> Result<()> {
856 let task_ctx = TaskContext::default();
857 let codec = EmptyPayloadOnlyCodec;
858 let decode_context = PhysicalPlanDecodeContext::new(&task_ctx, &codec);
859 let converter = DefaultPhysicalProtoConverter {};
860 let decoder = ConverterPlanDecoder {
861 ctx: &decode_context,
862 proto_converter: &converter,
863 };
864 let ctx = ExecutionPlanDecodeCtx::new(&decoder);
865
866 assert_eq!(ctx.decode_udf("test_udf", None)?.name(), "test_udf");
867 assert_eq!(ctx.decode_udaf("test_udaf", None)?.name(), "test_udaf");
868 assert_eq!(ctx.decode_udwf("test_udwf", None)?.name(), "test_udwf");
869 Ok(())
870 }
871
872 #[test]
873 fn decode_required_helpers_error_on_missing_fields() {
874 let task_ctx = TaskContext::default();
875 let codec = DefaultPhysicalExtensionCodec {};
876 let decode_context = PhysicalPlanDecodeContext::new(&task_ctx, &codec);
877 let converter = DefaultPhysicalProtoConverter {};
878 let decoder = ConverterPlanDecoder {
879 ctx: &decode_context,
880 proto_converter: &converter,
881 };
882 let ctx = ExecutionPlanDecodeCtx::new(&decoder);
883
884 let err = ctx
885 .decode_required_child(None, "FooExec", "input")
886 .unwrap_err();
887 assert!(
888 err.to_string()
889 .contains("FooExec is missing required field 'input'"),
890 "unexpected error: {err}"
891 );
892
893 let schema = Schema::empty();
894 let err = ctx
895 .decode_required_expr(None, &schema, "FooExec", "predicate")
896 .unwrap_err();
897 assert!(
898 err.to_string()
899 .contains("FooExec is missing required field 'predicate'"),
900 "unexpected error: {err}"
901 );
902 }
903
904 #[test]
905 fn try_from_proto_rejects_wrong_plan_variant() {
906 let task_ctx = TaskContext::default();
907 let codec = DefaultPhysicalExtensionCodec {};
908 let decode_context = PhysicalPlanDecodeContext::new(&task_ctx, &codec);
909 let converter = DefaultPhysicalProtoConverter {};
910 let decoder = ConverterPlanDecoder {
911 ctx: &decode_context,
912 proto_converter: &converter,
913 };
914 let ctx = ExecutionPlanDecodeCtx::new(&decoder);
915
916 let node = protobuf::PhysicalPlanNode {
917 physical_plan_type: None,
918 };
919 let err = ProjectionExec::try_from_proto(&node, &ctx).unwrap_err();
920 assert!(
921 err.to_string()
922 .contains("PhysicalPlanNode is not a ProjectionExec"),
923 "unexpected error: {err}"
924 );
925 }
926 }
927}
928
929#[derive(Clone)]
935pub struct PhysicalPlanDecodeContext<'a> {
936 task_ctx: &'a TaskContext,
937 codec: &'a dyn PhysicalExtensionCodec,
938 scalar_subquery_results: Option<ScalarSubqueryResults>,
939}
940
941impl<'a> PhysicalPlanDecodeContext<'a> {
942 pub fn new(task_ctx: &'a TaskContext, codec: &'a dyn PhysicalExtensionCodec) -> Self {
944 Self {
945 task_ctx,
946 codec,
947 scalar_subquery_results: None,
948 }
949 }
950
951 pub fn task_ctx(&self) -> &'a TaskContext {
953 self.task_ctx
954 }
955
956 pub fn codec(&self) -> &'a dyn PhysicalExtensionCodec {
958 self.codec
959 }
960
961 pub fn scalar_subquery_results(&self) -> Option<&ScalarSubqueryResults> {
964 self.scalar_subquery_results.as_ref()
965 }
966
967 pub fn with_scalar_subquery_results(
970 &self,
971 scalar_subquery_results: ScalarSubqueryResults,
972 ) -> Self {
973 Self {
974 task_ctx: self.task_ctx,
975 codec: self.codec,
976 scalar_subquery_results: Some(scalar_subquery_results),
977 }
978 }
979}
980
981impl AsExecutionPlan for protobuf::PhysicalPlanNode {
982 fn try_decode(buf: &[u8]) -> Result<Self>
983 where
984 Self: Sized,
985 {
986 protobuf::PhysicalPlanNode::decode(buf).map_err(|e| {
987 internal_datafusion_err!("failed to decode physical plan: {e:?}")
988 })
989 }
990
991 fn try_encode<B>(&self, buf: &mut B) -> Result<()>
992 where
993 B: BufMut,
994 Self: Sized,
995 {
996 self.encode(buf).map_err(|e| {
997 internal_datafusion_err!("failed to encode physical plan: {e:?}")
998 })
999 }
1000
1001 fn try_into_physical_plan(
1002 &self,
1003 ctx: &TaskContext,
1004 codec: &dyn PhysicalExtensionCodec,
1005 ) -> Result<Arc<dyn ExecutionPlan>> {
1006 self.try_into_physical_plan_with_converter(
1007 ctx,
1008 codec,
1009 &DefaultPhysicalProtoConverter {},
1010 )
1011 }
1012
1013 fn try_from_physical_plan(
1014 plan: Arc<dyn ExecutionPlan>,
1015 codec: &dyn PhysicalExtensionCodec,
1016 ) -> Result<Self>
1017 where
1018 Self: Sized,
1019 {
1020 Self::try_from_physical_plan_with_converter(
1021 plan,
1022 codec,
1023 &DefaultPhysicalProtoConverter {},
1024 )
1025 }
1026}
1027
1028pub trait PhysicalPlanNodeExt: Sized {
1042 fn node(&self) -> &protobuf::PhysicalPlanNode;
1044
1045 fn try_into_physical_plan_with_converter(
1046 &self,
1047 ctx: &TaskContext,
1048 codec: &dyn PhysicalExtensionCodec,
1049 proto_converter: &dyn PhysicalProtoConverterExtension,
1050 ) -> Result<Arc<dyn ExecutionPlan>> {
1051 let decode_ctx = PhysicalPlanDecodeContext::new(ctx, codec);
1052 self.try_into_physical_plan_with_context(&decode_ctx, proto_converter)
1053 }
1054
1055 fn try_into_physical_plan_with_context(
1056 &self,
1057 ctx: &PhysicalPlanDecodeContext<'_>,
1058 proto_converter: &dyn PhysicalProtoConverterExtension,
1059 ) -> Result<Arc<dyn ExecutionPlan>> {
1060 let plan = self.node().physical_plan_type.as_ref().ok_or_else(|| {
1061 proto_error(format!(
1062 "physical_plan::from_proto() Unsupported physical plan '{:?}'",
1063 self.node(),
1064 ))
1065 })?;
1066 let plan_decoder = ConverterPlanDecoder {
1070 ctx,
1071 proto_converter,
1072 };
1073 let decode_ctx = ExecutionPlanDecodeCtx::new(&plan_decoder);
1074 match plan {
1075 PhysicalPlanType::Explain(_) => {
1076 ExplainExec::try_from_proto(self.node(), &decode_ctx)
1077 }
1078 PhysicalPlanType::Projection(_) => {
1079 ProjectionExec::try_from_proto(self.node(), &decode_ctx)
1080 }
1081 PhysicalPlanType::Filter(_) => {
1082 FilterExec::try_from_proto(self.node(), &decode_ctx)
1083 }
1084 PhysicalPlanType::CsvScan(_) => {
1085 CsvSource::try_from_proto(self.node(), &decode_ctx)
1086 }
1087 PhysicalPlanType::JsonScan(_) => {
1088 JsonSource::try_from_proto(self.node(), &decode_ctx)
1089 }
1090 PhysicalPlanType::ParquetScan(_) => {
1091 #[cfg(feature = "parquet")]
1092 {
1093 ParquetSource::try_from_proto(self.node(), &decode_ctx)
1094 }
1095 #[cfg(not(feature = "parquet"))]
1096 not_impl_err!(
1097 "Unable to process a Parquet PhysicalPlan when the `parquet` feature is not enabled"
1098 )
1099 }
1100 PhysicalPlanType::AvroScan(_) => {
1101 #[cfg(feature = "avro")]
1102 {
1103 AvroSource::try_from_proto(self.node(), &decode_ctx)
1104 }
1105 #[cfg(not(feature = "avro"))]
1106 panic!(
1107 "Unable to process a Avro PhysicalPlan when `avro` feature is not enabled"
1108 )
1109 }
1110 PhysicalPlanType::MemoryScan(_) => {
1111 MemorySourceConfig::try_from_proto(self.node(), &decode_ctx)
1112 }
1113 PhysicalPlanType::ArrowScan(_) => {
1114 ArrowSource::try_from_proto(self.node(), &decode_ctx)
1115 }
1116 #[expect(
1117 deprecated,
1118 reason = "`CoalesceBatchesExec` remains supported for protobuf compatibility"
1119 )]
1120 PhysicalPlanType::CoalesceBatches(_) => {
1121 CoalesceBatchesExec::try_from_proto(self.node(), &decode_ctx)
1122 }
1123 PhysicalPlanType::Merge(_) => {
1124 CoalescePartitionsExec::try_from_proto(self.node(), &decode_ctx)
1125 }
1126 PhysicalPlanType::Repartition(_) => {
1127 RepartitionExec::try_from_proto(self.node(), &decode_ctx)
1128 }
1129 PhysicalPlanType::GlobalLimit(_) => {
1130 GlobalLimitExec::try_from_proto(self.node(), &decode_ctx)
1131 }
1132 PhysicalPlanType::LocalLimit(_) => {
1133 LocalLimitExec::try_from_proto(self.node(), &decode_ctx)
1134 }
1135 PhysicalPlanType::Window(_) => {
1136 WindowAggExec::try_from_proto(self.node(), &decode_ctx)
1137 }
1138 PhysicalPlanType::Aggregate(_) => {
1139 AggregateExec::try_from_proto(self.node(), &decode_ctx)
1140 }
1141 PhysicalPlanType::HashJoin(_) => {
1142 HashJoinExec::try_from_proto(self.node(), &decode_ctx)
1143 }
1144 PhysicalPlanType::SymmetricHashJoin(_) => {
1145 SymmetricHashJoinExec::try_from_proto(self.node(), &decode_ctx)
1146 }
1147 PhysicalPlanType::Union(_) => {
1148 UnionExec::try_from_proto(self.node(), &decode_ctx)
1149 }
1150 PhysicalPlanType::Interleave(_) => {
1151 InterleaveExec::try_from_proto(self.node(), &decode_ctx)
1152 }
1153 PhysicalPlanType::CrossJoin(_) => {
1154 CrossJoinExec::try_from_proto(self.node(), &decode_ctx)
1155 }
1156 PhysicalPlanType::Empty(_) => {
1157 EmptyExec::try_from_proto(self.node(), &decode_ctx)
1158 }
1159 PhysicalPlanType::PlaceholderRow(_) => {
1160 PlaceholderRowExec::try_from_proto(self.node(), &decode_ctx)
1161 }
1162 PhysicalPlanType::Sort(_) => {
1163 SortExec::try_from_proto(self.node(), &decode_ctx)
1164 }
1165 PhysicalPlanType::SortPreservingMerge(_) => {
1166 SortPreservingMergeExec::try_from_proto(self.node(), &decode_ctx)
1167 }
1168 PhysicalPlanType::Extension(extension) => {
1169 self.try_into_extension_physical_plan(extension, ctx, proto_converter)
1170 }
1171 PhysicalPlanType::NestedLoopJoin(_) => {
1172 NestedLoopJoinExec::try_from_proto(self.node(), &decode_ctx)
1173 }
1174 PhysicalPlanType::Analyze(_) => {
1175 AnalyzeExec::try_from_proto(self.node(), &decode_ctx)
1176 }
1177 PhysicalPlanType::JsonSink(_) => {
1178 JsonSink::try_from_proto(self.node(), &decode_ctx)
1179 }
1180 PhysicalPlanType::CsvSink(_) => {
1181 CsvSink::try_from_proto(self.node(), &decode_ctx)
1182 }
1183 PhysicalPlanType::ParquetSink(_) => {
1184 #[cfg(feature = "parquet")]
1185 {
1186 ParquetSink::try_from_proto(self.node(), &decode_ctx)
1187 }
1188 #[cfg(not(feature = "parquet"))]
1189 not_impl_err!("ParquetSink requires the `parquet` feature")
1190 }
1191 PhysicalPlanType::Unnest(_) => {
1192 UnnestExec::try_from_proto(self.node(), &decode_ctx)
1193 }
1194 PhysicalPlanType::Cooperative(_) => {
1195 CooperativeExec::try_from_proto(self.node(), &decode_ctx)
1196 }
1197 PhysicalPlanType::GenerateSeries(generate_series) => {
1198 self.try_into_generate_series_physical_plan(generate_series)
1199 }
1200 PhysicalPlanType::SortMergeJoin(_) => {
1201 SortMergeJoinExec::try_from_proto(self.node(), &decode_ctx)
1202 }
1203 PhysicalPlanType::AsyncFunc(_) => {
1204 AsyncFuncExec::try_from_proto(self.node(), &decode_ctx)
1205 }
1206 PhysicalPlanType::Buffer(_) => {
1207 BufferExec::try_from_proto(self.node(), &decode_ctx)
1208 }
1209 PhysicalPlanType::ScalarSubquery(_) => {
1210 ScalarSubqueryExec::try_from_proto(self.node(), &decode_ctx)
1211 }
1212 }
1213 }
1214
1215 fn try_from_physical_plan_with_converter(
1216 plan: Arc<dyn ExecutionPlan>,
1217 codec: &dyn PhysicalExtensionCodec,
1218 proto_converter: &dyn PhysicalProtoConverterExtension,
1219 ) -> Result<protobuf::PhysicalPlanNode> {
1220 let plan_clone = Arc::clone(&plan);
1221 let mut plan = plan.as_ref();
1222 while let Some(delegate) = plan.downcast_delegate() {
1228 plan = delegate;
1229 }
1230
1231 let encoder = ConverterPlanEncoder {
1235 codec,
1236 proto_converter,
1237 };
1238 let encode_ctx = ExecutionPlanEncodeCtx::new(&encoder);
1239 if let Some(node) = plan.try_to_proto(&encode_ctx)? {
1240 return Ok(node);
1241 }
1242
1243 if let Some(exec) = plan.downcast_ref::<LazyMemoryExec>()
1244 && let Some(node) =
1245 protobuf::PhysicalPlanNode::try_from_lazy_memory_exec(exec)?
1246 {
1247 return Ok(node);
1248 }
1249
1250 let mut buf: Vec<u8> = vec![];
1251 match codec.try_encode(Arc::clone(&plan_clone), &mut buf, proto_converter) {
1252 Ok(_) => {
1253 let inputs: Vec<protobuf::PhysicalPlanNode> = plan_clone
1254 .children()
1255 .into_iter()
1256 .cloned()
1257 .map(|i| {
1258 protobuf::PhysicalPlanNode::try_from_physical_plan_with_converter(
1259 i,
1260 codec,
1261 proto_converter,
1262 )
1263 })
1264 .collect::<Result<_>>()?;
1265
1266 Ok(protobuf::PhysicalPlanNode {
1267 physical_plan_type: Some(PhysicalPlanType::Extension(
1268 protobuf::PhysicalExtensionNode { node: buf, inputs },
1269 )),
1270 })
1271 }
1272 Err(e) => internal_err!(
1273 "Unsupported plan and extension codec failed with [{e}]. Plan: {plan_clone:?}"
1274 ),
1275 }
1276 }
1277
1278 fn try_into_extension_physical_plan(
1279 &self,
1280 extension: &protobuf::PhysicalExtensionNode,
1281 ctx: &PhysicalPlanDecodeContext<'_>,
1282 proto_converter: &dyn PhysicalProtoConverterExtension,
1283 ) -> Result<Arc<dyn ExecutionPlan>> {
1284 let inputs: Vec<Arc<dyn ExecutionPlan>> = extension
1285 .inputs
1286 .iter()
1287 .map(|i| proto_converter.proto_to_execution_plan(i, ctx))
1288 .collect::<Result<_>>()?;
1289
1290 let extension_node = ctx.codec().try_decode(
1291 extension.node.as_slice(),
1292 &inputs,
1293 ctx.task_ctx(),
1294 proto_converter,
1295 )?;
1296
1297 Ok(extension_node)
1298 }
1299
1300 fn generate_series_name_to_str(name: protobuf::GenerateSeriesName) -> &'static str {
1301 match name {
1302 protobuf::GenerateSeriesName::GsGenerateSeries => "generate_series",
1303 protobuf::GenerateSeriesName::GsRange => "range",
1304 }
1305 }
1306
1307 fn try_into_generate_series_physical_plan(
1308 &self,
1309 generate_series: &protobuf::GenerateSeriesNode,
1310 ) -> Result<Arc<dyn ExecutionPlan>> {
1311 let schema: SchemaRef = Arc::new(convert_required!(generate_series.schema)?);
1312
1313 let args = match &generate_series.args {
1314 Some(protobuf::generate_series_node::Args::ContainsNull(args)) => {
1315 GenSeriesArgs::ContainsNull {
1316 name: protobuf::PhysicalPlanNode::generate_series_name_to_str(
1317 args.name(),
1318 ),
1319 }
1320 }
1321 Some(protobuf::generate_series_node::Args::Int64Args(args)) => {
1322 GenSeriesArgs::Int64Args {
1323 start: args.start,
1324 end: args.end,
1325 step: args.step,
1326 include_end: args.include_end,
1327 name: protobuf::PhysicalPlanNode::generate_series_name_to_str(
1328 args.name(),
1329 ),
1330 }
1331 }
1332 Some(protobuf::generate_series_node::Args::TimestampArgs(args)) => {
1333 let step_proto = args.step.as_ref().ok_or_else(|| {
1334 internal_datafusion_err!("Missing step in TimestampArgs")
1335 })?;
1336 let step = IntervalMonthDayNanoType::make_value(
1337 step_proto.months,
1338 step_proto.days,
1339 step_proto.nanos,
1340 );
1341 GenSeriesArgs::TimestampArgs {
1342 start: args.start,
1343 end: args.end,
1344 step,
1345 tz: args.tz.as_ref().map(|s| Arc::from(s.as_str())),
1346 include_end: args.include_end,
1347 name: protobuf::PhysicalPlanNode::generate_series_name_to_str(
1348 args.name(),
1349 ),
1350 }
1351 }
1352 Some(protobuf::generate_series_node::Args::DateArgs(args)) => {
1353 let step_proto = args.step.as_ref().ok_or_else(|| {
1354 internal_datafusion_err!("Missing step in DateArgs")
1355 })?;
1356 let step = IntervalMonthDayNanoType::make_value(
1357 step_proto.months,
1358 step_proto.days,
1359 step_proto.nanos,
1360 );
1361 GenSeriesArgs::DateArgs {
1362 start: args.start,
1363 end: args.end,
1364 step,
1365 include_end: args.include_end,
1366 name: protobuf::PhysicalPlanNode::generate_series_name_to_str(
1367 args.name(),
1368 ),
1369 }
1370 }
1371 None => return internal_err!("Missing args in GenerateSeriesNode"),
1372 };
1373
1374 let table = GenerateSeriesTable::new(Arc::clone(&schema), args);
1375 let generator = table.as_generator(generate_series.target_batch_size as usize)?;
1376
1377 Ok(Arc::new(LazyMemoryExec::try_new(schema, vec![generator])?))
1378 }
1379
1380 fn str_to_generate_series_name(name: &str) -> Result<protobuf::GenerateSeriesName> {
1381 match name {
1382 "generate_series" => Ok(protobuf::GenerateSeriesName::GsGenerateSeries),
1383 "range" => Ok(protobuf::GenerateSeriesName::GsRange),
1384 _ => internal_err!("unknown name: {name}"),
1385 }
1386 }
1387
1388 fn try_from_lazy_memory_exec(
1389 exec: &LazyMemoryExec,
1390 ) -> Result<Option<protobuf::PhysicalPlanNode>> {
1391 let generators = exec.generators();
1392
1393 let [generator] = generators.as_slice() else {
1395 return Ok(None);
1396 };
1397
1398 let generator_guard = generator.read();
1399
1400 if let Some(empty_gen) = generator_guard.as_any().downcast_ref::<Empty>() {
1402 let schema = exec.schema();
1403 let node = protobuf::GenerateSeriesNode {
1404 schema: Some(schema.as_ref().try_into()?),
1405 target_batch_size: 8192, args: Some(protobuf::generate_series_node::Args::ContainsNull(
1407 protobuf::GenerateSeriesArgsContainsNull {
1408 name: protobuf::PhysicalPlanNode::str_to_generate_series_name(
1409 empty_gen.name(),
1410 )? as i32,
1411 },
1412 )),
1413 };
1414
1415 return Ok(Some(protobuf::PhysicalPlanNode {
1416 physical_plan_type: Some(PhysicalPlanType::GenerateSeries(node)),
1417 }));
1418 }
1419
1420 if let Some(int_64) = generator_guard
1421 .as_any()
1422 .downcast_ref::<GenericSeriesState<i64>>()
1423 {
1424 let schema = exec.schema();
1425 let node = protobuf::GenerateSeriesNode {
1426 schema: Some(schema.as_ref().try_into()?),
1427 target_batch_size: int_64.batch_size() as u32,
1428 args: Some(protobuf::generate_series_node::Args::Int64Args(
1429 protobuf::GenerateSeriesArgsInt64 {
1430 start: *int_64.start(),
1431 end: *int_64.end(),
1432 step: *int_64.step(),
1433 include_end: int_64.include_end(),
1434 name: protobuf::PhysicalPlanNode::str_to_generate_series_name(
1435 int_64.name(),
1436 )? as i32,
1437 },
1438 )),
1439 };
1440
1441 return Ok(Some(protobuf::PhysicalPlanNode {
1442 physical_plan_type: Some(PhysicalPlanType::GenerateSeries(node)),
1443 }));
1444 }
1445
1446 if let Some(timestamp_args) = generator_guard
1447 .as_any()
1448 .downcast_ref::<GenericSeriesState<TimestampValue>>()
1449 {
1450 let schema = exec.schema();
1451
1452 let start = timestamp_args.start().value();
1453 let end = timestamp_args.end().value();
1454
1455 let step_value = timestamp_args.step();
1456
1457 let step = Some(datafusion_proto_common::IntervalMonthDayNanoValue {
1458 months: step_value.months,
1459 days: step_value.days,
1460 nanos: step_value.nanoseconds,
1461 });
1462 let include_end = timestamp_args.include_end();
1463 let name = protobuf::PhysicalPlanNode::str_to_generate_series_name(
1464 timestamp_args.name(),
1465 )? as i32;
1466
1467 let args = match timestamp_args.current().tz_str() {
1468 Some(tz) => protobuf::generate_series_node::Args::TimestampArgs(
1469 protobuf::GenerateSeriesArgsTimestamp {
1470 start,
1471 end,
1472 step,
1473 include_end,
1474 name,
1475 tz: Some(tz.to_string()),
1476 },
1477 ),
1478 None => protobuf::generate_series_node::Args::DateArgs(
1479 protobuf::GenerateSeriesArgsDate {
1480 start,
1481 end,
1482 step,
1483 include_end,
1484 name,
1485 },
1486 ),
1487 };
1488
1489 let node = protobuf::GenerateSeriesNode {
1490 schema: Some(schema.as_ref().try_into()?),
1491 target_batch_size: timestamp_args.batch_size() as u32,
1492 args: Some(args),
1493 };
1494
1495 return Ok(Some(protobuf::PhysicalPlanNode {
1496 physical_plan_type: Some(PhysicalPlanType::GenerateSeries(node)),
1497 }));
1498 }
1499
1500 Ok(None)
1501 }
1502}
1503
1504impl PhysicalPlanNodeExt for protobuf::PhysicalPlanNode {
1505 fn node(&self) -> &protobuf::PhysicalPlanNode {
1506 self
1507 }
1508}
1509
1510pub trait AsExecutionPlan: Debug + Send + Sync + Clone {
1511 fn try_decode(buf: &[u8]) -> Result<Self>
1512 where
1513 Self: Sized;
1514
1515 fn try_encode<B>(&self, buf: &mut B) -> Result<()>
1516 where
1517 B: BufMut,
1518 Self: Sized;
1519
1520 fn try_into_physical_plan(
1521 &self,
1522 ctx: &TaskContext,
1523
1524 codec: &dyn PhysicalExtensionCodec,
1525 ) -> Result<Arc<dyn ExecutionPlan>>;
1526
1527 fn try_from_physical_plan(
1528 plan: Arc<dyn ExecutionPlan>,
1529 codec: &dyn PhysicalExtensionCodec,
1530 ) -> Result<Self>
1531 where
1532 Self: Sized;
1533}
1534
1535pub trait PhysicalExtensionCodec: Debug + Send + Sync + Any {
1536 fn try_decode(
1537 &self,
1538 buf: &[u8],
1539 inputs: &[Arc<dyn ExecutionPlan>],
1540 ctx: &TaskContext,
1541 proto_converter: &dyn PhysicalProtoConverterExtension,
1542 ) -> Result<Arc<dyn ExecutionPlan>>;
1543
1544 fn try_encode(
1545 &self,
1546 node: Arc<dyn ExecutionPlan>,
1547 buf: &mut Vec<u8>,
1548 proto_converter: &dyn PhysicalProtoConverterExtension,
1549 ) -> Result<()>;
1550
1551 fn try_decode_udf(&self, name: &str, _buf: &[u8]) -> Result<Arc<ScalarUDF>> {
1552 not_impl_err!("PhysicalExtensionCodec is not provided for scalar function {name}")
1553 }
1554
1555 fn try_encode_udf(&self, _node: &ScalarUDF, _buf: &mut Vec<u8>) -> Result<()> {
1556 Ok(())
1557 }
1558
1559 fn try_decode_higher_order_function(
1560 &self,
1561 name: &str,
1562 _buf: &[u8],
1563 ) -> Result<Arc<HigherOrderUDF>> {
1564 not_impl_err!(
1565 "PhysicalExtensionCodec is not provided for higher order function {name}"
1566 )
1567 }
1568
1569 fn try_encode_higher_order_function(
1570 &self,
1571 _node: &HigherOrderUDF,
1572 _buf: &mut Vec<u8>,
1573 ) -> Result<()> {
1574 Ok(())
1575 }
1576
1577 fn try_decode_expr(
1592 &self,
1593 _buf: &[u8],
1594 _inputs: &[Arc<dyn PhysicalExpr>],
1595 _ctx: &PhysicalExprDecodeCtx<'_>,
1596 ) -> Result<Arc<dyn PhysicalExpr>> {
1597 not_impl_err!("PhysicalExtensionCodec is not provided")
1598 }
1599
1600 fn try_encode_expr(
1611 &self,
1612 _node: &Arc<dyn PhysicalExpr>,
1613 _buf: &mut Vec<u8>,
1614 _ctx: &PhysicalExprEncodeCtx<'_>,
1615 ) -> Result<()> {
1616 not_impl_err!("PhysicalExtensionCodec is not provided")
1617 }
1618
1619 fn try_decode_udaf(&self, name: &str, _buf: &[u8]) -> Result<Arc<AggregateUDF>> {
1620 not_impl_err!(
1621 "PhysicalExtensionCodec is not provided for aggregate function {name}"
1622 )
1623 }
1624
1625 fn try_encode_udaf(&self, _node: &AggregateUDF, _buf: &mut Vec<u8>) -> Result<()> {
1626 Ok(())
1627 }
1628
1629 fn try_decode_udwf(&self, name: &str, _buf: &[u8]) -> Result<Arc<WindowUDF>> {
1630 not_impl_err!("PhysicalExtensionCodec is not provided for window function {name}")
1631 }
1632
1633 fn try_encode_udwf(&self, _node: &WindowUDF, _buf: &mut Vec<u8>) -> Result<()> {
1634 Ok(())
1635 }
1636}
1637
1638#[derive(Debug)]
1639pub struct DefaultPhysicalExtensionCodec {}
1640
1641impl PhysicalExtensionCodec for DefaultPhysicalExtensionCodec {
1642 fn try_decode(
1643 &self,
1644 _buf: &[u8],
1645 _inputs: &[Arc<dyn ExecutionPlan>],
1646 _ctx: &TaskContext,
1647 _proto_converter: &dyn PhysicalProtoConverterExtension,
1648 ) -> Result<Arc<dyn ExecutionPlan>> {
1649 not_impl_err!("PhysicalExtensionCodec is not provided")
1650 }
1651
1652 fn try_encode(
1653 &self,
1654 _node: Arc<dyn ExecutionPlan>,
1655 _buf: &mut Vec<u8>,
1656 _proto_converter: &dyn PhysicalProtoConverterExtension,
1657 ) -> Result<()> {
1658 not_impl_err!("PhysicalExtensionCodec is not provided")
1659 }
1660}
1661
1662pub trait PhysicalProtoConverterExtension {
1666 fn proto_to_execution_plan(
1667 &self,
1668 proto: &protobuf::PhysicalPlanNode,
1669 ctx: &PhysicalPlanDecodeContext<'_>,
1670 ) -> Result<Arc<dyn ExecutionPlan>>;
1671
1672 fn default_proto_to_execution_plan(
1673 &self,
1674 proto: &protobuf::PhysicalPlanNode,
1675 ctx: &PhysicalPlanDecodeContext<'_>,
1676 ) -> Result<Arc<dyn ExecutionPlan>>
1677 where
1678 Self: Sized,
1679 {
1680 proto.try_into_physical_plan_with_context(ctx, self)
1681 }
1682
1683 fn execution_plan_to_proto(
1684 &self,
1685 plan: &Arc<dyn ExecutionPlan>,
1686 codec: &dyn PhysicalExtensionCodec,
1687 ) -> Result<protobuf::PhysicalPlanNode>;
1688
1689 fn proto_to_physical_expr(
1690 &self,
1691 proto: &protobuf::PhysicalExprNode,
1692 input_schema: &Schema,
1693 ctx: &PhysicalPlanDecodeContext<'_>,
1694 ) -> Result<Arc<dyn PhysicalExpr>>;
1695
1696 fn default_proto_to_physical_expr(
1697 &self,
1698 proto: &protobuf::PhysicalExprNode,
1699 input_schema: &Schema,
1700 ctx: &PhysicalPlanDecodeContext<'_>,
1701 ) -> Result<Arc<dyn PhysicalExpr>>
1702 where
1703 Self: Sized,
1704 {
1705 parse_physical_expr_with_converter(proto, input_schema, ctx, self)
1706 }
1707
1708 fn physical_expr_to_proto(
1709 &self,
1710 expr: &Arc<dyn PhysicalExpr>,
1711 codec: &dyn PhysicalExtensionCodec,
1712 ) -> Result<protobuf::PhysicalExprNode>;
1713}
1714
1715#[derive(Clone, PartialEq, prost::Message)]
1718struct DataEncoderTuple {
1719 #[prost(uint32, tag = 1)]
1722 pub encoder_position: u32,
1723
1724 #[prost(bytes, tag = 2)]
1725 pub blob: Vec<u8>,
1726}
1727
1728pub struct DefaultPhysicalProtoConverter {}
1729
1730impl PhysicalProtoConverterExtension for DefaultPhysicalProtoConverter {
1731 fn proto_to_execution_plan(
1732 &self,
1733 proto: &protobuf::PhysicalPlanNode,
1734 ctx: &PhysicalPlanDecodeContext<'_>,
1735 ) -> Result<Arc<dyn ExecutionPlan>> {
1736 proto.try_into_physical_plan_with_context(ctx, self)
1737 }
1738
1739 fn execution_plan_to_proto(
1740 &self,
1741 plan: &Arc<dyn ExecutionPlan>,
1742 codec: &dyn PhysicalExtensionCodec,
1743 ) -> Result<protobuf::PhysicalPlanNode>
1744 where
1745 Self: Sized,
1746 {
1747 protobuf::PhysicalPlanNode::try_from_physical_plan_with_converter(
1748 Arc::clone(plan),
1749 codec,
1750 self,
1751 )
1752 }
1753
1754 fn proto_to_physical_expr(
1755 &self,
1756 proto: &protobuf::PhysicalExprNode,
1757 input_schema: &Schema,
1758 ctx: &PhysicalPlanDecodeContext<'_>,
1759 ) -> Result<Arc<dyn PhysicalExpr>>
1760 where
1761 Self: Sized,
1762 {
1763 parse_physical_expr_with_converter(proto, input_schema, ctx, self)
1765 }
1766
1767 fn physical_expr_to_proto(
1768 &self,
1769 expr: &Arc<dyn PhysicalExpr>,
1770 codec: &dyn PhysicalExtensionCodec,
1771 ) -> Result<protobuf::PhysicalExprNode> {
1772 serialize_physical_expr_with_converter(expr, codec, self)
1773 }
1774}
1775
1776#[derive(Default)]
1779struct DeduplicatingDeserializer {
1780 cache: RefCell<HashMap<u64, Arc<dyn PhysicalExpr>>>,
1782}
1783
1784impl PhysicalProtoConverterExtension for DeduplicatingDeserializer {
1785 fn proto_to_execution_plan(
1786 &self,
1787 proto: &protobuf::PhysicalPlanNode,
1788 ctx: &PhysicalPlanDecodeContext<'_>,
1789 ) -> Result<Arc<dyn ExecutionPlan>> {
1790 proto.try_into_physical_plan_with_context(ctx, self)
1791 }
1792
1793 fn execution_plan_to_proto(
1794 &self,
1795 _plan: &Arc<dyn ExecutionPlan>,
1796 _codec: &dyn PhysicalExtensionCodec,
1797 ) -> Result<protobuf::PhysicalPlanNode>
1798 where
1799 Self: Sized,
1800 {
1801 internal_err!("DeduplicatingDeserializer cannot serialize execution plans")
1802 }
1803
1804 fn proto_to_physical_expr(
1805 &self,
1806 proto: &protobuf::PhysicalExprNode,
1807 input_schema: &Schema,
1808 ctx: &PhysicalPlanDecodeContext<'_>,
1809 ) -> Result<Arc<dyn PhysicalExpr>>
1810 where
1811 Self: Sized,
1812 {
1813 let Some(id) = proto.expr_id else {
1817 return parse_physical_expr_with_converter(proto, input_schema, ctx, self);
1818 };
1819
1820 let parsed = parse_physical_expr_with_converter(proto, input_schema, ctx, self)?;
1821
1822 let mut cache = self.cache.borrow_mut();
1823 if let Some(cached) = cache.get(&id) {
1824 let children: Vec<_> = parsed.children().into_iter().cloned().collect();
1832 return Arc::clone(cached).with_new_children(children);
1833 }
1834
1835 cache.insert(id, Arc::clone(&parsed));
1836 Ok(parsed)
1837 }
1838
1839 fn physical_expr_to_proto(
1840 &self,
1841 _expr: &Arc<dyn PhysicalExpr>,
1842 _codec: &dyn PhysicalExtensionCodec,
1843 ) -> Result<protobuf::PhysicalExprNode> {
1844 internal_err!("DeduplicatingDeserializer cannot serialize physical expressions")
1845 }
1846}
1847
1848#[derive(Debug, Default, Clone, Copy)]
1857pub struct DeduplicatingProtoConverter {}
1858
1859impl PhysicalProtoConverterExtension for DeduplicatingProtoConverter {
1860 fn proto_to_execution_plan(
1861 &self,
1862 proto: &protobuf::PhysicalPlanNode,
1863 ctx: &PhysicalPlanDecodeContext<'_>,
1864 ) -> Result<Arc<dyn ExecutionPlan>> {
1865 let deserializer = DeduplicatingDeserializer::default();
1866 proto.try_into_physical_plan_with_context(ctx, &deserializer)
1867 }
1868
1869 fn execution_plan_to_proto(
1870 &self,
1871 plan: &Arc<dyn ExecutionPlan>,
1872 codec: &dyn PhysicalExtensionCodec,
1873 ) -> Result<protobuf::PhysicalPlanNode>
1874 where
1875 Self: Sized,
1876 {
1877 protobuf::PhysicalPlanNode::try_from_physical_plan_with_converter(
1878 Arc::clone(plan),
1879 codec,
1880 self,
1881 )
1882 }
1883
1884 fn proto_to_physical_expr(
1885 &self,
1886 proto: &protobuf::PhysicalExprNode,
1887 input_schema: &Schema,
1888 ctx: &PhysicalPlanDecodeContext<'_>,
1889 ) -> Result<Arc<dyn PhysicalExpr>>
1890 where
1891 Self: Sized,
1892 {
1893 let deserializer = DeduplicatingDeserializer::default();
1894 deserializer.proto_to_physical_expr(proto, input_schema, ctx)
1895 }
1896
1897 fn physical_expr_to_proto(
1898 &self,
1899 expr: &Arc<dyn PhysicalExpr>,
1900 codec: &dyn PhysicalExtensionCodec,
1901 ) -> Result<protobuf::PhysicalExprNode> {
1902 serialize_physical_expr_with_converter(expr, codec, self)
1903 }
1904}
1905
1906#[derive(Debug)]
1909pub struct ComposedPhysicalExtensionCodec {
1910 codecs: Vec<Arc<dyn PhysicalExtensionCodec>>,
1911}
1912
1913impl ComposedPhysicalExtensionCodec {
1914 pub fn new(codecs: Vec<Arc<dyn PhysicalExtensionCodec>>) -> Self {
1917 Self { codecs }
1918 }
1919
1920 fn decode_protobuf<R>(
1921 &self,
1922 buf: &[u8],
1923 decode: impl FnOnce(&dyn PhysicalExtensionCodec, &[u8]) -> Result<R>,
1924 ) -> Result<R> {
1925 let proto =
1926 DataEncoderTuple::decode(buf).map_err(|e| internal_datafusion_err!("{e}"))?;
1927
1928 let codec = self.codecs.get(proto.encoder_position as usize).ok_or(
1929 internal_datafusion_err!("Can't find required codec in codec list"),
1930 )?;
1931
1932 decode(codec.as_ref(), &proto.blob)
1933 }
1934
1935 fn encode_protobuf(
1936 &self,
1937 buf: &mut Vec<u8>,
1938 mut encode: impl FnMut(&dyn PhysicalExtensionCodec, &mut Vec<u8>) -> Result<()>,
1939 ) -> Result<()> {
1940 let mut data = vec![];
1941 let mut last_err = None;
1942 let mut encoder_position = None;
1943
1944 for (position, codec) in self.codecs.iter().enumerate() {
1946 match encode(codec.as_ref(), &mut data) {
1947 Ok(_) => {
1948 encoder_position = Some(position as u32);
1949 break;
1950 }
1951 Err(err) => last_err = Some(err),
1952 }
1953 }
1954
1955 let encoder_position = encoder_position.ok_or_else(|| {
1956 last_err.unwrap_or_else(|| {
1957 DataFusionError::NotImplemented(
1958 "Empty list of composed codecs".to_owned(),
1959 )
1960 })
1961 })?;
1962
1963 let proto = DataEncoderTuple {
1965 encoder_position,
1966 blob: data,
1967 };
1968 proto
1969 .encode(buf)
1970 .map_err(|e| internal_datafusion_err!("{e}"))
1971 }
1972}
1973
1974impl PhysicalExtensionCodec for ComposedPhysicalExtensionCodec {
1975 fn try_decode(
1976 &self,
1977 buf: &[u8],
1978 inputs: &[Arc<dyn ExecutionPlan>],
1979 ctx: &TaskContext,
1980 proto_converter: &dyn PhysicalProtoConverterExtension,
1981 ) -> Result<Arc<dyn ExecutionPlan>> {
1982 self.decode_protobuf(buf, |codec, data| {
1983 codec.try_decode(data, inputs, ctx, proto_converter)
1984 })
1985 }
1986
1987 fn try_encode(
1988 &self,
1989 node: Arc<dyn ExecutionPlan>,
1990 buf: &mut Vec<u8>,
1991 proto_converter: &dyn PhysicalProtoConverterExtension,
1992 ) -> Result<()> {
1993 self.encode_protobuf(buf, |codec, data| {
1994 codec.try_encode(Arc::clone(&node), data, proto_converter)
1995 })
1996 }
1997
1998 fn try_decode_udf(&self, name: &str, buf: &[u8]) -> Result<Arc<ScalarUDF>> {
1999 self.decode_protobuf(buf, |codec, data| codec.try_decode_udf(name, data))
2000 }
2001
2002 fn try_encode_udf(&self, node: &ScalarUDF, buf: &mut Vec<u8>) -> Result<()> {
2003 self.encode_protobuf(buf, |codec, data| codec.try_encode_udf(node, data))
2004 }
2005
2006 fn try_decode_udaf(&self, name: &str, buf: &[u8]) -> Result<Arc<AggregateUDF>> {
2007 self.decode_protobuf(buf, |codec, data| codec.try_decode_udaf(name, data))
2008 }
2009
2010 fn try_encode_udaf(&self, node: &AggregateUDF, buf: &mut Vec<u8>) -> Result<()> {
2011 self.encode_protobuf(buf, |codec, data| codec.try_encode_udaf(node, data))
2012 }
2013}
2014
2015struct ConverterPlanEncoder<'a> {
2019 codec: &'a dyn PhysicalExtensionCodec,
2020 proto_converter: &'a dyn PhysicalProtoConverterExtension,
2021}
2022
2023impl ExecutionPlanEncode for ConverterPlanEncoder<'_> {
2024 fn encode_plan(
2025 &self,
2026 plan: &Arc<dyn ExecutionPlan>,
2027 ) -> Result<protobuf::PhysicalPlanNode> {
2028 self.proto_converter
2029 .execution_plan_to_proto(plan, self.codec)
2030 }
2031
2032 fn encode_expr(
2033 &self,
2034 expr: &Arc<dyn PhysicalExpr>,
2035 ) -> Result<protobuf::PhysicalExprNode> {
2036 self.proto_converter
2037 .physical_expr_to_proto(expr, self.codec)
2038 }
2039
2040 fn encode_udf(&self, udf: &ScalarUDF) -> Result<Option<Vec<u8>>> {
2043 let mut buf = vec![];
2044 self.codec.try_encode_udf(udf, &mut buf)?;
2045 Ok((!buf.is_empty()).then_some(buf))
2046 }
2047
2048 fn encode_udaf(&self, udaf: &AggregateUDF) -> Result<Option<Vec<u8>>> {
2049 let mut buf = vec![];
2050 self.codec.try_encode_udaf(udaf, &mut buf)?;
2051 Ok((!buf.is_empty()).then_some(buf))
2052 }
2053
2054 fn encode_udwf(&self, udwf: &WindowUDF) -> Result<Option<Vec<u8>>> {
2055 let mut buf = vec![];
2056 self.codec.try_encode_udwf(udwf, &mut buf)?;
2057 Ok((!buf.is_empty()).then_some(buf))
2058 }
2059}
2060
2061struct ConverterPlanDecoder<'a, 'ctx> {
2066 ctx: &'a PhysicalPlanDecodeContext<'ctx>,
2067 proto_converter: &'a dyn PhysicalProtoConverterExtension,
2068}
2069
2070impl ExecutionPlanDecode for ConverterPlanDecoder<'_, '_> {
2071 fn decode_plan(
2072 &self,
2073 node: &protobuf::PhysicalPlanNode,
2074 ) -> Result<Arc<dyn ExecutionPlan>> {
2075 self.proto_converter.proto_to_execution_plan(node, self.ctx)
2076 }
2077
2078 fn decode_plan_with_scalar_subquery_results(
2079 &self,
2080 node: &protobuf::PhysicalPlanNode,
2081 results: ScalarSubqueryResults,
2082 ) -> Result<Arc<dyn ExecutionPlan>> {
2083 let scoped_ctx = self.ctx.with_scalar_subquery_results(results);
2084 self.proto_converter
2085 .proto_to_execution_plan(node, &scoped_ctx)
2086 }
2087
2088 fn decode_expr(
2089 &self,
2090 node: &protobuf::PhysicalExprNode,
2091 input_schema: &Schema,
2092 ) -> Result<Arc<dyn PhysicalExpr>> {
2093 self.proto_converter
2094 .proto_to_physical_expr(node, input_schema, self.ctx)
2095 }
2096
2097 fn task_ctx(&self) -> &TaskContext {
2098 self.ctx.task_ctx()
2099 }
2100
2101 fn decode_udf(&self, name: &str, payload: Option<&[u8]>) -> Result<Arc<ScalarUDF>> {
2105 match payload {
2106 Some(buf) => self.ctx.codec().try_decode_udf(name, buf),
2107 None => self
2108 .ctx
2109 .task_ctx()
2110 .udf(name)
2111 .or_else(|_| self.ctx.codec().try_decode_udf(name, &[])),
2112 }
2113 }
2114
2115 fn decode_udaf(
2116 &self,
2117 name: &str,
2118 payload: Option<&[u8]>,
2119 ) -> Result<Arc<AggregateUDF>> {
2120 match payload {
2121 Some(buf) => self.ctx.codec().try_decode_udaf(name, buf),
2122 None => self
2123 .ctx
2124 .task_ctx()
2125 .udaf(name)
2126 .or_else(|_| self.ctx.codec().try_decode_udaf(name, &[])),
2127 }
2128 }
2129
2130 fn decode_udwf(&self, name: &str, payload: Option<&[u8]>) -> Result<Arc<WindowUDF>> {
2131 match payload {
2132 Some(buf) => self.ctx.codec().try_decode_udwf(name, buf),
2133 None => self
2134 .ctx
2135 .task_ctx()
2136 .udwf(name)
2137 .or_else(|_| self.ctx.codec().try_decode_udwf(name, &[])),
2138 }
2139 }
2140}