1use std::fmt::{self, Display};
16use std::future::Future;
17use std::marker::PhantomData;
18use std::pin::Pin;
19use std::str::FromStr;
20use std::sync::Arc;
21use std::task::{Context, Poll};
22
23use common_base::readable_size::ReadableSize;
24use common_telemetry::tracing::{Span, info_span};
25use common_time::util::format_nanoseconds_human_readable;
26use datafusion::arrow::compute::cast;
27use datafusion::arrow::datatypes::SchemaRef as DfSchemaRef;
28use datafusion::error::Result as DfResult;
29use datafusion::execution::context::ExecutionProps;
30use datafusion::logical_expr::Expr;
31use datafusion::logical_expr::utils::conjunction;
32use datafusion::physical_expr::create_physical_expr;
33use datafusion::physical_plan::metrics::{BaselineMetrics, MetricValue};
34use datafusion::physical_plan::{
35 DisplayFormatType, ExecutionPlan, ExecutionPlanVisitor, PhysicalExpr,
36 RecordBatchStream as DfRecordBatchStream, accept,
37};
38use datafusion_common::arrow::error::ArrowError;
39use datafusion_common::{DataFusionError, ToDFSchema};
40use datatypes::arrow::array::Array;
41use datatypes::arrow::datatypes::DataType as ArrowDataType;
42use datatypes::schema::{ColumnExtType, Schema, SchemaRef};
43use futures::ready;
44use jsonb;
45use pin_project::pin_project;
46use snafu::ResultExt;
47
48use crate::error::{self, Result};
49use crate::filter::batch_filter;
50use crate::{
51 DfRecordBatch, DfSendableRecordBatchStream, OrderOption, RecordBatch, RecordBatchStream,
52 SendableRecordBatchStream, Stream,
53};
54
55type FutureStream =
56 Pin<Box<dyn std::future::Future<Output = Result<SendableRecordBatchStream>> + Send>>;
57
58#[pin_project]
60pub struct RecordBatchStreamTypeAdapter<T, E> {
61 #[pin]
62 stream: T,
63 projected_schema: DfSchemaRef,
64 projection: Vec<usize>,
65 predicate: Option<Arc<dyn PhysicalExpr>>,
66 phantom: PhantomData<E>,
67}
68
69impl<T, E> RecordBatchStreamTypeAdapter<T, E>
70where
71 T: Stream<Item = std::result::Result<DfRecordBatch, E>>,
72 E: std::error::Error + Send + Sync + 'static,
73{
74 pub fn new(projected_schema: DfSchemaRef, stream: T, projection: Option<Vec<usize>>) -> Self {
75 let projection = if let Some(projection) = projection {
76 projection
77 } else {
78 (0..projected_schema.fields().len()).collect()
79 };
80
81 Self {
82 stream,
83 projected_schema,
84 projection,
85 predicate: None,
86 phantom: Default::default(),
87 }
88 }
89
90 pub fn with_filter(mut self, filters: Vec<Expr>) -> Result<Self> {
91 let filters = if let Some(expr) = conjunction(filters) {
92 let df_schema = self
93 .projected_schema
94 .clone()
95 .to_dfschema_ref()
96 .context(error::PhysicalExprSnafu)?;
97
98 let filters = create_physical_expr(&expr, &df_schema, &ExecutionProps::new())
99 .context(error::PhysicalExprSnafu)?;
100 Some(filters)
101 } else {
102 None
103 };
104 self.predicate = filters;
105 Ok(self)
106 }
107}
108
109impl<T, E> DfRecordBatchStream for RecordBatchStreamTypeAdapter<T, E>
110where
111 T: Stream<Item = std::result::Result<DfRecordBatch, E>>,
112 E: std::error::Error + Send + Sync + 'static,
113{
114 fn schema(&self) -> DfSchemaRef {
115 self.projected_schema.clone()
116 }
117}
118
119impl<T, E> Stream for RecordBatchStreamTypeAdapter<T, E>
120where
121 T: Stream<Item = std::result::Result<DfRecordBatch, E>>,
122 E: std::error::Error + Send + Sync + 'static,
123{
124 type Item = DfResult<DfRecordBatch>;
125
126 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
127 let this = self.project();
128
129 let batch = futures::ready!(this.stream.poll_next(cx))
130 .map(|r| r.map_err(|e| DataFusionError::External(Box::new(e))));
131
132 let projected_schema = this.projected_schema.clone();
133 let projection = this.projection.clone();
134 let predicate = this.predicate.clone();
135
136 let batch = batch.map(|b| {
137 b.and_then(|b| {
138 let projected_column = b.project(&projection)?;
139 if projected_column.schema().fields.len() != projected_schema.fields.len() {
140 return Err(DataFusionError::ArrowError(Box::new(ArrowError::SchemaError(format!(
141 "Trying to cast a RecordBatch into an incompatible schema. RecordBatch: {}, Target: {}",
142 projected_column.schema(),
143 projected_schema,
144 ))), None));
145 }
146
147 let mut columns = Vec::with_capacity(projected_schema.fields.len());
148 for (idx,field) in projected_schema.fields.iter().enumerate() {
149 let column = projected_column.column(idx);
150 let extype = field.metadata().get("greptime:type").and_then(|s| ColumnExtType::from_str(s).ok());
151 let output = custom_cast(&column, field.data_type(), extype)?;
152 columns.push(output)
153 }
154 let record_batch = DfRecordBatch::try_new(projected_schema, columns)?;
155 let record_batch = if let Some(predicate) = predicate {
156 batch_filter(&record_batch, &predicate)?
157 } else {
158 record_batch
159 };
160 Ok(record_batch)
161 })
162 });
163
164 Poll::Ready(batch)
165 }
166
167 #[inline]
168 fn size_hint(&self) -> (usize, Option<usize>) {
169 self.stream.size_hint()
170 }
171}
172
173pub struct DfRecordBatchStreamAdapter {
176 stream: SendableRecordBatchStream,
177}
178
179impl DfRecordBatchStreamAdapter {
180 pub fn new(stream: SendableRecordBatchStream) -> Self {
181 Self { stream }
182 }
183}
184
185impl DfRecordBatchStream for DfRecordBatchStreamAdapter {
186 fn schema(&self) -> DfSchemaRef {
187 self.stream.schema().arrow_schema().clone()
188 }
189}
190
191impl Stream for DfRecordBatchStreamAdapter {
192 type Item = DfResult<DfRecordBatch>;
193
194 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
195 match Pin::new(&mut self.stream).poll_next(cx) {
196 Poll::Pending => Poll::Pending,
197 Poll::Ready(Some(recordbatch)) => match recordbatch {
198 Ok(recordbatch) => Poll::Ready(Some(Ok(recordbatch.into_df_record_batch()))),
199 Err(e) => Poll::Ready(Some(Err(DataFusionError::External(Box::new(e))))),
200 },
201 Poll::Ready(None) => Poll::Ready(None),
202 }
203 }
204
205 #[inline]
206 fn size_hint(&self) -> (usize, Option<usize>) {
207 self.stream.size_hint()
208 }
209}
210
211pub struct RecordBatchStreamAdapter {
215 schema: SchemaRef,
216 stream: DfSendableRecordBatchStream,
217 metrics: Option<BaselineMetrics>,
218 metrics_2: Metrics,
220 explain_verbose: bool,
222 span: Span,
223}
224
225enum Metrics {
227 Unavailable,
228 Unresolved(Arc<dyn ExecutionPlan>),
229 PartialResolved(Arc<dyn ExecutionPlan>, RecordBatchMetrics),
230 Resolved(RecordBatchMetrics),
231}
232
233impl RecordBatchStreamAdapter {
234 pub fn try_new(stream: DfSendableRecordBatchStream) -> Result<Self> {
235 let schema =
236 Arc::new(Schema::try_from(stream.schema()).context(error::SchemaConversionSnafu)?);
237 Ok(Self {
238 schema,
239 stream,
240 metrics: None,
241 metrics_2: Metrics::Unavailable,
242 explain_verbose: false,
243 span: Span::current(),
244 })
245 }
246
247 pub fn try_new_with_span(stream: DfSendableRecordBatchStream, span: Span) -> Result<Self> {
248 let schema =
249 Arc::new(Schema::try_from(stream.schema()).context(error::SchemaConversionSnafu)?);
250 let subspan = info_span!(parent: &span, "RecordBatchStreamAdapter");
251 Ok(Self {
252 schema,
253 stream,
254 metrics: None,
255 metrics_2: Metrics::Unavailable,
256 explain_verbose: false,
257 span: subspan,
258 })
259 }
260
261 pub fn set_metrics2(&mut self, plan: Arc<dyn ExecutionPlan>) {
262 self.metrics_2 = Metrics::Unresolved(plan)
263 }
264
265 pub fn set_explain_verbose(&mut self, verbose: bool) {
267 self.explain_verbose = verbose;
268 }
269}
270
271impl RecordBatchStream for RecordBatchStreamAdapter {
272 fn name(&self) -> &str {
273 "RecordBatchStreamAdapter"
274 }
275
276 fn schema(&self) -> SchemaRef {
277 self.schema.clone()
278 }
279
280 fn metrics(&self) -> Option<RecordBatchMetrics> {
281 match &self.metrics_2 {
282 Metrics::Resolved(metrics) | Metrics::PartialResolved(_, metrics) => {
283 Some(metrics.clone())
284 }
285 Metrics::Unavailable | Metrics::Unresolved(_) => None,
286 }
287 }
288
289 fn output_ordering(&self) -> Option<&[OrderOption]> {
290 None
291 }
292}
293
294impl Stream for RecordBatchStreamAdapter {
295 type Item = Result<RecordBatch>;
296
297 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
298 let timer = self
299 .metrics
300 .as_ref()
301 .map(|m| m.elapsed_compute().clone())
302 .unwrap_or_default();
303 let _guard = timer.timer();
304 let poll_span = info_span!(parent: &self.span, "poll_next");
305 let _entered = poll_span.enter();
306 match Pin::new(&mut self.stream).poll_next(cx) {
307 Poll::Pending => Poll::Pending,
308 Poll::Ready(Some(df_record_batch)) => {
309 let df_record_batch = df_record_batch?;
310 if let Metrics::Unresolved(df_plan) | Metrics::PartialResolved(df_plan, _) =
311 &self.metrics_2
312 {
313 let mut metric_collector = MetricCollector::new(self.explain_verbose);
314 accept(df_plan.as_ref(), &mut metric_collector).unwrap();
315 self.metrics_2 = Metrics::PartialResolved(
316 df_plan.clone(),
317 metric_collector.record_batch_metrics,
318 );
319 }
320 Poll::Ready(Some(Ok(RecordBatch::from_df_record_batch(
321 self.schema(),
322 df_record_batch,
323 ))))
324 }
325 Poll::Ready(None) => {
326 if let Metrics::Unresolved(df_plan) | Metrics::PartialResolved(df_plan, _) =
327 &self.metrics_2
328 {
329 let mut metric_collector = MetricCollector::new(self.explain_verbose);
330 accept(df_plan.as_ref(), &mut metric_collector).unwrap();
331 self.metrics_2 = Metrics::Resolved(metric_collector.record_batch_metrics);
332 }
333 Poll::Ready(None)
334 }
335 }
336 }
337
338 #[inline]
339 fn size_hint(&self) -> (usize, Option<usize>) {
340 self.stream.size_hint()
341 }
342}
343
344pub struct MetricCollector {
346 current_level: usize,
347 pub record_batch_metrics: RecordBatchMetrics,
348 verbose: bool,
349}
350
351impl MetricCollector {
352 pub fn new(verbose: bool) -> Self {
353 Self {
354 current_level: 0,
355 record_batch_metrics: RecordBatchMetrics::default(),
356 verbose,
357 }
358 }
359}
360
361impl ExecutionPlanVisitor for MetricCollector {
362 type Error = !;
363
364 fn pre_visit(&mut self, plan: &dyn ExecutionPlan) -> std::result::Result<bool, Self::Error> {
365 let Some(metric) = plan.metrics() else {
367 self.record_batch_metrics.plan_metrics.push(PlanMetrics {
368 plan: plan.name().to_string(),
369 plan_name: plan.name().to_string(),
370 level: self.current_level,
371 metrics: vec![],
372 });
373 self.current_level += 1;
374 return Ok(true);
375 };
376
377 let metric = metric
379 .aggregate_by_name()
380 .sorted_for_display()
381 .timestamps_removed();
382 let mut plan_metric = PlanMetrics {
383 plan: one_line(plan, self.verbose).to_string(),
384 plan_name: plan.name().to_string(),
385 level: self.current_level,
386 metrics: Vec::with_capacity(metric.iter().size_hint().0),
387 };
388 for m in metric.iter() {
389 plan_metric
390 .metrics
391 .push((m.value().name().to_string(), m.value().as_usize()));
392
393 match m.value() {
395 MetricValue::ElapsedCompute(ec) => {
396 self.record_batch_metrics.elapsed_compute += ec.value()
397 }
398 MetricValue::CurrentMemoryUsage(m) => {
399 self.record_batch_metrics.memory_usage += m.value()
400 }
401 _ => {}
402 }
403 }
404 self.record_batch_metrics.plan_metrics.push(plan_metric);
405
406 self.current_level += 1;
407 Ok(true)
408 }
409
410 fn post_visit(&mut self, _plan: &dyn ExecutionPlan) -> std::result::Result<bool, Self::Error> {
411 self.current_level -= 1;
412 Ok(true)
413 }
414}
415
416fn one_line(plan: &dyn ExecutionPlan, verbose: bool) -> impl fmt::Display + '_ {
419 struct Wrapper<'a> {
420 plan: &'a dyn ExecutionPlan,
421 format_type: DisplayFormatType,
422 }
423
424 impl fmt::Display for Wrapper<'_> {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 self.plan.fmt_as(self.format_type, f)?;
427 writeln!(f)
428 }
429 }
430
431 let format_type = if verbose {
432 DisplayFormatType::Verbose
433 } else {
434 DisplayFormatType::Default
435 };
436 Wrapper { plan, format_type }
437}
438
439#[derive(serde::Serialize, serde::Deserialize, Default, Debug, Clone)]
442pub struct RecordBatchMetrics {
443 pub elapsed_compute: usize,
446 pub memory_usage: usize,
448 pub plan_metrics: Vec<PlanMetrics>,
451 #[serde(default, skip_serializing_if = "Vec::is_empty")]
464 pub region_watermarks: Vec<RegionWatermarkEntry>,
465}
466
467#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
468pub struct RegionWatermarkEntry {
469 pub region_id: u64,
470 #[serde(default, skip_serializing_if = "Option::is_none")]
471 pub watermark: Option<u64>,
472}
473
474fn is_time_metric(metric_name: &str) -> bool {
476 metric_name.contains("elapsed") || metric_name.contains("time") || metric_name.contains("cost")
477}
478
479fn is_bytes_metric(metric_name: &str) -> bool {
481 metric_name.contains("bytes") || metric_name.contains("mem")
482}
483
484fn format_bytes_human_readable(bytes: usize) -> String {
485 format!("{}", ReadableSize(bytes as u64))
486}
487
488impl Display for RecordBatchMetrics {
490 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491 for metric in &self.plan_metrics {
492 write!(
493 f,
494 "{:indent$}{} metrics=[",
495 " ",
496 metric.plan.trim_end(),
497 indent = metric.level * 2,
498 )?;
499 for (label, value) in &metric.metrics {
500 if is_time_metric(label) {
501 write!(
502 f,
503 "{}: {}, ",
504 label,
505 format_nanoseconds_human_readable(*value),
506 )?;
507 } else if is_bytes_metric(label) {
508 write!(f, "{}: {}, ", label, format_bytes_human_readable(*value),)?;
509 } else {
510 write!(f, "{}: {}, ", label, value)?;
511 }
512 }
513 writeln!(f, "]")?;
514 }
515
516 Ok(())
517 }
518}
519
520#[derive(serde::Serialize, serde::Deserialize, Default, Debug, Clone)]
521pub struct PlanMetrics {
522 pub plan: String,
524 #[serde(default)]
526 pub plan_name: String,
527 pub level: usize,
529 pub metrics: Vec<(String, usize)>,
532}
533
534enum AsyncRecordBatchStreamAdapterState {
535 Uninit(FutureStream),
536 Ready(SendableRecordBatchStream),
537 Failed,
538}
539
540pub struct AsyncRecordBatchStreamAdapter {
541 schema: SchemaRef,
542 state: AsyncRecordBatchStreamAdapterState,
543}
544
545impl AsyncRecordBatchStreamAdapter {
546 pub fn new(schema: SchemaRef, stream: FutureStream) -> Self {
547 Self {
548 schema,
549 state: AsyncRecordBatchStreamAdapterState::Uninit(stream),
550 }
551 }
552}
553
554impl RecordBatchStream for AsyncRecordBatchStreamAdapter {
555 fn schema(&self) -> SchemaRef {
556 self.schema.clone()
557 }
558
559 fn output_ordering(&self) -> Option<&[OrderOption]> {
560 None
561 }
562
563 fn metrics(&self) -> Option<RecordBatchMetrics> {
564 None
565 }
566}
567
568impl Stream for AsyncRecordBatchStreamAdapter {
569 type Item = Result<RecordBatch>;
570
571 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
572 loop {
573 match &mut self.state {
574 AsyncRecordBatchStreamAdapterState::Uninit(stream_future) => {
575 match ready!(Pin::new(stream_future).poll(cx)) {
576 Ok(stream) => {
577 self.state = AsyncRecordBatchStreamAdapterState::Ready(stream);
578 continue;
579 }
580 Err(e) => {
581 self.state = AsyncRecordBatchStreamAdapterState::Failed;
582 return Poll::Ready(Some(Err(e)));
583 }
584 };
585 }
586 AsyncRecordBatchStreamAdapterState::Ready(stream) => {
587 return Poll::Ready(ready!(Pin::new(stream).poll_next(cx)));
588 }
589 AsyncRecordBatchStreamAdapterState::Failed => return Poll::Ready(None),
590 }
591 }
592 }
593
594 #[inline]
596 fn size_hint(&self) -> (usize, Option<usize>) {
597 (0, None)
598 }
599}
600
601fn custom_cast(
603 array: &dyn Array,
604 target_type: &ArrowDataType,
605 extype: Option<ColumnExtType>,
606) -> std::result::Result<Arc<dyn Array>, ArrowError> {
607 if let ArrowDataType::Map(_, _) = array.data_type()
608 && let ArrowDataType::Binary = target_type
609 {
610 return convert_map_to_json_binary(array, extype);
611 }
612
613 cast(array, target_type)
614}
615
616fn convert_map_to_json_binary(
618 array: &dyn Array,
619 extype: Option<ColumnExtType>,
620) -> std::result::Result<Arc<dyn Array>, ArrowError> {
621 use datatypes::arrow::array::{BinaryArray, MapArray};
622 use serde_json::Value;
623
624 let map_array = array
625 .as_any()
626 .downcast_ref::<MapArray>()
627 .ok_or_else(|| ArrowError::CastError("Failed to downcast to MapArray".to_string()))?;
628
629 let mut json_values = Vec::with_capacity(map_array.len());
630
631 for i in 0..map_array.len() {
632 if map_array.is_null(i) {
633 json_values.push(None);
634 } else {
635 let map_entry = map_array.value(i);
637 let key_value_array = map_entry
638 .as_any()
639 .downcast_ref::<datatypes::arrow::array::StructArray>()
640 .ok_or_else(|| {
641 ArrowError::CastError("Failed to downcast to StructArray".to_string())
642 })?;
643
644 let mut json_obj = serde_json::Map::with_capacity(key_value_array.len());
646
647 for j in 0..key_value_array.len() {
648 if key_value_array.is_null(j) {
649 continue;
650 }
651 let key_field = key_value_array.column(0);
652 let value_field = key_value_array.column(1);
653
654 if key_field.is_null(j) {
655 continue;
656 }
657
658 let key = key_field
659 .as_any()
660 .downcast_ref::<datatypes::arrow::array::StringArray>()
661 .ok_or_else(|| {
662 ArrowError::CastError("Failed to downcast key to StringArray".to_string())
663 })?
664 .value(j);
665
666 let value = if value_field.is_null(j) {
667 Value::Null
668 } else {
669 let value_str = value_field
670 .as_any()
671 .downcast_ref::<datatypes::arrow::array::StringArray>()
672 .ok_or_else(|| {
673 ArrowError::CastError(
674 "Failed to downcast value to StringArray".to_string(),
675 )
676 })?
677 .value(j);
678 Value::String(value_str.to_string())
679 };
680
681 json_obj.insert(key.to_string(), value);
682 }
683
684 let json_value = Value::Object(json_obj);
685 let json_bytes = match extype {
686 Some(ColumnExtType::Json) => {
687 let json_string = match serde_json::to_string(&json_value) {
688 Ok(s) => s,
689 Err(e) => {
690 return Err(ArrowError::CastError(format!(
691 "Failed to serialize JSON: {}",
692 e
693 )));
694 }
695 };
696 match jsonb::parse_value(json_string.as_bytes()) {
697 Ok(jsonb_value) => jsonb_value.to_vec(),
698 Err(e) => {
699 return Err(ArrowError::CastError(format!(
700 "Failed to serialize JSONB: {}",
701 e
702 )));
703 }
704 }
705 }
706 _ => match serde_json::to_vec(&json_value) {
707 Ok(b) => b,
708 Err(e) => {
709 return Err(ArrowError::CastError(format!(
710 "Failed to serialize JSON: {}",
711 e
712 )));
713 }
714 },
715 };
716 json_values.push(Some(json_bytes));
717 }
718 }
719
720 let binary_array = BinaryArray::from_iter(json_values);
721 Ok(Arc::new(binary_array))
722}
723
724#[cfg(test)]
725mod test {
726 use common_error::ext::BoxedError;
727 use common_error::mock::MockError;
728 use common_error::status_code::StatusCode;
729 use datatypes::arrow::array::{ArrayRef, MapArray, StringArray, StructArray};
730 use datatypes::arrow::buffer::OffsetBuffer;
731 use datatypes::arrow::datatypes::Field;
732 use datatypes::prelude::ConcreteDataType;
733 use datatypes::schema::ColumnSchema;
734 use datatypes::vectors::Int32Vector;
735 use serde_json::json;
736 use snafu::IntoError;
737
738 use super::*;
739 use crate::RecordBatches;
740 use crate::error::Error;
741
742 #[tokio::test]
743 async fn test_async_recordbatch_stream_adaptor() {
744 struct MaybeErrorRecordBatchStream {
745 items: Vec<Result<RecordBatch>>,
746 }
747
748 impl RecordBatchStream for MaybeErrorRecordBatchStream {
749 fn schema(&self) -> SchemaRef {
750 unimplemented!()
751 }
752
753 fn output_ordering(&self) -> Option<&[OrderOption]> {
754 None
755 }
756
757 fn metrics(&self) -> Option<RecordBatchMetrics> {
758 None
759 }
760 }
761
762 impl Stream for MaybeErrorRecordBatchStream {
763 type Item = Result<RecordBatch>;
764
765 fn poll_next(
766 mut self: Pin<&mut Self>,
767 _: &mut Context<'_>,
768 ) -> Poll<Option<Self::Item>> {
769 if let Some(batch) = self.items.pop() {
770 Poll::Ready(Some(Ok(batch?)))
771 } else {
772 Poll::Ready(None)
773 }
774 }
775 }
776
777 fn new_future_stream(
778 maybe_recordbatches: Result<Vec<Result<RecordBatch>>>,
779 ) -> FutureStream {
780 Box::pin(async move {
781 maybe_recordbatches
782 .map(|items| Box::pin(MaybeErrorRecordBatchStream { items }) as _)
783 })
784 }
785
786 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
787 "a",
788 ConcreteDataType::int32_datatype(),
789 false,
790 )]));
791 let batch1 = RecordBatch::new(
792 schema.clone(),
793 vec![Arc::new(Int32Vector::from_slice([1])) as _],
794 )
795 .unwrap();
796 let batch2 = RecordBatch::new(
797 schema.clone(),
798 vec![Arc::new(Int32Vector::from_slice([2])) as _],
799 )
800 .unwrap();
801
802 let success_stream = new_future_stream(Ok(vec![Ok(batch1.clone()), Ok(batch2.clone())]));
803 let adapter = AsyncRecordBatchStreamAdapter::new(schema.clone(), success_stream);
804 let collected = RecordBatches::try_collect(Box::pin(adapter)).await.unwrap();
805 assert_eq!(
806 collected,
807 RecordBatches::try_new(schema.clone(), vec![batch2.clone(), batch1.clone()]).unwrap()
808 );
809
810 let poll_err_stream = new_future_stream(Ok(vec![
811 Ok(batch1.clone()),
812 Err(error::ExternalSnafu
813 .into_error(BoxedError::new(MockError::new(StatusCode::Unknown)))),
814 ]));
815 let adapter = AsyncRecordBatchStreamAdapter::new(schema.clone(), poll_err_stream);
816 let err = RecordBatches::try_collect(Box::pin(adapter))
817 .await
818 .unwrap_err();
819 assert!(
820 matches!(err, Error::External { .. }),
821 "unexpected err {err}"
822 );
823
824 let failed_to_init_stream =
825 new_future_stream(Err(error::ExternalSnafu
826 .into_error(BoxedError::new(MockError::new(StatusCode::Internal)))));
827 let adapter = AsyncRecordBatchStreamAdapter::new(schema.clone(), failed_to_init_stream);
828 let err = RecordBatches::try_collect(Box::pin(adapter))
829 .await
830 .unwrap_err();
831 assert!(
832 matches!(err, Error::External { .. }),
833 "unexpected err {err}"
834 );
835 }
836
837 #[test]
838 fn test_convert_map_to_json_binary() {
839 let keys = StringArray::from(vec![Some("a"), Some("b"), Some("c"), Some("x")]);
840 let values = StringArray::from(vec![Some("1"), None, Some("3"), Some("42")]);
841 let key_field = Arc::new(Field::new("key", ArrowDataType::Utf8, false));
842 let value_field = Arc::new(Field::new("value", ArrowDataType::Utf8, true));
843 let struct_type = ArrowDataType::Struct(vec![key_field, value_field].into());
844
845 let entries_field = Arc::new(Field::new("entries", struct_type, false));
846
847 let struct_array = StructArray::from(vec![
848 (
849 Arc::new(Field::new("key", ArrowDataType::Utf8, false)),
850 Arc::new(keys) as ArrayRef,
851 ),
852 (
853 Arc::new(Field::new("value", ArrowDataType::Utf8, true)),
854 Arc::new(values) as ArrayRef,
855 ),
856 ]);
857
858 let offsets = OffsetBuffer::from_lengths([3, 0, 1]);
859 let nulls = datatypes::arrow::buffer::NullBuffer::from(vec![true, false, true]);
860
861 let map_array = MapArray::new(
862 entries_field,
863 offsets,
864 struct_array,
865 Some(nulls), false,
867 );
868
869 let result = convert_map_to_json_binary(&map_array, None).unwrap();
870 let binary_array = result
871 .as_any()
872 .downcast_ref::<datatypes::arrow::array::BinaryArray>()
873 .unwrap();
874
875 let expected_jsons = [
876 Some(r#"{"a":"1","b":null,"c":"3"}"#),
877 None,
878 Some(r#"{"x":"42"}"#),
879 ];
880
881 for (i, _) in expected_jsons.iter().enumerate() {
882 if let Some(expected) = &expected_jsons[i] {
883 assert!(!binary_array.is_null(i));
884 let actual_bytes = binary_array.value(i);
885 let actual_str = std::str::from_utf8(actual_bytes).unwrap();
886 assert_eq!(actual_str, *expected);
887 } else {
888 assert!(binary_array.is_null(i));
889 }
890 }
891
892 let result_json =
893 convert_map_to_json_binary(&map_array, Some(ColumnExtType::Json)).unwrap();
894 let binary_array_json = result_json
895 .as_any()
896 .downcast_ref::<datatypes::arrow::array::BinaryArray>()
897 .unwrap();
898
899 for (i, _) in expected_jsons.iter().enumerate() {
900 if expected_jsons[i].is_some() {
901 assert!(!binary_array_json.is_null(i));
902 let actual_bytes = binary_array_json.value(i);
903 assert_ne!(actual_bytes, expected_jsons[i].unwrap().as_bytes());
904 } else {
905 assert!(binary_array_json.is_null(i));
906 }
907 }
908 }
909
910 #[test]
911 fn test_recordbatch_metrics_deserializes_without_region_watermarks() {
912 let metrics: RecordBatchMetrics = serde_json::from_value(json!({
913 "elapsed_compute": 12,
914 "memory_usage": 34,
915 "plan_metrics": []
916 }))
917 .unwrap();
918
919 assert!(metrics.region_watermarks.is_empty());
920 assert_eq!(metrics.elapsed_compute, 12);
921 assert_eq!(metrics.memory_usage, 34);
922 }
923
924 #[test]
925 fn test_plan_metrics_deserializes_without_plan_name() {
926 let metrics: RecordBatchMetrics = serde_json::from_value(json!({
927 "elapsed_compute": 12,
928 "memory_usage": 34,
929 "plan_metrics": [{
930 "plan": "SeqScan: region=1",
931 "level": 0,
932 "metrics": []
933 }]
934 }))
935 .unwrap();
936
937 assert_eq!(metrics.plan_metrics[0].plan_name, "");
938 }
939
940 #[test]
941 fn test_recordbatch_metrics_region_watermarks_serde_roundtrip() {
942 let metrics = RecordBatchMetrics {
943 region_watermarks: vec![
944 RegionWatermarkEntry {
945 region_id: 1,
946 watermark: Some(100),
947 },
948 RegionWatermarkEntry {
949 region_id: 2,
950 watermark: None,
951 },
952 ],
953 ..Default::default()
954 };
955
956 let value = serde_json::to_value(&metrics).unwrap();
957 assert_eq!(
958 value.get("region_watermarks").unwrap(),
959 &json!([
960 { "region_id": 1, "watermark": 100 },
961 { "region_id": 2 }
962 ])
963 );
964
965 let decoded: RecordBatchMetrics = serde_json::from_value(value).unwrap();
966 assert_eq!(decoded.region_watermarks, metrics.region_watermarks);
967 }
968
969 #[test]
970 fn test_recordbatch_metrics_skips_empty_region_watermarks_on_serialize() {
971 let value = serde_json::to_value(RecordBatchMetrics::default()).unwrap();
972 assert!(value.get("region_watermarks").is_none());
973 }
974}