1use std::sync::Arc;
16
17use bytes::Bytes;
18use catalog::CatalogManagerRef;
19use common_error::ext::BoxedError;
20use common_function::function::FunctionContext;
21use common_function::function_registry::FUNCTION_REGISTRY;
22use common_query::error::RegisterUdfSnafu;
23use common_query::logical_plan::SubstraitPlanDecoder;
24use datafusion::catalog::{CatalogProviderList, TableProvider};
25use datafusion::common::{DFSchema, DataFusionError, TableReference, not_impl_err, substrait_err};
26use datafusion::error::Result;
27use datafusion::execution::context::SessionState;
28use datafusion::execution::registry::SerializerRegistry;
29use datafusion::execution::{FunctionRegistry, SessionStateBuilder};
30use datafusion::logical_expr::{Extension, LogicalPlan};
31use datafusion_expr::{Expr, UserDefinedLogicalNode};
32use greptime_proto::substrait_extension::MergeScan as PbMergeScan;
33use promql::functions::register_promql_functions;
34use prost::Message;
35use session::context::{QueryContext, QueryContextRef};
36use snafu::ResultExt;
37use substrait::df_logical_plan::consumer::{DefaultSubstraitConsumer, SubstraitConsumer};
38use substrait::error::{DecodeDfPlanSnafu, DecodeRelSnafu};
39use substrait::extension_serializer::ExtensionSerializer;
40use substrait::substrait_proto_df::proto::{
41 ExtensionLeafRel, ExtensionMultiRel, ExtensionSingleRel, Plan, Type,
42};
43use substrait::{DFLogicalSubstraitConvertor, Extensions, SubstraitPlan};
44
45use crate::dist_plan::MergeScanLogicalPlan;
46use crate::query_engine::QueryEngineState;
47
48#[derive(Debug)]
50pub struct DefaultSerializer;
51
52impl SerializerRegistry for DefaultSerializer {
53 fn serialize_logical_plan(&self, node: &dyn UserDefinedLogicalNode) -> Result<Vec<u8>> {
54 if node.name() == MergeScanLogicalPlan::name() {
55 let merge_scan = node
56 .as_any()
57 .downcast_ref::<MergeScanLogicalPlan>()
58 .expect("Failed to downcast to MergeScanLogicalPlan");
59
60 let input = merge_scan.input();
61 let is_placeholder = merge_scan.is_placeholder();
62 let input = DFLogicalSubstraitConvertor
63 .encode(input, DefaultSerializer)
64 .map_err(|e| DataFusionError::External(Box::new(e)))?
65 .to_vec();
66
67 Ok(PbMergeScan {
68 is_placeholder,
69 input,
70 }
71 .encode_to_vec())
72 } else {
73 ExtensionSerializer.serialize_logical_plan(node)
74 }
75 }
76
77 fn deserialize_logical_plan(
78 &self,
79 name: &str,
80 bytes: &[u8],
81 ) -> Result<Arc<dyn UserDefinedLogicalNode>> {
82 if name == MergeScanLogicalPlan::name() {
83 Err(DataFusionError::Substrait(format!(
85 "Unsupported plan node: {name}"
86 )))
87 } else {
88 ExtensionSerializer.deserialize_logical_plan(name, bytes)
89 }
90 }
91}
92
93struct MergeScanSubstraitConsumer<'a> {
95 inner: DefaultSubstraitConsumer<'a>,
96 session_state: &'a SessionState,
97 catalog_manager: Option<CatalogManagerRef>,
98 payload: bool,
99}
100
101impl MergeScanSubstraitConsumer<'_> {
102 fn query_ctx(&self) -> QueryContextRef {
103 self.session_state
104 .config()
105 .get_extension()
106 .unwrap_or_else(QueryContext::arc)
107 }
108
109 async fn decode_payload(&self, payload: Vec<u8>) -> Result<LogicalPlan> {
110 decode_plan(Bytes::from(payload), self.session_state, true)
111 .await
112 .map_err(|e| DataFusionError::External(Box::new(e)))
113 }
114}
115
116#[async_trait::async_trait]
117impl SubstraitConsumer for MergeScanSubstraitConsumer<'_> {
118 async fn resolve_table_ref(
119 &self,
120 table_ref: &TableReference,
121 ) -> Result<Option<Arc<dyn TableProvider>>> {
122 if !self.payload {
123 return self.inner.resolve_table_ref(table_ref).await;
124 }
125
126 let query_ctx = self.query_ctx();
127 let resolved = table_ref
128 .clone()
129 .resolve(query_ctx.current_catalog(), &query_ctx.current_schema());
130 let Some(manager) = &self.catalog_manager else {
132 return self
133 .inner
134 .resolve_table_ref(&TableReference::from(resolved))
135 .await;
136 };
137 let catalog_list: Arc<dyn CatalogProviderList> = Arc::new(
138 catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
139 manager.clone(),
140 query_ctx,
141 ),
142 );
143 let schema_name = resolved.schema.as_ref();
144 let catalog_name = resolved.catalog.as_ref();
145 let schema = catalog_list
146 .catalog(catalog_name)
147 .ok_or_else(|| {
148 DataFusionError::Plan(format!("failed to resolve catalog: {catalog_name}"))
149 })?
150 .schema(schema_name)
151 .ok_or_else(|| {
152 DataFusionError::Plan(format!("failed to resolve schema: {schema_name}"))
153 })?;
154 schema.table(&resolved.table).await
155 }
156
157 fn get_extensions(&self) -> &Extensions {
158 self.inner.get_extensions()
159 }
160
161 fn get_function_registry(&self) -> &impl FunctionRegistry {
162 self.inner.get_function_registry()
163 }
164
165 fn push_outer_schema(&self, schema: Arc<DFSchema>) {
166 self.inner.push_outer_schema(schema)
167 }
168
169 fn pop_outer_schema(&self) {
170 self.inner.pop_outer_schema()
171 }
172
173 fn get_outer_schema(&self, steps_out: usize) -> Option<Arc<DFSchema>> {
174 self.inner.get_outer_schema(steps_out)
175 }
176
177 fn push_lambda_parameters(
178 &self,
179 lambda_parameters: &[Type],
180 input_schema: &DFSchema,
181 ) -> Result<Vec<String>> {
182 self.inner
183 .push_lambda_parameters(lambda_parameters, input_schema)
184 }
185
186 fn pop_lambda_parameters(&self) {
187 self.inner.pop_lambda_parameters()
188 }
189
190 fn lambda_variable(&self, steps_out: usize, field_idx: usize) -> Result<Expr> {
191 self.inner.lambda_variable(steps_out, field_idx)
192 }
193
194 async fn consume_extension_leaf(&self, rel: &ExtensionLeafRel) -> Result<LogicalPlan> {
195 let Some(detail) = rel.detail.as_ref() else {
197 return self.inner.consume_extension_leaf(rel).await;
198 };
199 if detail.type_url != MergeScanLogicalPlan::name() {
200 return self.inner.consume_extension_leaf(rel).await;
201 }
202
203 let merge_scan = PbMergeScan::decode(detail.value.as_ref()).map_err(|e| {
204 DataFusionError::Substrait(format!("Failed to decode the MergeScan plan node: {e}"))
205 })?;
206
207 let input = self.decode_payload(merge_scan.input).await?;
208
209 Ok(MergeScanLogicalPlan::new(input, merge_scan.is_placeholder).into_logical_plan())
210 }
211
212 async fn consume_extension_single(&self, rel: &ExtensionSingleRel) -> Result<LogicalPlan> {
214 let Some(detail) = &rel.detail else {
215 return substrait_err!("Unexpected empty detail in ExtensionSingleRel");
216 };
217 let plan = self
218 .session_state
219 .serializer_registry()
220 .deserialize_logical_plan(&detail.type_url, &detail.value)?;
221 let Some(input_rel) = &rel.input else {
222 return substrait_err!(
223 "ExtensionSingleRel missing input rel, try using ExtensionLeafRel instead"
224 );
225 };
226 let input_plan = self.consume_rel(input_rel).await?;
227 let plan = plan.with_exprs_and_inputs(plan.expressions(), vec![input_plan])?;
228 Ok(LogicalPlan::Extension(Extension { node: plan }))
229 }
230
231 async fn consume_extension_multi(&self, rel: &ExtensionMultiRel) -> Result<LogicalPlan> {
233 let Some(detail) = &rel.detail else {
234 return substrait_err!("Unexpected empty detail in ExtensionMultiRel");
235 };
236 let plan = self
237 .session_state
238 .serializer_registry()
239 .deserialize_logical_plan(&detail.type_url, &detail.value)?;
240 let mut inputs = Vec::with_capacity(rel.inputs.len());
241 for input in &rel.inputs {
242 let input_plan = self.consume_rel(input).await?;
243 inputs.push(input_plan);
244 }
245 let plan = plan.with_exprs_and_inputs(plan.expressions(), inputs)?;
246 Ok(LogicalPlan::Extension(Extension { node: plan }))
247 }
248}
249
250async fn decode_plan(
252 bytes: Bytes,
253 state: &SessionState,
254 payload: bool,
255) -> substrait::error::Result<LogicalPlan> {
256 let plan = Plan::decode(bytes).context(DecodeRelSnafu)?;
257 let extensions = Extensions::try_from(&plan.extensions).context(DecodeDfPlanSnafu)?;
258 if !extensions.type_variations.is_empty() {
259 return not_impl_err!("Type variation extensions are not supported")
260 .context(DecodeDfPlanSnafu);
261 }
262
263 let catalog_manager = state
264 .config()
265 .get_extension::<QueryEngineState>()
266 .map(|engine_state| engine_state.catalog_manager().clone());
267 let consumer = MergeScanSubstraitConsumer {
268 inner: DefaultSubstraitConsumer::new(&extensions, state),
269 session_state: state,
270 catalog_manager,
271 payload,
272 };
273
274 DFLogicalSubstraitConvertor
275 .decode_with_consumer(&plan, state, &consumer)
276 .await
277}
278
279pub struct DefaultPlanDecoder {
281 session_state: SessionState,
282 query_ctx: QueryContextRef,
283}
284
285impl DefaultPlanDecoder {
286 pub fn new(
287 session_state: SessionState,
288 query_ctx: &QueryContextRef,
289 ) -> crate::error::Result<Self> {
290 Ok(Self {
291 session_state,
292 query_ctx: query_ctx.clone(),
293 })
294 }
295}
296
297fn register_greptime_functions(
302 session_state: &mut SessionState,
303 query_ctx: &QueryContextRef,
304) -> common_query::error::Result<()> {
305 for func in FUNCTION_REGISTRY.scalar_functions() {
306 let udf = func.provide(FunctionContext {
307 query_ctx: query_ctx.clone(),
308 state: Default::default(),
309 });
310 session_state
311 .register_udf(Arc::new(udf))
312 .context(RegisterUdfSnafu { name: func.name() })?;
313 }
314
315 for func in FUNCTION_REGISTRY.aggregate_functions() {
316 let name = func.name().to_string();
317 session_state
318 .register_udaf(Arc::new(func))
319 .context(RegisterUdfSnafu { name })?;
320 }
321
322 register_promql_functions(session_state);
323
324 Ok(())
325}
326
327#[async_trait::async_trait]
328impl SubstraitPlanDecoder for DefaultPlanDecoder {
329 async fn decode(
330 &self,
331 message: bytes::Bytes,
332 catalog_list: Arc<dyn CatalogProviderList>,
333 optimize: bool,
334 ) -> common_query::error::Result<LogicalPlan> {
335 let mut session_state = SessionStateBuilder::new_from_existing(self.session_state.clone())
336 .with_serializer_registry(Arc::new(DefaultSerializer))
337 .with_catalog_list(catalog_list)
338 .build();
339 register_greptime_functions(&mut session_state, &self.query_ctx)?;
341
342 let logical_plan = decode_plan(message, &session_state, false)
343 .await
344 .map_err(BoxedError::new)
345 .context(common_query::error::DecodePlanSnafu)?;
346
347 if optimize {
348 self.session_state
349 .optimize(&logical_plan)
350 .map_err(Into::into)
351 } else {
352 Ok(logical_plan)
353 }
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use std::any::Any;
360 use std::sync::atomic::{AtomicBool, Ordering};
361
362 use catalog::error::Result as CatalogResult;
363 use catalog::{CatalogManager, RegisterTableRequest};
364 use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME, NUMBERS_TABLE_ID};
365 use common_function::aggrs::aggr_wrapper::StateWrapper;
366 use common_function::aggrs::aggr_wrapper::fix_order::FixStateUdafOrderingAnalyzer;
367 use common_query::logical_plan::SubstraitPlanDecoderRef;
368 use common_query::native_histogram::native_histogram_value_type;
369 use common_time::Timezone;
370 use datafusion::catalog::TableProvider;
371 use datafusion::datasource::MemTable;
372 use datafusion::logical_expr::Extension;
373 use datafusion::optimizer::AnalyzerRule;
374 use datafusion_expr::expr::{AggregateFunction, Cast, InSubquery, ScalarFunction, Sort};
375 use datafusion_expr::{
376 AggregateUDF, Expr, LogicalPlanBuilder, LogicalTableSource, ScalarUDF, Subquery, col, lit,
377 };
378 use datatypes::arrow::datatypes::{
379 DataType as ArrowDataType, Field, Schema, SchemaRef, TimeUnit,
380 };
381 use datatypes::data_type::DataType;
382 use futures::stream::BoxStream;
383 use promql::extension_plan::{RangeManipulate, SeriesNormalize, UnionDistinctOn};
384 use promql::functions::{
385 MixedRange, NativeHistogramAggAvg, NativeHistogramAggSum, NativeHistogramCount,
386 NativeHistogramDrop, PromqlFloatToString,
387 };
388 use session::context::QueryContext;
389 use table::TableRef;
390 use table::metadata::{TableId, TableInfoRef};
391 use table::table::numbers::{NUMBERS_TABLE_NAME, NumbersTable};
392
393 use super::*;
394 use crate::QueryEngineFactory;
395 use crate::dummy_catalog::DummyCatalogList;
396 use crate::optimizer::test_util::mock_table_provider;
397 use crate::options::QueryOptions;
398
399 fn mock_plan(schema: SchemaRef) -> LogicalPlan {
400 let table_source = LogicalTableSource::new(schema);
401 let projection = None;
402 let builder =
403 LogicalPlanBuilder::scan("devices", Arc::new(table_source), projection).unwrap();
404
405 builder
406 .filter(col("k0").eq(lit("hello")))
407 .unwrap()
408 .build()
409 .unwrap()
410 }
411
412 #[tokio::test]
413 async fn test_serializer_decode_plan() {
414 let catalog_list = catalog::memory::new_memory_catalog_manager().unwrap();
415 let factory = QueryEngineFactory::new(
416 catalog_list,
417 None,
418 None,
419 None,
420 None,
421 false,
422 QueryOptions::default(),
423 );
424
425 let engine = factory.query_engine();
426
427 let table_provider = Arc::new(mock_table_provider(1.into()));
428 let plan = mock_plan(table_provider.schema().clone());
429
430 let bytes = DFLogicalSubstraitConvertor
431 .encode(&plan, DefaultSerializer)
432 .unwrap();
433
434 let plan_decoder = engine
435 .engine_context(QueryContext::arc())
436 .unwrap()
437 .new_plan_decoder()
438 .unwrap();
439 let catalog_list = Arc::new(DummyCatalogList::with_table_provider(table_provider));
440
441 let decode_plan = plan_decoder
442 .decode(bytes, catalog_list, false)
443 .await
444 .unwrap();
445
446 assert_eq!(
447 "Filter: devices.k0 = Utf8(\"hello\")
448 TableScan: devices",
449 decode_plan.to_string(),
450 );
451 }
452
453 #[tokio::test]
454 async fn test_serializer_decode_native_histogram_udf() {
455 let catalog_list = catalog::memory::new_memory_catalog_manager().unwrap();
456 let factory = QueryEngineFactory::new(
457 catalog_list,
458 None,
459 None,
460 None,
461 None,
462 false,
463 QueryOptions::default(),
464 );
465 let engine = factory.query_engine();
466 let schema = Arc::new(Schema::new(vec![Field::new(
467 "histogram",
468 native_histogram_value_type().as_arrow_type(),
469 true,
470 )]));
471 let plan = LogicalPlanBuilder::scan(
472 "devices",
473 Arc::new(LogicalTableSource::new(schema.clone())),
474 None,
475 )
476 .unwrap()
477 .aggregate(
478 Vec::<Expr>::new(),
479 vec![
480 Arc::new(NativeHistogramAggSum::aggregate_udf())
481 .call(vec![col("histogram")])
482 .alias("sum"),
483 Arc::new(NativeHistogramAggAvg::aggregate_udf())
484 .call(vec![col("histogram")])
485 .alias("avg"),
486 ],
487 )
488 .unwrap()
489 .project(vec![
490 Expr::ScalarFunction(ScalarFunction {
491 func: Arc::new(NativeHistogramCount::scalar_udf()),
492 args: vec![col("sum")],
493 }),
494 Expr::ScalarFunction(ScalarFunction {
495 func: Arc::new(NativeHistogramDrop::bool_false_udf(
496 "ignored annotation".to_string(),
497 None,
498 )),
499 args: vec![col("sum")],
500 }),
501 Expr::ScalarFunction(ScalarFunction {
502 func: Arc::new(NativeHistogramDrop::bool_true_udf(
503 "ignored annotation".to_string(),
504 None,
505 )),
506 args: vec![col("sum")],
507 }),
508 Expr::ScalarFunction(ScalarFunction {
509 func: Arc::new(NativeHistogramDrop::float_null_udf(
510 "ignored annotation".to_string(),
511 None,
512 )),
513 args: vec![col("sum")],
514 }),
515 Expr::ScalarFunction(ScalarFunction {
516 func: Arc::new(PromqlFloatToString::scalar_udf()),
517 args: vec![lit(2.0)],
518 }),
519 ])
520 .unwrap()
521 .build()
522 .unwrap();
523 let bytes = DFLogicalSubstraitConvertor
524 .encode(&plan, DefaultSerializer)
525 .unwrap();
526 let table_provider = Arc::new(MemTable::try_new(schema, vec![vec![]]).unwrap());
527 let plan_decoder = engine
528 .engine_context(QueryContext::arc())
529 .unwrap()
530 .new_plan_decoder()
531 .unwrap();
532
533 let decoded = plan_decoder
534 .decode(
535 bytes,
536 Arc::new(DummyCatalogList::with_table_provider(table_provider)),
537 false,
538 )
539 .await
540 .unwrap();
541
542 let decoded = decoded.to_string();
543 assert!(decoded.contains("prom_native_histogram_count"));
544 assert!(decoded.contains("prom_native_histogram_drop_bool"));
545 assert!(decoded.contains("prom_native_histogram_keep_bool"));
546 assert!(decoded.contains("prom_native_histogram_drop_float"));
547 assert!(decoded.contains(NativeHistogramAggSum::name()));
548 assert!(decoded.contains(NativeHistogramAggAvg::name()));
549 assert!(decoded.contains(PromqlFloatToString::name()));
550
551 let schema = Arc::new(Schema::new(vec![
552 Field::new(
553 "timestamp",
554 ArrowDataType::Timestamp(TimeUnit::Millisecond, None),
555 false,
556 ),
557 Field::new("float", ArrowDataType::Float64, true),
558 Field::new(
559 "histogram",
560 native_histogram_value_type().as_arrow_type(),
561 true,
562 ),
563 ]));
564 let input = LogicalPlanBuilder::scan(
565 "devices",
566 Arc::new(LogicalTableSource::new(schema.clone())),
567 None,
568 )
569 .unwrap()
570 .build()
571 .unwrap();
572 let input = LogicalPlan::Extension(Extension {
573 node: Arc::new(
574 RangeManipulate::new(
575 0,
576 1000,
577 1000,
578 0,
579 1000,
580 "timestamp".to_string(),
581 vec!["float".to_string(), "histogram".to_string()],
582 input,
583 )
584 .unwrap(),
585 ),
586 });
587 let plan = LogicalPlanBuilder::from(input)
588 .project(vec![
589 Expr::ScalarFunction(ScalarFunction {
590 func: Arc::new(MixedRange::float_udf(None)),
591 args: vec![
592 lit("last_over_time"),
593 col("timestamp_range"),
594 col("float"),
595 col("histogram"),
596 ],
597 })
598 .alias("mixed_float"),
599 Expr::ScalarFunction(ScalarFunction {
600 func: Arc::new(MixedRange::histogram_udf(None)),
601 args: vec![
602 lit("last_over_time"),
603 col("timestamp_range"),
604 col("float"),
605 col("histogram"),
606 ],
607 })
608 .alias("mixed_histogram"),
609 ])
610 .unwrap()
611 .build()
612 .unwrap();
613 let bytes = DFLogicalSubstraitConvertor
614 .encode(&plan, DefaultSerializer)
615 .unwrap();
616 let table_provider = Arc::new(MemTable::try_new(schema, vec![vec![]]).unwrap());
617 let decoded = plan_decoder
618 .decode(
619 bytes,
620 Arc::new(DummyCatalogList::with_table_provider(table_provider)),
621 false,
622 )
623 .await
624 .unwrap()
625 .to_string();
626 assert!(decoded.contains("prom_mixed_range_float"));
627 assert!(decoded.contains("prom_mixed_range_histogram"));
628 }
629
630 #[tokio::test]
631 async fn test_serializer_decode_merge_scan() {
632 let engine = QueryEngineFactory::new(
633 numbers_catalog_manager(),
634 None,
635 None,
636 None,
637 None,
638 false,
639 QueryOptions::default(),
640 )
641 .query_engine();
642 let plan = merge_scan(numbers_scan(), true);
643 let decoded = plan_decoder(engine.as_ref())
644 .decode(encode_plan(&plan), request_catalog_list(), false)
645 .await
646 .unwrap();
647
648 let LogicalPlan::Extension(extension) = &decoded else {
649 panic!("Expect a MergeScan plan, got: {decoded}");
650 };
651 let merge_scan = extension
652 .node
653 .as_any()
654 .downcast_ref::<MergeScanLogicalPlan>()
655 .expect("Expect a MergeScan plan node");
656 assert!(merge_scan.is_placeholder());
657 assert_eq!(merge_scan.input().to_string(), numbers_scan().to_string());
658 }
659
660 #[tokio::test]
662 async fn test_serializer_decode_merge_scan_with_engine_catalog() {
663 let engine = QueryEngineFactory::new(
664 numbers_catalog_manager(),
665 None,
666 None,
667 None,
668 None,
669 false,
670 QueryOptions::default(),
671 )
672 .query_engine();
673 let decoded = plan_decoder(engine.as_ref())
674 .decode(
675 encode_plan(&merge_scan(numbers_scan(), false)),
676 request_catalog_list(),
677 false,
678 )
679 .await
680 .unwrap();
681
682 let LogicalPlan::Extension(extension) = &decoded else {
683 panic!("Expect a MergeScan plan, got: {decoded}");
684 };
685 let merge_scan = extension
686 .node
687 .as_any()
688 .downcast_ref::<MergeScanLogicalPlan>()
689 .expect("Expect a MergeScan plan node");
690 let LogicalPlan::TableScan(scan) = merge_scan.input() else {
691 panic!("Expect a table scan, got: {}", merge_scan.input());
692 };
693 assert_eq!(scan.table_name.table(), NUMBERS_TABLE_NAME);
694 assert_eq!(scan.source.schema().fields().len(), 1);
695 assert_eq!(scan.source.schema().field(0).name(), "number");
696 }
697
698 #[tokio::test]
700 async fn test_serializer_decode_nested_merge_scan() {
701 let engine = QueryEngineFactory::new(
702 numbers_catalog_manager(),
703 None,
704 None,
705 None,
706 None,
707 false,
708 QueryOptions::default(),
709 )
710 .query_engine();
711 let inner = merge_scan(numbers_scan(), false);
712 let input = LogicalPlanBuilder::from(inner)
713 .filter(col("number").lt(lit(10u32)))
714 .unwrap()
715 .build()
716 .unwrap();
717 let plan = merge_scan(input, false);
718
719 let decoded = plan_decoder(engine.as_ref())
720 .decode(encode_plan(&plan), request_catalog_list(), false)
721 .await
722 .unwrap();
723
724 assert_eq!(decoded.to_string(), plan.to_string());
725 assert_eq!(decoded.to_string().matches("MergeScan [").count(), 2);
726 }
727
728 fn greptime_date_format_udf(query_ctx: &QueryContextRef) -> Arc<ScalarUDF> {
729 FUNCTION_REGISTRY
730 .get_function("date_format")
731 .expect("`date_format` is a function of GreptimeDB")
732 .provide(FunctionContext {
733 query_ctx: query_ctx.clone(),
734 state: Default::default(),
735 })
736 .into()
737 }
738
739 fn date_format_query_ctx() -> QueryContextRef {
741 let query_ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
742 query_ctx.set_timezone(Timezone::from_tz_string("Asia/Shanghai").unwrap());
743 Arc::new(query_ctx)
744 }
745
746 fn greptime_date_format_expr(query_ctx: &QueryContextRef, timestamp: Expr) -> Expr {
747 Expr::ScalarFunction(ScalarFunction {
748 func: greptime_date_format_udf(query_ctx),
749 args: vec![timestamp, lit("%Y-%m-%d %H:%i:%S")],
750 })
751 }
752
753 fn scalar_functions_of(plan: &LogicalPlan) -> Vec<Arc<ScalarUDF>> {
755 use datafusion::common::tree_node::{TreeNode, TreeNodeRecursion};
756
757 let mut udfs = Vec::new();
758 for expr in plan.expressions() {
759 expr.apply(|expr| {
760 if let Expr::ScalarFunction(func) = expr {
761 udfs.push(Arc::clone(&func.func));
762 }
763 Ok(TreeNodeRecursion::Continue)
764 })
765 .unwrap();
766 }
767
768 if let LogicalPlan::Extension(extension) = plan
769 && let Some(merge_scan) = extension
770 .node
771 .as_any()
772 .downcast_ref::<MergeScanLogicalPlan>()
773 {
774 udfs.extend(scalar_functions_of(merge_scan.input()));
775 }
776
777 for input in plan.inputs() {
778 udfs.extend(scalar_functions_of(input));
779 }
780
781 udfs
782 }
783
784 fn assert_only_function_is_greptime_date_format(
786 plan: &LogicalPlan,
787 query_ctx: &QueryContextRef,
788 ) {
789 let udfs = scalar_functions_of(plan);
790 assert_eq!(udfs.len(), 1, "expected one function in: {plan}");
791
792 let udf = &udfs[0];
793 assert_eq!(udf.name(), "date_format", "got: {plan}");
794 assert_eq!(
795 udf.as_ref(),
796 greptime_date_format_udf(query_ctx).as_ref(),
797 "`date_format` is not bound to the implementation of GreptimeDB: {plan}"
798 );
799 }
800
801 #[tokio::test]
803 async fn test_serializer_decode_keeps_greptime_date_format() {
804 for _ in 0..8 {
806 let catalog_list = catalog::memory::new_memory_catalog_manager().unwrap();
807 let factory = QueryEngineFactory::new(
808 catalog_list,
809 None,
810 None,
811 None,
812 None,
813 false,
814 QueryOptions::default(),
815 );
816 let engine = factory.query_engine();
817
818 let table_provider = Arc::new(mock_table_provider(1.into()));
819 let query_ctx = date_format_query_ctx();
820 let plan = LogicalPlanBuilder::scan(
821 "devices",
822 Arc::new(LogicalTableSource::new(table_provider.schema().clone())),
823 None,
824 )
825 .unwrap()
826 .project(vec![greptime_date_format_expr(&query_ctx, col("ts"))])
827 .unwrap()
828 .build()
829 .unwrap();
830
831 let bytes = DFLogicalSubstraitConvertor
832 .encode(&plan, DefaultSerializer)
833 .unwrap();
834 let plan_decoder = engine
835 .engine_context(query_ctx.clone())
836 .unwrap()
837 .new_plan_decoder()
838 .unwrap();
839 let decoded = plan_decoder
840 .decode(
841 bytes,
842 Arc::new(DummyCatalogList::with_table_provider(table_provider)),
843 false,
844 )
845 .await
846 .unwrap();
847
848 assert_only_function_is_greptime_date_format(&decoded, &query_ctx);
849 }
850 }
851
852 #[tokio::test]
854 async fn test_serializer_decode_merge_scan_payload_keeps_greptime_date_format() {
855 let catalog_manager = catalog::memory::new_memory_catalog_manager().unwrap();
856 catalog_manager
857 .register_table_sync(RegisterTableRequest {
858 catalog: DEFAULT_CATALOG_NAME.to_string(),
859 schema: DEFAULT_SCHEMA_NAME.to_string(),
860 table_name: NUMBERS_TABLE_NAME.to_string(),
861 table_id: NUMBERS_TABLE_ID,
862 table: NumbersTable::table(NUMBERS_TABLE_ID),
863 })
864 .unwrap();
865
866 for _ in 0..8 {
867 let factory = QueryEngineFactory::new(
868 catalog_manager.clone(),
869 None,
870 None,
871 None,
872 None,
873 false,
874 QueryOptions::default(),
875 );
876 let engine = factory.query_engine();
877 let query_ctx = date_format_query_ctx();
878
879 let input = LogicalPlanBuilder::scan(
880 NUMBERS_TABLE_NAME,
881 Arc::new(LogicalTableSource::new(
882 NumbersTable::schema().arrow_schema().clone(),
883 )),
884 None,
885 )
886 .unwrap()
887 .project(vec![greptime_date_format_expr(
888 &query_ctx,
889 Expr::Cast(Cast::new(
890 Box::new(col("number")),
891 ArrowDataType::Timestamp(TimeUnit::Millisecond, None),
892 )),
893 )])
894 .unwrap()
895 .build()
896 .unwrap();
897 let plan = MergeScanLogicalPlan::new(input, false).into_logical_plan();
898
899 let bytes = DFLogicalSubstraitConvertor
900 .encode(&plan, DefaultSerializer)
901 .unwrap();
902 let plan_decoder = engine
903 .engine_context(query_ctx.clone())
904 .unwrap()
905 .new_plan_decoder()
906 .unwrap();
907 let catalog_list = Arc::new(DummyCatalogList::with_table_provider(Arc::new(
908 mock_table_provider(1.into()),
909 )));
910
911 let decoded = plan_decoder
912 .decode(bytes, catalog_list, false)
913 .await
914 .unwrap();
915
916 let LogicalPlan::Extension(extension) = &decoded else {
917 panic!("Expect a MergeScan plan, got: {decoded}");
918 };
919 let merge_scan = extension
920 .node
921 .as_any()
922 .downcast_ref::<MergeScanLogicalPlan>()
923 .expect("Expect a MergeScan plan node");
924
925 assert_only_function_is_greptime_date_format(merge_scan.input(), &query_ctx);
926 }
927 }
928
929 fn numbers_catalog_manager() -> CatalogManagerRef {
931 let catalog_manager = catalog::memory::new_memory_catalog_manager().unwrap();
932 catalog_manager
933 .register_table_sync(RegisterTableRequest {
934 catalog: DEFAULT_CATALOG_NAME.to_string(),
935 schema: DEFAULT_SCHEMA_NAME.to_string(),
936 table_name: NUMBERS_TABLE_NAME.to_string(),
937 table_id: NUMBERS_TABLE_ID,
938 table: NumbersTable::table(NUMBERS_TABLE_ID),
939 })
940 .unwrap();
941 catalog_manager
942 }
943
944 fn numbers_scan() -> LogicalPlan {
946 LogicalPlanBuilder::scan(
947 NUMBERS_TABLE_NAME,
948 Arc::new(LogicalTableSource::new(
949 NumbersTable::schema().arrow_schema().clone(),
950 )),
951 None,
952 )
953 .unwrap()
954 .build()
955 .unwrap()
956 }
957
958 fn merge_scan(input: LogicalPlan, is_placeholder: bool) -> LogicalPlan {
959 MergeScanLogicalPlan::new(input, is_placeholder).into_logical_plan()
960 }
961
962 fn encode_plan(plan: &LogicalPlan) -> Bytes {
963 DFLogicalSubstraitConvertor
964 .encode(plan, DefaultSerializer)
965 .unwrap()
966 }
967
968 fn plan_decoder(engine: &dyn crate::QueryEngine) -> SubstraitPlanDecoderRef {
969 engine
970 .engine_context(QueryContext::arc())
971 .unwrap()
972 .new_plan_decoder()
973 .unwrap()
974 }
975
976 fn request_catalog_list() -> Arc<dyn CatalogProviderList> {
978 Arc::new(DummyCatalogList::with_table_provider(Arc::new(
979 mock_table_provider(1.into()),
980 )))
981 }
982
983 #[tokio::test]
985 async fn test_serializer_decode_payload_observes_catalog_and_query_context() {
986 let observed = Arc::new(std::sync::Mutex::new(Vec::new()));
987 let inner = catalog::memory::new_memory_catalog_manager().unwrap();
988 let manager: CatalogManagerRef = Arc::new(InterceptingCatalogManager {
989 inner,
990 resolution: TableResolution::ObserveContext(observed.clone()),
991 });
992 let mut resolver_ctx = QueryContext::arc();
993 Arc::make_mut(&mut resolver_ctx).set_current_catalog("request_cat");
994 Arc::make_mut(&mut resolver_ctx).set_current_schema("request_schema");
995 let engine = QueryEngineFactory::new(
996 manager,
997 None,
998 None,
999 None,
1000 None,
1001 false,
1002 QueryOptions::default(),
1003 )
1004 .query_engine();
1005 let mut state = engine
1006 .engine_context(resolver_ctx.clone())
1007 .unwrap()
1008 .state()
1009 .clone();
1010 state.config_mut().set_extension(resolver_ctx);
1011 let extensions = Extensions::default();
1012 let consumer = MergeScanSubstraitConsumer {
1013 inner: DefaultSubstraitConsumer::new(&extensions, &state),
1014 session_state: &state,
1015 catalog_manager: state
1016 .config()
1017 .get_extension::<QueryEngineState>()
1018 .map(|s| s.catalog_manager().clone()),
1019 payload: true,
1020 };
1021 for reference in [
1022 TableReference::bare(NUMBERS_TABLE_NAME),
1023 TableReference::partial("explicit_schema", NUMBERS_TABLE_NAME),
1024 TableReference::full(
1025 DEFAULT_CATALOG_NAME,
1026 DEFAULT_SCHEMA_NAME,
1027 NUMBERS_TABLE_NAME,
1028 ),
1029 ] {
1030 consumer
1031 .resolve_table_ref(&reference)
1032 .await
1033 .unwrap()
1034 .unwrap();
1035 }
1036 assert_eq!(
1037 *observed.lock().unwrap(),
1038 vec![
1039 [
1040 "request_cat".to_string(),
1041 "request_schema".to_string(),
1042 NUMBERS_TABLE_NAME.to_string(),
1043 "request_cat".to_string(),
1044 "request_schema".to_string(),
1045 ],
1046 [
1047 "request_cat".to_string(),
1048 "explicit_schema".to_string(),
1049 NUMBERS_TABLE_NAME.to_string(),
1050 "request_cat".to_string(),
1051 "request_schema".to_string(),
1052 ],
1053 [
1054 DEFAULT_CATALOG_NAME.to_string(),
1055 DEFAULT_SCHEMA_NAME.to_string(),
1056 NUMBERS_TABLE_NAME.to_string(),
1057 "request_cat".to_string(),
1058 "request_schema".to_string(),
1059 ],
1060 ],
1061 );
1062 }
1063
1064 enum TableResolution {
1066 ObserveContext(Arc<std::sync::Mutex<Vec<[String; 5]>>>),
1068 AwaitSignal {
1070 notify: Arc<tokio::sync::Notify>,
1071 entered: Arc<AtomicBool>,
1072 },
1073 }
1074
1075 struct InterceptingCatalogManager {
1077 inner: CatalogManagerRef,
1078 resolution: TableResolution,
1079 }
1080
1081 #[async_trait::async_trait]
1082 impl CatalogManager for InterceptingCatalogManager {
1083 fn as_any(&self) -> &dyn Any {
1084 self.inner.as_any()
1085 }
1086
1087 async fn catalog_names(&self) -> CatalogResult<Vec<String>> {
1088 self.inner.catalog_names().await
1089 }
1090
1091 async fn schema_names(
1092 &self,
1093 catalog: &str,
1094 query_ctx: Option<&QueryContext>,
1095 ) -> CatalogResult<Vec<String>> {
1096 self.inner.schema_names(catalog, query_ctx).await
1097 }
1098
1099 async fn table_names(
1100 &self,
1101 catalog: &str,
1102 schema: &str,
1103 query_ctx: Option<&QueryContext>,
1104 ) -> CatalogResult<Vec<String>> {
1105 self.inner.table_names(catalog, schema, query_ctx).await
1106 }
1107
1108 async fn catalog_exists(&self, catalog: &str) -> CatalogResult<bool> {
1109 self.inner.catalog_exists(catalog).await
1110 }
1111
1112 async fn schema_exists(
1113 &self,
1114 catalog: &str,
1115 schema: &str,
1116 query_ctx: Option<&QueryContext>,
1117 ) -> CatalogResult<bool> {
1118 self.inner.schema_exists(catalog, schema, query_ctx).await
1119 }
1120
1121 async fn table_exists(
1122 &self,
1123 catalog: &str,
1124 schema: &str,
1125 table: &str,
1126 query_ctx: Option<&QueryContext>,
1127 ) -> CatalogResult<bool> {
1128 self.inner
1129 .table_exists(catalog, schema, table, query_ctx)
1130 .await
1131 }
1132
1133 async fn table(
1134 &self,
1135 catalog: &str,
1136 schema: &str,
1137 table_name: &str,
1138 query_ctx: Option<&QueryContext>,
1139 ) -> CatalogResult<Option<TableRef>> {
1140 match &self.resolution {
1141 TableResolution::ObserveContext(observed) => {
1142 let query_ctx = query_ctx.unwrap();
1143 observed.lock().unwrap().push([
1144 catalog.to_string(),
1145 schema.to_string(),
1146 table_name.to_string(),
1147 query_ctx.current_catalog().to_string(),
1148 query_ctx.current_schema(),
1149 ]);
1150 Ok(Some(NumbersTable::table(NUMBERS_TABLE_ID)))
1151 }
1152
1153 TableResolution::AwaitSignal { notify, entered } => {
1154 entered.store(true, Ordering::SeqCst);
1155 notify.notified().await;
1156 self.inner
1157 .table(catalog, schema, table_name, query_ctx)
1158 .await
1159 }
1160 }
1161 }
1162
1163 async fn table_info_by_id(&self, table_id: TableId) -> CatalogResult<Option<TableInfoRef>> {
1164 self.inner.table_info_by_id(table_id).await
1165 }
1166
1167 async fn tables_by_ids(
1168 &self,
1169 catalog: &str,
1170 schema: &str,
1171 table_ids: &[TableId],
1172 ) -> CatalogResult<Vec<TableRef>> {
1173 self.inner.tables_by_ids(catalog, schema, table_ids).await
1174 }
1175
1176 fn tables<'a>(
1177 &'a self,
1178 catalog: &'a str,
1179 schema: &'a str,
1180 query_ctx: Option<&'a QueryContext>,
1181 ) -> BoxStream<'a, CatalogResult<TableRef>> {
1182 self.inner.tables(catalog, schema, query_ctx)
1183 }
1184 }
1185
1186 fn engine_with_intercepting_catalog(
1187 resolution: TableResolution,
1188 ) -> Arc<dyn crate::QueryEngine> {
1189 let catalog_manager: CatalogManagerRef = Arc::new(InterceptingCatalogManager {
1190 inner: numbers_catalog_manager(),
1191 resolution,
1192 });
1193 QueryEngineFactory::new(
1194 catalog_manager,
1195 None,
1196 None,
1197 None,
1198 None,
1199 false,
1200 QueryOptions::default(),
1201 )
1202 .query_engine()
1203 }
1204
1205 #[tokio::test(flavor = "current_thread")]
1210 async fn test_serializer_decode_merge_scan_awaits_caller_runtime_task() {
1211 let notify = Arc::new(tokio::sync::Notify::new());
1212 let entered = Arc::new(AtomicBool::new(false));
1213 let engine = engine_with_intercepting_catalog(TableResolution::AwaitSignal {
1214 notify: notify.clone(),
1215 entered: entered.clone(),
1216 });
1217 let plan = merge_scan(numbers_scan(), false);
1218 let bytes = encode_plan(&plan);
1219
1220 let decoder = plan_decoder(engine.as_ref());
1221 let mut decode = Box::pin(decoder.decode(bytes, request_catalog_list(), false));
1222 assert!(futures::poll!(decode.as_mut()).is_pending());
1224 assert!(entered.load(Ordering::SeqCst));
1225
1226 let signal = tokio::spawn(async move {
1227 notify.notify_waiters();
1228 });
1229 tokio::task::yield_now().await;
1230 let decoded = decode.await.unwrap();
1231 signal.await.unwrap();
1232
1233 assert_eq!(decoded.to_string(), plan.to_string());
1234 }
1235
1236 #[tokio::test]
1238 async fn test_serializer_decode_missing_engine_catalog_table() {
1239 let missing_manager: CatalogManagerRef =
1240 catalog::memory::new_memory_catalog_manager().unwrap();
1241 let engine = QueryEngineFactory::new(
1242 missing_manager,
1243 None,
1244 None,
1245 None,
1246 None,
1247 false,
1248 QueryOptions::default(),
1249 )
1250 .query_engine();
1251 let bytes = encode_plan(&merge_scan(numbers_scan(), false));
1252
1253 let err = plan_decoder(engine.as_ref())
1254 .decode(bytes, request_catalog_list(), false)
1255 .await
1256 .unwrap_err();
1257
1258 let err = format!("{err:?}");
1259 assert!(
1260 err.contains("Table not found: greptime.public.numbers"),
1261 "unexpected error: {err}"
1262 );
1263 }
1264
1265 #[tokio::test]
1267 async fn test_serializer_decode_manual_state_keeps_extension_registry() {
1268 let manager = catalog::memory::new_memory_catalog_manager().unwrap();
1269 manager.register_catalog_sync("manual_cat").unwrap();
1270 manager
1271 .register_schema_sync(catalog::RegisterSchemaRequest {
1272 catalog: "manual_cat".to_string(),
1273 schema: "manual_schema".to_string(),
1274 })
1275 .unwrap();
1276 manager
1277 .register_table_sync(RegisterTableRequest {
1278 catalog: "manual_cat".to_string(),
1279 schema: "manual_schema".to_string(),
1280 table_name: NUMBERS_TABLE_NAME.to_string(),
1281 table_id: NUMBERS_TABLE_ID,
1282 table: NumbersTable::table(NUMBERS_TABLE_ID),
1283 })
1284 .unwrap();
1285 let query_ctx = Arc::new(QueryContext::with("manual_cat", "manual_schema"));
1286 let mut config = datafusion::execution::context::SessionConfig::new()
1287 .with_information_schema(true)
1288 .with_default_catalog_and_schema("manual_cat", "manual_schema");
1289 config.set_extension(query_ctx.clone());
1290 let state = SessionStateBuilder::new()
1291 .with_default_features()
1292 .with_config(config)
1293 .build();
1294 let decoder = DefaultPlanDecoder::new(state, &query_ctx).unwrap();
1295 let plan = LogicalPlan::Extension(Extension {
1296 node: Arc::new(SeriesNormalize::new(
1297 0,
1298 "number",
1299 false,
1300 Vec::new(),
1301 merge_scan(numbers_scan(), false),
1302 )),
1303 });
1304 let request_catalog = Arc::new(
1305 catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
1306 manager, query_ctx,
1307 ),
1308 );
1309 let decoded = decoder
1310 .decode(encode_plan(&plan), request_catalog, false)
1311 .await
1312 .unwrap();
1313
1314 assert_eq!(decoded.to_string(), plan.to_string());
1315 assert_eq!(decoded.schema().as_arrow(), plan.schema().as_arrow());
1316 }
1317
1318 #[tokio::test]
1320 async fn test_serializer_decode_merge_scan_under_series_normalize() {
1321 let outer = merge_scan(numbers_scan(), false);
1322 let plan = LogicalPlan::Extension(Extension {
1323 node: Arc::new(SeriesNormalize::new(
1324 0,
1325 "number",
1326 false,
1327 Vec::new(),
1328 outer.clone(),
1329 )),
1330 });
1331 let bytes = encode_plan(&plan);
1332
1333 let decoded = plan_decoder(
1334 QueryEngineFactory::new(
1335 numbers_catalog_manager(),
1336 None,
1337 None,
1338 None,
1339 None,
1340 false,
1341 QueryOptions::default(),
1342 )
1343 .query_engine()
1344 .as_ref(),
1345 )
1346 .decode(bytes, request_catalog_list(), false)
1347 .await
1348 .unwrap();
1349
1350 let LogicalPlan::Extension(extension) = &decoded else {
1351 panic!("Expect a SeriesNormalize plan, got: {decoded}");
1352 };
1353 let normalize = extension
1354 .node
1355 .as_any()
1356 .downcast_ref::<SeriesNormalize>()
1357 .expect("Expect a SeriesNormalize plan node");
1358 assert_eq!(normalize.inputs()[0].to_string(), outer.to_string());
1359 }
1360
1361 #[tokio::test]
1363 async fn test_serializer_decode_merge_scan_under_union_distinct_on() {
1364 let left = merge_scan(numbers_scan(), false);
1365 let right = merge_scan(numbers_scan(), true);
1366 let plan = LogicalPlan::Extension(Extension {
1367 node: Arc::new(
1368 UnionDistinctOn::try_new(left.clone(), right.clone(), vec![], 0).unwrap(),
1369 ),
1370 });
1371 let bytes = encode_plan(&plan);
1372
1373 let decoded = plan_decoder(
1374 QueryEngineFactory::new(
1375 numbers_catalog_manager(),
1376 None,
1377 None,
1378 None,
1379 None,
1380 false,
1381 QueryOptions::default(),
1382 )
1383 .query_engine()
1384 .as_ref(),
1385 )
1386 .decode(bytes, request_catalog_list(), false)
1387 .await
1388 .unwrap();
1389
1390 let LogicalPlan::Extension(extension) = &decoded else {
1391 panic!("Expect a UnionDistinctOn plan, got: {decoded}");
1392 };
1393 let union = extension
1394 .node
1395 .as_any()
1396 .downcast_ref::<UnionDistinctOn>()
1397 .expect("Expect a UnionDistinctOn plan node");
1398 assert_eq!(union.inputs()[0].to_string(), left.to_string());
1399 assert_eq!(union.inputs()[1].to_string(), right.to_string());
1400 }
1401
1402 #[tokio::test]
1407 async fn test_serializer_decode_merge_scan_inside_subquery() {
1408 let inner = merge_scan(numbers_scan(), false);
1409 let payload = LogicalPlanBuilder::from(numbers_scan())
1410 .filter(Expr::InSubquery(InSubquery::new(
1411 Box::new(col("number")),
1412 Subquery {
1413 subquery: Arc::new(inner.clone()),
1414 outer_ref_columns: vec![],
1415 spans: Default::default(),
1416 },
1417 false,
1418 )))
1419 .unwrap()
1420 .build()
1421 .unwrap();
1422 let plan = merge_scan(payload.clone(), false);
1423 let bytes = encode_plan(&plan);
1424
1425 let decoded = plan_decoder(
1426 QueryEngineFactory::new(
1427 numbers_catalog_manager(),
1428 None,
1429 None,
1430 None,
1431 None,
1432 false,
1433 QueryOptions::default(),
1434 )
1435 .query_engine()
1436 .as_ref(),
1437 )
1438 .decode(bytes, request_catalog_list(), false)
1439 .await
1440 .unwrap();
1441
1442 assert_eq!(decoded.to_string().matches("MergeScan [").count(), 2);
1443 assert!(
1444 decoded.to_string().contains("IN (<subquery>)"),
1445 "expect the decoded subquery filter, got: {decoded}"
1446 );
1447 }
1448
1449 #[tokio::test]
1451 async fn test_serializer_decode_payload_keeps_state_udaf_ordering() {
1452 let last_value = (*datafusion::functions_aggregate::first_last::last_value_udaf()).clone();
1453 let state_udaf = AggregateUDF::new_from_impl(StateWrapper::new(last_value).unwrap());
1454 let aggr_expr = Expr::AggregateFunction(AggregateFunction::new_udf(
1455 Arc::new(state_udaf),
1456 vec![col("number")],
1457 false,
1458 None,
1459 vec![Sort::new(col("number"), true, true)],
1460 None,
1461 ));
1462 let payload = LogicalPlanBuilder::from(numbers_scan())
1463 .aggregate(Vec::<Expr>::new(), vec![aggr_expr])
1464 .unwrap()
1465 .build()
1466 .unwrap();
1467 let bytes = encode_plan(&payload);
1468 let encoded = Plan::decode(bytes.clone()).unwrap();
1469 let extensions = Extensions::try_from(&encoded.extensions).unwrap();
1470 let catalog_manager = numbers_catalog_manager();
1471 let engine = QueryEngineFactory::new(
1472 catalog_manager.clone(),
1473 None,
1474 None,
1475 None,
1476 None,
1477 false,
1478 QueryOptions::default(),
1479 )
1480 .query_engine();
1481 let mut state = SessionStateBuilder::new_from_existing(
1482 engine
1483 .engine_context(QueryContext::arc())
1484 .unwrap()
1485 .state()
1486 .clone(),
1487 )
1488 .with_serializer_registry(Arc::new(DefaultSerializer))
1489 .build();
1490 register_greptime_functions(&mut state, &QueryContext::arc()).unwrap();
1491 let consumer = MergeScanSubstraitConsumer {
1492 inner: DefaultSubstraitConsumer::new(&extensions, &state),
1493 session_state: &state,
1494 catalog_manager: Some(catalog_manager),
1495 payload: false,
1496 };
1497 let decoded = consumer.decode_payload(bytes.to_vec()).await.unwrap();
1498
1499 let fixed_payload = FixStateUdafOrderingAnalyzer {}
1500 .analyze(payload.clone(), &Default::default())
1501 .unwrap();
1502 assert_ne!(
1503 fixed_payload.schema().as_arrow(),
1504 payload.schema().as_arrow()
1505 );
1506 assert_eq!(
1507 decoded.schema().as_arrow(),
1508 fixed_payload.schema().as_arrow()
1509 );
1510 let LogicalPlan::Aggregate(aggregate) = &decoded else {
1511 panic!("Expected an aggregate payload, got: {decoded}");
1512 };
1513 let Expr::AggregateFunction(function) = &aggregate.aggr_expr[0] else {
1514 panic!("Expected a state aggregate, got: {:?}", aggregate.aggr_expr);
1515 };
1516 assert!(function.func.inner().is::<StateWrapper>());
1517 assert_eq!(function.params.order_by.len(), 1);
1518 let ArrowDataType::Struct(fields) = decoded.schema().field(0).data_type() else {
1519 panic!("Expected the ordered aggregate state type");
1520 };
1521 assert_eq!(fields.len(), 3);
1522 assert_eq!(fields[1].name(), "number");
1523 assert!(fields[1].is_nullable());
1524 }
1525
1526 #[tokio::test]
1528 async fn test_serializer_decode_rejects_type_variations() {
1529 use substrait::substrait_proto_df::proto::extensions::SimpleExtensionDeclaration;
1530 use substrait::substrait_proto_df::proto::extensions::simple_extension_declaration::{
1531 ExtensionTypeVariation, MappingType,
1532 };
1533
1534 let engine = QueryEngineFactory::new(
1535 numbers_catalog_manager(),
1536 None,
1537 None,
1538 None,
1539 None,
1540 false,
1541 QueryOptions::default(),
1542 )
1543 .query_engine();
1544 let encoded = encode_plan(&merge_scan(numbers_scan(), false));
1545 let mut substrait_plan = Plan::decode(encoded).unwrap();
1546 substrait_plan.extensions.push(SimpleExtensionDeclaration {
1547 mapping_type: Some(MappingType::ExtensionTypeVariation(
1548 ExtensionTypeVariation {
1549 extension_urn_reference: u32::MAX,
1550 type_variation_anchor: 1,
1551 name: "u!variation".to_string(),
1552 },
1553 )),
1554 });
1555 let bytes = Bytes::from(substrait_plan.encode_to_vec());
1556
1557 let err = plan_decoder(engine.as_ref())
1558 .decode(bytes, request_catalog_list(), false)
1559 .await
1560 .unwrap_err();
1561
1562 let err = format!("{err:?}");
1563 assert!(
1564 err.contains("Type variation extensions are not supported"),
1565 "unexpected error: {err}"
1566 );
1567 }
1568}