1use std::{collections::VecDeque, fmt::Debug, pin::Pin, sync::Arc, task::Poll};
19
20use crate::{FlightData, FlightDescriptor, SchemaAsIpc, error::Result};
21
22use arrow_array::{Array, ArrayRef, RecordBatch, RecordBatchOptions, UnionArray};
23use arrow_ipc::writer::{DictionaryTracker, IpcDataGenerator, IpcWriteContext, IpcWriteOptions};
24
25use arrow_schema::{ArrowError, DataType, Field, FieldRef, Fields, Schema, SchemaRef, UnionMode};
26use bytes::Bytes;
27use futures::{Stream, StreamExt, ready, stream::BoxStream};
28
29#[derive(Debug)]
149pub struct FlightDataEncoderBuilder {
150 max_flight_data_size: usize,
153 options: IpcWriteOptions,
155 app_metadata: Bytes,
157 schema: Option<SchemaRef>,
159 descriptor: Option<FlightDescriptor>,
161 dictionary_handling: DictionaryHandling,
164}
165
166pub const GRPC_TARGET_MAX_FLIGHT_SIZE_BYTES: usize = 2097152;
171
172impl Default for FlightDataEncoderBuilder {
173 fn default() -> Self {
174 Self {
175 max_flight_data_size: GRPC_TARGET_MAX_FLIGHT_SIZE_BYTES,
176 options: IpcWriteOptions::default(),
177 app_metadata: Bytes::new(),
178 schema: None,
179 descriptor: None,
180 dictionary_handling: DictionaryHandling::Hydrate,
181 }
182 }
183}
184
185impl FlightDataEncoderBuilder {
186 pub fn new() -> Self {
188 Self::default()
189 }
190
191 pub fn with_max_flight_data_size(mut self, max_flight_data_size: usize) -> Self {
202 self.max_flight_data_size = max_flight_data_size;
203 self
204 }
205
206 pub fn with_dictionary_handling(mut self, dictionary_handling: DictionaryHandling) -> Self {
208 self.dictionary_handling = dictionary_handling;
209 self
210 }
211
212 pub fn with_metadata(mut self, app_metadata: Bytes) -> Self {
216 self.app_metadata = app_metadata;
217 self
218 }
219
220 pub fn with_options(mut self, options: IpcWriteOptions) -> Self {
222 self.options = options;
223 self
224 }
225
226 pub fn with_schema(mut self, schema: SchemaRef) -> Self {
232 self.schema = Some(schema);
233 self
234 }
235
236 pub fn with_flight_descriptor(mut self, descriptor: Option<FlightDescriptor>) -> Self {
238 self.descriptor = descriptor;
239 self
240 }
241
242 pub fn build<S>(self, input: S) -> FlightDataEncoder
247 where
248 S: Stream<Item = Result<RecordBatch>> + Send + 'static,
249 {
250 let Self {
251 max_flight_data_size,
252 options,
253 app_metadata,
254 schema,
255 descriptor,
256 dictionary_handling,
257 } = self;
258
259 FlightDataEncoder::new(
260 input.boxed(),
261 schema,
262 max_flight_data_size,
263 options,
264 app_metadata,
265 descriptor,
266 dictionary_handling,
267 )
268 }
269}
270
271pub struct FlightDataEncoder {
275 inner: BoxStream<'static, Result<RecordBatch>>,
277 input_schema: Option<SchemaRef>,
279 schema: Option<SchemaRef>,
281 max_flight_data_size: usize,
284 encoder: FlightIpcEncoder,
286 app_metadata: Option<Bytes>,
288 queue: VecDeque<FlightData>,
290 done: bool,
292 descriptor: Option<FlightDescriptor>,
294 dictionary_handling: DictionaryHandling,
297}
298
299impl FlightDataEncoder {
300 fn new(
301 inner: BoxStream<'static, Result<RecordBatch>>,
302 schema: Option<SchemaRef>,
303 max_flight_data_size: usize,
304 options: IpcWriteOptions,
305 app_metadata: Bytes,
306 descriptor: Option<FlightDescriptor>,
307 dictionary_handling: DictionaryHandling,
308 ) -> Self {
309 let mut encoder = Self {
310 inner,
311 input_schema: schema.clone(),
312 schema: None,
313 max_flight_data_size,
314 encoder: FlightIpcEncoder::new(
315 options,
316 dictionary_handling != DictionaryHandling::Resend,
317 ),
318 app_metadata: Some(app_metadata),
319 queue: VecDeque::new(),
320 done: false,
321 descriptor,
322 dictionary_handling,
323 };
324
325 if let Some(schema) = schema {
327 encoder.encode_schema(&schema);
328 }
329
330 encoder
331 }
332
333 pub fn known_schema(&self) -> Option<SchemaRef> {
336 self.schema.clone()
337 }
338
339 #[inline]
341 fn queue_message(&mut self, mut data: FlightData) {
342 if let Some(descriptor) = self.descriptor.take() {
343 data.flight_descriptor = Some(descriptor);
344 }
345 self.queue.push_back(data);
346 }
347
348 fn encode_schema(&mut self, schema: &SchemaRef) -> SchemaRef {
351 let send_dictionaries = self.dictionary_handling == DictionaryHandling::Resend;
354 let schema = Arc::new(prepare_schema_for_flight(
355 schema,
356 &mut self.encoder.dictionary_tracker,
357 send_dictionaries,
358 ));
359 let mut schema_flight_data = self.encoder.encode_schema(&schema);
360
361 if let Some(app_metadata) = self.app_metadata.take() {
363 schema_flight_data.app_metadata = app_metadata;
364 }
365 self.queue_message(schema_flight_data);
366 self.schema = Some(schema.clone());
368 schema
369 }
370
371 fn encode_batch(&mut self, batch: RecordBatch) -> Result<()> {
373 match &self.input_schema {
374 Some(expected) if expected.as_ref() != batch.schema_ref().as_ref() => {
375 return Err(ArrowError::SchemaError(
376 "Record batch schema does not match input schema".to_string(),
377 )
378 .into());
379 }
380 None => self.input_schema = Some(batch.schema()),
381 _ => {}
382 }
383
384 let schema = match &self.schema {
385 Some(schema) => schema.clone(),
386 None => self.encode_schema(batch.schema_ref()),
388 };
389
390 let batch = match self.dictionary_handling {
391 DictionaryHandling::Resend => batch,
392 DictionaryHandling::Hydrate => hydrate_dictionaries(&batch, schema)?,
393 };
394
395 let batches = split_batch_for_grpc_response(batch, self.max_flight_data_size);
396 let last = batches.len().saturating_sub(1); for (i, batch) in batches.into_iter().enumerate() {
398 self.encoder
399 .ipc_write_context
400 .set_reserve_scratch(i != last);
401 let (flight_dictionaries, flight_batch) = self.encoder.encode_batch(&batch)?;
402 for dict in flight_dictionaries {
403 self.queue_message(dict);
404 }
405 self.queue_message(flight_batch);
406 }
407
408 Ok(())
409 }
410}
411
412impl Stream for FlightDataEncoder {
413 type Item = Result<FlightData>;
414
415 fn poll_next(
416 mut self: Pin<&mut Self>,
417 cx: &mut std::task::Context<'_>,
418 ) -> Poll<Option<Self::Item>> {
419 loop {
420 if self.done && self.queue.is_empty() {
421 return Poll::Ready(None);
422 }
423
424 if let Some(data) = self.queue.pop_front() {
426 return Poll::Ready(Some(Ok(data)));
427 }
428
429 let batch = ready!(self.inner.poll_next_unpin(cx));
431
432 match batch {
433 None => {
434 self.done = true;
436 assert!(self.queue.is_empty());
438 return Poll::Ready(None);
439 }
440 Some(Err(e)) => {
441 self.done = true;
443 self.queue.clear();
444 return Poll::Ready(Some(Err(e)));
445 }
446 Some(Ok(batch)) => {
447 if let Err(e) = self.encode_batch(batch) {
449 self.done = true;
450 self.queue.clear();
451 return Poll::Ready(Some(Err(e)));
452 }
453 }
454 }
455 }
456 }
457}
458
459#[derive(Debug, PartialEq)]
488pub enum DictionaryHandling {
489 Hydrate,
497 Resend,
507}
508
509fn prepare_field_for_flight(
510 field: &FieldRef,
511 dictionary_tracker: &mut DictionaryTracker,
512 send_dictionaries: bool,
513) -> Field {
514 match field.data_type() {
515 DataType::List(inner) => Field::new_list(
516 field.name(),
517 prepare_field_for_flight(inner, dictionary_tracker, send_dictionaries),
518 field.is_nullable(),
519 )
520 .with_metadata(field.metadata().clone()),
521 DataType::LargeList(inner) => Field::new_large_list(
522 field.name(),
523 prepare_field_for_flight(inner, dictionary_tracker, send_dictionaries),
524 field.is_nullable(),
525 )
526 .with_metadata(field.metadata().clone()),
527 DataType::Struct(fields) => {
528 let new_fields: Vec<Field> = fields
529 .iter()
530 .map(|f| prepare_field_for_flight(f, dictionary_tracker, send_dictionaries))
531 .collect();
532 Field::new_struct(field.name(), new_fields, field.is_nullable())
533 .with_metadata(field.metadata().clone())
534 }
535 DataType::Union(fields, mode) => {
536 let (type_ids, new_fields): (Vec<i8>, Vec<Field>) = fields
537 .iter()
538 .map(|(type_id, f)| {
539 (
540 type_id,
541 prepare_field_for_flight(f, dictionary_tracker, send_dictionaries),
542 )
543 })
544 .unzip();
545
546 Field::new_union(field.name(), type_ids, new_fields, *mode)
547 }
548 DataType::Dictionary(_, value_type) => {
549 if !send_dictionaries {
550 let value_field = Field::new(
552 field.name(),
553 value_type.as_ref().clone(),
554 field.is_nullable(),
555 );
556 prepare_field_for_flight(
557 &Arc::new(value_field),
558 dictionary_tracker,
559 send_dictionaries,
560 )
561 .with_metadata(field.metadata().clone())
562 } else {
563 let value_field = Field::new("values", value_type.as_ref().clone(), true);
567 prepare_field_for_flight(
568 &Arc::new(value_field),
569 dictionary_tracker,
570 send_dictionaries,
571 );
572 dictionary_tracker.next_dict_id();
573 #[expect(deprecated)]
574 Field::new_dict(
575 field.name(),
576 field.data_type().clone(),
577 field.is_nullable(),
578 0,
579 field.dict_is_ordered().unwrap_or_default(),
580 )
581 .with_metadata(field.metadata().clone())
582 }
583 }
584 DataType::ListView(inner) | DataType::LargeListView(inner) => {
585 let prepared = prepare_field_for_flight(inner, dictionary_tracker, send_dictionaries);
586 Field::new(
587 field.name(),
588 match field.data_type() {
589 DataType::ListView(_) => DataType::ListView(Arc::new(prepared)),
590 _ => DataType::LargeListView(Arc::new(prepared)),
591 },
592 field.is_nullable(),
593 )
594 .with_metadata(field.metadata().clone())
595 }
596 DataType::FixedSizeList(inner, size) => Field::new(
597 field.name(),
598 DataType::FixedSizeList(
599 Arc::new(prepare_field_for_flight(
600 inner,
601 dictionary_tracker,
602 send_dictionaries,
603 )),
604 *size,
605 ),
606 field.is_nullable(),
607 )
608 .with_metadata(field.metadata().clone()),
609 DataType::RunEndEncoded(run_ends, values) => Field::new(
610 field.name(),
611 DataType::RunEndEncoded(
612 run_ends.clone(),
613 Arc::new(prepare_field_for_flight(
614 values,
615 dictionary_tracker,
616 send_dictionaries,
617 )),
618 ),
619 field.is_nullable(),
620 )
621 .with_metadata(field.metadata().clone()),
622 DataType::Map(inner, sorted) => Field::new(
623 field.name(),
624 DataType::Map(
625 prepare_field_for_flight(inner, dictionary_tracker, send_dictionaries).into(),
626 *sorted,
627 ),
628 field.is_nullable(),
629 )
630 .with_metadata(field.metadata().clone()),
631 DataType::Null
632 | DataType::Boolean
633 | DataType::Int8
634 | DataType::Int16
635 | DataType::Int32
636 | DataType::Int64
637 | DataType::UInt8
638 | DataType::UInt16
639 | DataType::UInt32
640 | DataType::UInt64
641 | DataType::Float16
642 | DataType::Float32
643 | DataType::Float64
644 | DataType::Timestamp(_, _)
645 | DataType::Date32
646 | DataType::Date64
647 | DataType::Time32(_)
648 | DataType::Time64(_)
649 | DataType::Duration(_)
650 | DataType::Interval(_)
651 | DataType::Binary
652 | DataType::FixedSizeBinary(_)
653 | DataType::LargeBinary
654 | DataType::BinaryView
655 | DataType::Utf8
656 | DataType::LargeUtf8
657 | DataType::Utf8View
658 | DataType::Decimal32(_, _)
659 | DataType::Decimal64(_, _)
660 | DataType::Decimal128(_, _)
661 | DataType::Decimal256(_, _) => field.as_ref().clone(),
662 }
663}
664
665fn prepare_schema_for_flight(
671 schema: &Schema,
672 dictionary_tracker: &mut DictionaryTracker,
673 send_dictionaries: bool,
674) -> Schema {
675 let fields: Fields = schema
676 .fields()
677 .iter()
678 .map(|field| prepare_field_for_flight(field, dictionary_tracker, send_dictionaries))
679 .collect();
680
681 Schema::new(fields).with_metadata(schema.metadata().clone())
682}
683
684fn split_batch_for_grpc_response(
691 batch: RecordBatch,
692 max_flight_data_size: usize,
693) -> Vec<RecordBatch> {
694 let size = batch
695 .columns()
696 .iter()
697 .map(|col| col.get_buffer_memory_size())
698 .sum::<usize>();
699
700 let n_batches =
701 (size / max_flight_data_size + usize::from(size % max_flight_data_size != 0)).max(1);
702 let num_rows = batch.num_rows();
703 let rows_per_batch = (num_rows / n_batches).max(1);
704 let mut offset = 0;
705 let mut batches = Vec::with_capacity(n_batches);
706
707 while offset < num_rows {
708 let length = rows_per_batch.min(num_rows - offset);
709 batches.push(batch.slice(offset, length));
710 offset += length;
711 }
712
713 batches
714}
715
716struct FlightIpcEncoder {
723 options: IpcWriteOptions,
724 data_gen: IpcDataGenerator,
725 dictionary_tracker: DictionaryTracker,
726 ipc_write_context: IpcWriteContext,
727}
728
729impl FlightIpcEncoder {
730 fn new(options: IpcWriteOptions, error_on_replacement: bool) -> Self {
731 Self {
732 options,
733 data_gen: IpcDataGenerator::default(),
734 dictionary_tracker: DictionaryTracker::new(error_on_replacement),
735 ipc_write_context: IpcWriteContext::default(),
736 }
737 }
738
739 fn encode_schema(&self, schema: &Schema) -> FlightData {
741 SchemaAsIpc::new(schema, &self.options).into()
742 }
743
744 fn encode_batch(
747 &mut self,
748 batch: &RecordBatch,
749 ) -> Result<(impl Iterator<Item = FlightData> + use<>, FlightData)> {
750 let (encoded_dictionaries, encoded_batch) = self.data_gen.encode(
751 batch,
752 &mut self.dictionary_tracker,
753 &self.options,
754 &mut self.ipc_write_context,
755 )?;
756
757 let flight_dictionaries = encoded_dictionaries.into_iter().map(|e| e.into());
758 let flight_batch = encoded_batch.into();
759
760 Ok((flight_dictionaries, flight_batch))
761 }
762}
763
764fn hydrate_dictionaries(batch: &RecordBatch, schema: SchemaRef) -> Result<RecordBatch> {
767 let columns = schema
768 .fields()
769 .iter()
770 .zip(batch.columns())
771 .map(|(field, c)| hydrate_dictionary(c, field.data_type()))
772 .collect::<Result<Vec<_>>>()?;
773
774 let options = RecordBatchOptions::new().with_row_count(Some(batch.num_rows()));
775
776 Ok(RecordBatch::try_new_with_options(
777 schema, columns, &options,
778 )?)
779}
780
781fn hydrate_dictionary(array: &ArrayRef, data_type: &DataType) -> Result<ArrayRef> {
783 let arr = match (array.data_type(), data_type) {
784 (DataType::Union(_, UnionMode::Sparse), DataType::Union(fields, UnionMode::Sparse)) => {
785 let union_arr = array.as_any().downcast_ref::<UnionArray>().unwrap();
786
787 Arc::new(UnionArray::try_new(
788 fields.clone(),
789 union_arr.type_ids().clone(),
790 None,
791 fields
792 .iter()
793 .map(|(type_id, field)| {
794 Ok(arrow_cast::cast(
795 union_arr.child(type_id),
796 field.data_type(),
797 )?)
798 })
799 .collect::<Result<Vec<_>>>()?,
800 )?)
801 }
802 (_, data_type) => arrow_cast::cast(array, data_type)?,
803 };
804 Ok(arr)
805}
806
807#[cfg(test)]
808mod tests {
809 use crate::decode::{DecodedPayload, FlightDataDecoder};
810 use arrow_array::builder::{
811 FixedSizeListBuilder, GenericByteDictionaryBuilder, GenericListViewBuilder, Int32Builder,
812 LargeListBuilder, ListBuilder, StringDictionaryBuilder, StructBuilder,
813 };
814 use arrow_array::*;
815 use arrow_array::{cast::downcast_array, types::*};
816 use arrow_buffer::ScalarBuffer;
817 use arrow_cast::pretty::pretty_format_batches;
818 use arrow_ipc::{CompressionType, MetadataVersion};
819 use arrow_schema::{UnionFields, UnionMode};
820 use builder::MapBuilder;
821 use std::collections::HashMap;
822
823 use super::*;
824
825 #[test]
826 fn test_encode_flight_data() {
829 let options = IpcWriteOptions::try_new(8, false, MetadataVersion::V5).unwrap();
831 let c1 = UInt32Array::from(vec![1, 2, 3, 4, 5, 6]);
832
833 let batch = RecordBatch::try_from_iter(vec![("a", Arc::new(c1) as ArrayRef)])
834 .expect("cannot create record batch");
835 let schema = batch.schema_ref();
836
837 let (_, baseline_flight_batch) = make_flight_data(&batch, &options);
838
839 let big_batch = batch.slice(0, batch.num_rows() - 1);
840 let optimized_big_batch =
841 hydrate_dictionaries(&big_batch, Arc::clone(schema)).expect("failed to optimize");
842 let (_, optimized_big_flight_batch) = make_flight_data(&optimized_big_batch, &options);
843
844 assert_eq!(
845 baseline_flight_batch.data_body.len(),
846 optimized_big_flight_batch.data_body.len()
847 );
848
849 let small_batch = batch.slice(0, 1);
850 let optimized_small_batch =
851 hydrate_dictionaries(&small_batch, Arc::clone(schema)).expect("failed to optimize");
852 let (_, optimized_small_flight_batch) = make_flight_data(&optimized_small_batch, &options);
853
854 assert!(
855 baseline_flight_batch.data_body.len() > optimized_small_flight_batch.data_body.len()
856 );
857 }
858
859 #[tokio::test]
860 async fn test_dictionary_hydration() {
861 let arr1: DictionaryArray<UInt16Type> = vec!["a", "a", "b"].into_iter().collect();
862 let arr2: DictionaryArray<UInt16Type> = vec!["c", "c", "d"].into_iter().collect();
863
864 let schema = Arc::new(Schema::new(vec![Field::new_dictionary(
865 "dict",
866 DataType::UInt16,
867 DataType::Utf8,
868 false,
869 )]));
870 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
871 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
872
873 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
874
875 let encoder = FlightDataEncoderBuilder::default().build(stream);
876 let mut decoder = FlightDataDecoder::new(encoder);
877 let expected_schema = Schema::new(vec![Field::new("dict", DataType::Utf8, false)]);
878 let expected_schema = Arc::new(expected_schema);
879 let mut expected_arrays = vec![
880 StringArray::from(vec!["a", "a", "b"]),
881 StringArray::from(vec!["c", "c", "d"]),
882 ]
883 .into_iter();
884 while let Some(decoded) = decoder.next().await {
885 let decoded = decoded.unwrap();
886 match decoded.payload {
887 DecodedPayload::None => {}
888 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
889 DecodedPayload::RecordBatch(b) => {
890 assert_eq!(b.schema(), expected_schema);
891 let expected_array = expected_arrays.next().unwrap();
892 let actual_array = b.column_by_name("dict").unwrap();
893 let actual_array = downcast_array::<StringArray>(actual_array);
894
895 assert_eq!(actual_array, expected_array);
896 }
897 }
898 }
899 }
900
901 #[tokio::test]
902 async fn test_dictionary_resend() {
903 let arr1: DictionaryArray<UInt16Type> = vec!["a", "a", "b"].into_iter().collect();
904 let arr2: DictionaryArray<UInt16Type> = vec!["c", "c", "d"].into_iter().collect();
905
906 let schema = Arc::new(Schema::new(vec![Field::new_dictionary(
907 "dict",
908 DataType::UInt16,
909 DataType::Utf8,
910 false,
911 )]));
912 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
913 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
914
915 verify_flight_round_trip(vec![batch1, batch2]).await;
916 }
917
918 #[tokio::test]
919 async fn test_compression_round_trip() {
920 let ints = Int32Array::from_iter_values((0..1024).map(|i| i % 8));
924 let strings = StringArray::from_iter_values((0..1024).map(|i| format!("value-{}", i % 8)));
925 let batch = RecordBatch::try_from_iter(vec![
926 ("ints", Arc::new(ints) as ArrayRef),
927 ("strings", Arc::new(strings) as ArrayRef),
928 ])
929 .unwrap();
930
931 for compression in [CompressionType::LZ4_FRAME, CompressionType::ZSTD] {
932 let options = IpcWriteOptions::default()
933 .try_with_compression(Some(compression))
934 .unwrap();
935 verify_flight_round_trip_with_options(vec![batch.clone()], options).await;
936 }
937 }
938
939 #[tokio::test]
940 async fn test_dictionary_hydration_known_schema() {
941 let arr1: DictionaryArray<UInt16Type> = vec!["a", "a", "b"].into_iter().collect();
942 let arr2: DictionaryArray<UInt16Type> = vec!["c", "c", "d"].into_iter().collect();
943
944 let schema = Arc::new(Schema::new(vec![Field::new_dictionary(
945 "dict",
946 DataType::UInt16,
947 DataType::Utf8,
948 false,
949 )]));
950 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
951 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
952
953 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
954
955 let encoder = FlightDataEncoderBuilder::default()
956 .with_schema(schema)
957 .build(stream);
958 let expected_schema =
959 Arc::new(Schema::new(vec![Field::new("dict", DataType::Utf8, false)]));
960 assert_eq!(Some(expected_schema), encoder.known_schema())
961 }
962
963 #[tokio::test]
964 async fn test_dictionary_resend_known_schema() {
965 let arr1: DictionaryArray<UInt16Type> = vec!["a", "a", "b"].into_iter().collect();
966 let arr2: DictionaryArray<UInt16Type> = vec!["c", "c", "d"].into_iter().collect();
967
968 let schema = Arc::new(Schema::new(vec![Field::new_dictionary(
969 "dict",
970 DataType::UInt16,
971 DataType::Utf8,
972 false,
973 )]));
974 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
975 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
976
977 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
978
979 let encoder = FlightDataEncoderBuilder::default()
980 .with_dictionary_handling(DictionaryHandling::Resend)
981 .with_schema(schema.clone())
982 .build(stream);
983 assert_eq!(Some(schema), encoder.known_schema())
984 }
985
986 #[tokio::test]
987 async fn test_multiple_dictionaries_resend() {
988 let schema = Arc::new(Schema::new(vec![
990 Field::new_dictionary("dict_1", DataType::UInt16, DataType::Utf8, false),
991 Field::new_dictionary("dict_2", DataType::UInt16, DataType::Utf8, false),
992 ]));
993
994 let arr_one_1: Arc<DictionaryArray<UInt16Type>> =
995 Arc::new(vec!["a", "a", "b"].into_iter().collect());
996 let arr_one_2: Arc<DictionaryArray<UInt16Type>> =
997 Arc::new(vec!["c", "c", "d"].into_iter().collect());
998 let arr_two_1: Arc<DictionaryArray<UInt16Type>> =
999 Arc::new(vec!["b", "a", "c"].into_iter().collect());
1000 let arr_two_2: Arc<DictionaryArray<UInt16Type>> =
1001 Arc::new(vec!["k", "d", "e"].into_iter().collect());
1002 let batch1 =
1003 RecordBatch::try_new(schema.clone(), vec![arr_one_1.clone(), arr_one_2.clone()])
1004 .unwrap();
1005 let batch2 =
1006 RecordBatch::try_new(schema.clone(), vec![arr_two_1.clone(), arr_two_2.clone()])
1007 .unwrap();
1008
1009 verify_flight_round_trip(vec![batch1, batch2]).await;
1010 }
1011
1012 #[tokio::test]
1013 async fn test_dictionary_list_hydration() {
1014 let mut builder = ListBuilder::new(StringDictionaryBuilder::<UInt16Type>::new());
1015
1016 builder.append_value(vec![Some("a"), None, Some("b")]);
1017
1018 let arr1 = builder.finish();
1019
1020 builder.append_value(vec![Some("c"), None, Some("d")]);
1021
1022 let arr2 = builder.finish();
1023
1024 let schema = Arc::new(Schema::new(vec![Field::new_list(
1025 "dict_list",
1026 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1027 true,
1028 )]));
1029
1030 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1031 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1032
1033 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
1034
1035 let encoder = FlightDataEncoderBuilder::default().build(stream);
1036
1037 let mut decoder = FlightDataDecoder::new(encoder);
1038 let expected_schema = Schema::new(vec![Field::new_list(
1039 "dict_list",
1040 Field::new_list_field(DataType::Utf8, true),
1041 true,
1042 )]);
1043
1044 let expected_schema = Arc::new(expected_schema);
1045
1046 let mut expected_arrays = vec![
1047 StringArray::from_iter(vec![Some("a"), None, Some("b")]),
1048 StringArray::from_iter(vec![Some("c"), None, Some("d")]),
1049 ]
1050 .into_iter();
1051
1052 while let Some(decoded) = decoder.next().await {
1053 let decoded = decoded.unwrap();
1054 match decoded.payload {
1055 DecodedPayload::None => {}
1056 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
1057 DecodedPayload::RecordBatch(b) => {
1058 assert_eq!(b.schema(), expected_schema);
1059 let expected_array = expected_arrays.next().unwrap();
1060 let list_array =
1061 downcast_array::<ListArray>(b.column_by_name("dict_list").unwrap());
1062 let elem_array = downcast_array::<StringArray>(list_array.value(0).as_ref());
1063
1064 assert_eq!(elem_array, expected_array);
1065 }
1066 }
1067 }
1068 }
1069
1070 #[tokio::test]
1071 async fn test_dictionary_list_resend() {
1072 let mut builder = ListBuilder::new(StringDictionaryBuilder::<UInt16Type>::new());
1073
1074 builder.append_value(vec![Some("a"), None, Some("b")]);
1075
1076 let arr1 = builder.finish();
1077
1078 builder.append_value(vec![Some("c"), None, Some("d")]);
1079
1080 let arr2 = builder.finish();
1081
1082 let schema = Arc::new(Schema::new(vec![Field::new_list(
1083 "dict_list",
1084 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1085 true,
1086 )]));
1087
1088 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1089 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1090
1091 verify_flight_round_trip(vec![batch1, batch2]).await;
1092 }
1093
1094 #[tokio::test]
1095 async fn test_dictionary_struct_hydration() {
1096 let struct_fields = vec![Field::new_list(
1097 "dict_list",
1098 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1099 true,
1100 )];
1101
1102 let mut struct_builder = StructBuilder::new(
1103 struct_fields.clone(),
1104 vec![Box::new(builder::ListBuilder::new(
1105 StringDictionaryBuilder::<UInt16Type>::new(),
1106 ))],
1107 );
1108
1109 struct_builder
1110 .field_builder::<ListBuilder<GenericByteDictionaryBuilder<UInt16Type,GenericStringType<i32>>>>(0)
1111 .unwrap()
1112 .append_value(vec![Some("a"), None, Some("b")]);
1113
1114 struct_builder.append(true);
1115
1116 let arr1 = struct_builder.finish();
1117
1118 struct_builder
1119 .field_builder::<ListBuilder<GenericByteDictionaryBuilder<UInt16Type,GenericStringType<i32>>>>(0)
1120 .unwrap()
1121 .append_value(vec![Some("c"), None, Some("d")]);
1122 struct_builder.append(true);
1123
1124 let arr2 = struct_builder.finish();
1125
1126 let schema = Arc::new(Schema::new(vec![Field::new_struct(
1127 "struct",
1128 struct_fields,
1129 true,
1130 )]));
1131
1132 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1133 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1134
1135 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
1136
1137 let encoder = FlightDataEncoderBuilder::default().build(stream);
1138
1139 let mut decoder = FlightDataDecoder::new(encoder);
1140 let expected_schema = Schema::new(vec![Field::new_struct(
1141 "struct",
1142 vec![Field::new_list(
1143 "dict_list",
1144 Field::new_list_field(DataType::Utf8, true),
1145 true,
1146 )],
1147 true,
1148 )]);
1149
1150 let expected_schema = Arc::new(expected_schema);
1151
1152 let mut expected_arrays = vec![
1153 StringArray::from_iter(vec![Some("a"), None, Some("b")]),
1154 StringArray::from_iter(vec![Some("c"), None, Some("d")]),
1155 ]
1156 .into_iter();
1157
1158 while let Some(decoded) = decoder.next().await {
1159 let decoded = decoded.unwrap();
1160 match decoded.payload {
1161 DecodedPayload::None => {}
1162 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
1163 DecodedPayload::RecordBatch(b) => {
1164 assert_eq!(b.schema(), expected_schema);
1165 let expected_array = expected_arrays.next().unwrap();
1166 let struct_array =
1167 downcast_array::<StructArray>(b.column_by_name("struct").unwrap());
1168 let list_array = downcast_array::<ListArray>(struct_array.column(0));
1169
1170 let elem_array = downcast_array::<StringArray>(list_array.value(0).as_ref());
1171
1172 assert_eq!(elem_array, expected_array);
1173 }
1174 }
1175 }
1176 }
1177
1178 #[tokio::test]
1179 async fn test_dictionary_struct_resend() {
1180 let struct_fields = vec![Field::new_list(
1181 "dict_list",
1182 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1183 true,
1184 )];
1185
1186 let mut struct_builder = StructBuilder::new(
1187 struct_fields.clone(),
1188 vec![Box::new(builder::ListBuilder::new(
1189 StringDictionaryBuilder::<UInt16Type>::new(),
1190 ))],
1191 );
1192
1193 struct_builder.field_builder::<ListBuilder<GenericByteDictionaryBuilder<UInt16Type,GenericStringType<i32>>>>(0)
1194 .unwrap()
1195 .append_value(vec![Some("a"), None, Some("b")]);
1196 struct_builder.append(true);
1197
1198 let arr1 = struct_builder.finish();
1199
1200 struct_builder.field_builder::<ListBuilder<GenericByteDictionaryBuilder<UInt16Type,GenericStringType<i32>>>>(0)
1201 .unwrap()
1202 .append_value(vec![Some("c"), None, Some("d")]);
1203 struct_builder.append(true);
1204
1205 let arr2 = struct_builder.finish();
1206
1207 let schema = Arc::new(Schema::new(vec![Field::new_struct(
1208 "struct",
1209 struct_fields,
1210 true,
1211 )]));
1212
1213 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1214 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1215
1216 verify_flight_round_trip(vec![batch1, batch2]).await;
1217 }
1218
1219 #[tokio::test]
1220 async fn test_dictionary_union_hydration() {
1221 let struct_fields = vec![Field::new_list(
1222 "dict_list",
1223 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1224 true,
1225 )];
1226
1227 let union_fields = [
1228 (
1229 0,
1230 Arc::new(Field::new_list(
1231 "dict_list",
1232 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1233 true,
1234 )),
1235 ),
1236 (
1237 1,
1238 Arc::new(Field::new_struct("struct", struct_fields.clone(), true)),
1239 ),
1240 (2, Arc::new(Field::new("string", DataType::Utf8, true))),
1241 ]
1242 .into_iter()
1243 .collect::<UnionFields>();
1244
1245 let struct_fields = vec![Field::new_list(
1246 "dict_list",
1247 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1248 true,
1249 )];
1250
1251 let mut builder = builder::ListBuilder::new(StringDictionaryBuilder::<UInt16Type>::new());
1252
1253 builder.append_value(vec![Some("a"), None, Some("b")]);
1254
1255 let arr1 = builder.finish();
1256
1257 let type_id_buffer = std::iter::once(0).collect::<ScalarBuffer<i8>>();
1258 let arr1 = UnionArray::try_new(
1259 union_fields.clone(),
1260 type_id_buffer,
1261 None,
1262 vec![
1263 Arc::new(arr1) as Arc<dyn Array>,
1264 new_null_array(union_fields.iter().nth(1).unwrap().1.data_type(), 1),
1265 new_null_array(union_fields.iter().nth(2).unwrap().1.data_type(), 1),
1266 ],
1267 )
1268 .unwrap();
1269
1270 builder.append_value(vec![Some("c"), None, Some("d")]);
1271
1272 let arr2 = Arc::new(builder.finish());
1273 let arr2 = StructArray::new(struct_fields.clone().into(), vec![arr2], None);
1274
1275 let type_id_buffer = std::iter::once(1).collect::<ScalarBuffer<i8>>();
1276 let arr2 = UnionArray::try_new(
1277 union_fields.clone(),
1278 type_id_buffer,
1279 None,
1280 vec![
1281 new_null_array(union_fields.iter().next().unwrap().1.data_type(), 1),
1282 Arc::new(arr2),
1283 new_null_array(union_fields.iter().nth(2).unwrap().1.data_type(), 1),
1284 ],
1285 )
1286 .unwrap();
1287
1288 let type_id_buffer = std::iter::once(2).collect::<ScalarBuffer<i8>>();
1289 let arr3 = UnionArray::try_new(
1290 union_fields.clone(),
1291 type_id_buffer,
1292 None,
1293 vec![
1294 new_null_array(union_fields.iter().next().unwrap().1.data_type(), 1),
1295 new_null_array(union_fields.iter().nth(1).unwrap().1.data_type(), 1),
1296 Arc::new(StringArray::from(vec!["e"])),
1297 ],
1298 )
1299 .unwrap();
1300
1301 let (type_ids, union_fields): (Vec<_>, Vec<_>) = union_fields
1302 .iter()
1303 .map(|(type_id, field_ref)| (type_id, (*Arc::clone(field_ref)).clone()))
1304 .unzip();
1305 let schema = Arc::new(Schema::new(vec![Field::new_union(
1306 "union",
1307 type_ids.clone(),
1308 union_fields.clone(),
1309 UnionMode::Sparse,
1310 )]));
1311
1312 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1313 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1314 let batch3 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr3)]).unwrap();
1315
1316 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2), Ok(batch3)]);
1317
1318 let encoder = FlightDataEncoderBuilder::default().build(stream);
1319
1320 let mut decoder = FlightDataDecoder::new(encoder);
1321
1322 let hydrated_struct_fields = vec![Field::new_list(
1323 "dict_list",
1324 Field::new_list_field(DataType::Utf8, true),
1325 true,
1326 )];
1327
1328 let hydrated_union_fields = vec![
1329 Field::new_list(
1330 "dict_list",
1331 Field::new_list_field(DataType::Utf8, true),
1332 true,
1333 ),
1334 Field::new_struct("struct", hydrated_struct_fields.clone(), true),
1335 Field::new("string", DataType::Utf8, true),
1336 ];
1337
1338 let expected_schema = Schema::new(vec![Field::new_union(
1339 "union",
1340 type_ids.clone(),
1341 hydrated_union_fields,
1342 UnionMode::Sparse,
1343 )]);
1344
1345 let expected_schema = Arc::new(expected_schema);
1346
1347 let mut expected_arrays = vec![
1348 StringArray::from_iter(vec![Some("a"), None, Some("b")]),
1349 StringArray::from_iter(vec![Some("c"), None, Some("d")]),
1350 StringArray::from(vec!["e"]),
1351 ]
1352 .into_iter();
1353
1354 let mut batch = 0;
1355 while let Some(decoded) = decoder.next().await {
1356 let decoded = decoded.unwrap();
1357 match decoded.payload {
1358 DecodedPayload::None => {}
1359 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
1360 DecodedPayload::RecordBatch(b) => {
1361 assert_eq!(b.schema(), expected_schema);
1362 let expected_array = expected_arrays.next().unwrap();
1363 let union_arr =
1364 downcast_array::<UnionArray>(b.column_by_name("union").unwrap());
1365
1366 let elem_array = match batch {
1367 0 => {
1368 let list_array = downcast_array::<ListArray>(union_arr.child(0));
1369 downcast_array::<StringArray>(list_array.value(0).as_ref())
1370 }
1371 1 => {
1372 let struct_array = downcast_array::<StructArray>(union_arr.child(1));
1373 let list_array = downcast_array::<ListArray>(struct_array.column(0));
1374
1375 downcast_array::<StringArray>(list_array.value(0).as_ref())
1376 }
1377 _ => downcast_array::<StringArray>(union_arr.child(2)),
1378 };
1379
1380 batch += 1;
1381
1382 assert_eq!(elem_array, expected_array);
1383 }
1384 }
1385 }
1386 }
1387
1388 #[tokio::test]
1389 async fn test_dictionary_union_resend() {
1390 let struct_fields = vec![Field::new_list(
1391 "dict_list",
1392 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1393 true,
1394 )];
1395
1396 let union_fields = [
1397 (
1398 0,
1399 Arc::new(Field::new_list(
1400 "dict_list",
1401 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1402 true,
1403 )),
1404 ),
1405 (
1406 1,
1407 Arc::new(Field::new_struct("struct", struct_fields.clone(), true)),
1408 ),
1409 (2, Arc::new(Field::new("string", DataType::Utf8, true))),
1410 ]
1411 .into_iter()
1412 .collect::<UnionFields>();
1413
1414 let mut field_types = union_fields.iter().map(|(_, field)| field.data_type());
1415 let dict_list_ty = field_types.next().unwrap();
1416 let struct_ty = field_types.next().unwrap();
1417 let string_ty = field_types.next().unwrap();
1418
1419 let struct_fields = vec![Field::new_list(
1420 "dict_list",
1421 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1422 true,
1423 )];
1424
1425 let mut builder = builder::ListBuilder::new(StringDictionaryBuilder::<UInt16Type>::new());
1426
1427 builder.append_value(vec![Some("a"), None, Some("b")]);
1428
1429 let arr1 = builder.finish();
1430
1431 let type_id_buffer = std::iter::once(0).collect::<ScalarBuffer<i8>>();
1432 let arr1 = UnionArray::try_new(
1433 union_fields.clone(),
1434 type_id_buffer,
1435 None,
1436 vec![
1437 Arc::new(arr1),
1438 new_null_array(struct_ty, 1),
1439 new_null_array(string_ty, 1),
1440 ],
1441 )
1442 .unwrap();
1443
1444 builder.append_value(vec![Some("c"), None, Some("d")]);
1445
1446 let arr2 = Arc::new(builder.finish());
1447 let arr2 = StructArray::new(struct_fields.clone().into(), vec![arr2], None);
1448
1449 let type_id_buffer = std::iter::once(1).collect::<ScalarBuffer<i8>>();
1450 let arr2 = UnionArray::try_new(
1451 union_fields.clone(),
1452 type_id_buffer,
1453 None,
1454 vec![
1455 new_null_array(dict_list_ty, 1),
1456 Arc::new(arr2),
1457 new_null_array(string_ty, 1),
1458 ],
1459 )
1460 .unwrap();
1461
1462 let type_id_buffer = std::iter::once(2).collect::<ScalarBuffer<i8>>();
1463 let arr3 = UnionArray::try_new(
1464 union_fields.clone(),
1465 type_id_buffer,
1466 None,
1467 vec![
1468 new_null_array(dict_list_ty, 1),
1469 new_null_array(struct_ty, 1),
1470 Arc::new(StringArray::from(vec!["e"])),
1471 ],
1472 )
1473 .unwrap();
1474
1475 let (type_ids, union_fields): (Vec<_>, Vec<_>) = union_fields
1476 .iter()
1477 .map(|(type_id, field_ref)| (type_id, (*Arc::clone(field_ref)).clone()))
1478 .unzip();
1479 let schema = Arc::new(Schema::new(vec![Field::new_union(
1480 "union",
1481 type_ids.clone(),
1482 union_fields.clone(),
1483 UnionMode::Sparse,
1484 )]));
1485
1486 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1487 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1488 let batch3 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr3)]).unwrap();
1489
1490 verify_flight_round_trip(vec![batch1, batch2, batch3]).await;
1491 }
1492
1493 #[tokio::test]
1494 async fn test_dictionary_map_hydration() {
1495 let mut builder = MapBuilder::new(
1496 None,
1497 StringDictionaryBuilder::<UInt16Type>::new(),
1498 StringDictionaryBuilder::<UInt16Type>::new(),
1499 );
1500
1501 builder.keys().append_value("k1");
1503 builder.values().append_value("a");
1504 builder.keys().append_value("k2");
1505 builder.values().append_null();
1506 builder.keys().append_value("k3");
1507 builder.values().append_value("b");
1508 builder.append(true).unwrap();
1509
1510 let arr1 = builder.finish();
1511
1512 builder.keys().append_value("k1");
1514 builder.values().append_value("c");
1515 builder.keys().append_value("k2");
1516 builder.values().append_null();
1517 builder.keys().append_value("k3");
1518 builder.values().append_value("d");
1519 builder.append(true).unwrap();
1520
1521 let arr2 = builder.finish();
1522
1523 let schema = Arc::new(Schema::new(vec![Field::new_map(
1524 "dict_map",
1525 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
1526 Field::new_dictionary(
1527 Field::MAP_KEY_FIELD_DEFAULT_NAME,
1528 DataType::UInt16,
1529 DataType::Utf8,
1530 false,
1531 ),
1532 Field::new_dictionary(
1533 Field::MAP_VALUE_FIELD_DEFAULT_NAME,
1534 DataType::UInt16,
1535 DataType::Utf8,
1536 true,
1537 ),
1538 false,
1539 false,
1540 )]));
1541
1542 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1543 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1544
1545 let stream = futures::stream::iter(vec![Ok(batch1), Ok(batch2)]);
1546
1547 let encoder = FlightDataEncoderBuilder::default().build(stream);
1548
1549 let mut decoder = FlightDataDecoder::new(encoder);
1550 let expected_schema = Schema::new(vec![Field::new_map(
1551 "dict_map",
1552 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
1553 Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false),
1554 Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Utf8, true),
1555 false,
1556 false,
1557 )]);
1558
1559 let expected_schema = Arc::new(expected_schema);
1560
1561 let arr1 = MapArray::from_vec_of_maps::<StringArray, StringArray, _, _>(
1563 vec![Some(vec![
1564 ("k1", Some("a")),
1565 ("k2", None),
1566 ("k3", Some("b")),
1567 ])],
1568 false,
1569 );
1570
1571 let arr2 = MapArray::from_vec_of_maps::<StringArray, StringArray, _, _>(
1572 vec![Some(vec![
1573 ("k1", Some("c")),
1574 ("k2", None),
1575 ("k3", Some("d")),
1576 ])],
1577 false,
1578 );
1579
1580 let mut expected_arrays = vec![arr1, arr2].into_iter();
1581
1582 while let Some(decoded) = decoder.next().await {
1583 let decoded = decoded.unwrap();
1584 match decoded.payload {
1585 DecodedPayload::None => {}
1586 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
1587 DecodedPayload::RecordBatch(b) => {
1588 assert_eq!(b.schema(), expected_schema);
1589 let expected_array = expected_arrays.next().unwrap();
1590 let map_array =
1591 downcast_array::<MapArray>(b.column_by_name("dict_map").unwrap());
1592
1593 assert_eq!(map_array, expected_array);
1594 }
1595 }
1596 }
1597 }
1598
1599 #[tokio::test]
1600 async fn test_dictionary_map_resend() {
1601 let mut builder = MapBuilder::new(
1602 None,
1603 StringDictionaryBuilder::<UInt16Type>::new(),
1604 StringDictionaryBuilder::<UInt16Type>::new(),
1605 );
1606
1607 builder.keys().append_value("k1");
1609 builder.values().append_value("a");
1610 builder.keys().append_value("k2");
1611 builder.values().append_null();
1612 builder.keys().append_value("k3");
1613 builder.values().append_value("b");
1614 builder.append(true).unwrap();
1615
1616 let arr1 = builder.finish();
1617
1618 builder.keys().append_value("k1");
1620 builder.values().append_value("c");
1621 builder.keys().append_value("k2");
1622 builder.values().append_null();
1623 builder.keys().append_value("k3");
1624 builder.values().append_value("d");
1625 builder.append(true).unwrap();
1626
1627 let arr2 = builder.finish();
1628
1629 let schema = Arc::new(Schema::new(vec![Field::new_map(
1630 "dict_map",
1631 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
1632 Field::new_dictionary(
1633 Field::MAP_KEY_FIELD_DEFAULT_NAME,
1634 DataType::UInt16,
1635 DataType::Utf8,
1636 false,
1637 ),
1638 Field::new_dictionary(
1639 Field::MAP_VALUE_FIELD_DEFAULT_NAME,
1640 DataType::UInt16,
1641 DataType::Utf8,
1642 true,
1643 ),
1644 false,
1645 false,
1646 )]));
1647
1648 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1649 let batch2 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr2)]).unwrap();
1650
1651 verify_flight_round_trip(vec![batch1, batch2]).await;
1652 }
1653
1654 #[tokio::test]
1655 async fn test_dictionary_ree_resend() {
1656 let dict_values1 = vec![Some("a"), None, Some("b")]
1657 .into_iter()
1658 .collect::<DictionaryArray<Int32Type>>();
1659 let run_ends1 = Int32Array::from(vec![1, 2, 3]);
1660 let arr1 = RunArray::try_new(&run_ends1, &dict_values1).unwrap();
1661
1662 let dict_values2 = vec![Some("c"), Some("a")]
1663 .into_iter()
1664 .collect::<DictionaryArray<Int32Type>>();
1665 let run_ends2 = Int32Array::from(vec![1, 2]);
1666 let arr2 = RunArray::try_new(&run_ends2, &dict_values2).unwrap();
1667
1668 let schema = Arc::new(Schema::new(vec![Field::new(
1669 "ree",
1670 arr1.data_type().clone(),
1671 true,
1672 )]));
1673
1674 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1675 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1676
1677 verify_flight_round_trip(vec![batch1, batch2]).await;
1678 }
1679
1680 #[tokio::test]
1681 async fn test_dictionary_of_struct_of_dict_resend() {
1682 let struct_fields: Vec<Field> = vec![
1686 Field::new_dictionary("dict", DataType::Int32, DataType::Utf8, true),
1687 Field::new("int", DataType::Int32, false),
1688 ];
1689
1690 let inner_values =
1691 StringArray::from(vec![Some("alpha"), None, Some("beta"), Some("gamma")]);
1692 let inner_keys = Int32Array::from_iter_values([0, 1, 2, 3, 0]);
1693 let inner_dict = DictionaryArray::new(inner_keys, Arc::new(inner_values));
1694 let int_array = Int32Array::from(vec![10, 20, 30, 40, 50]);
1695
1696 let struct_array = StructArray::from(vec![
1697 (
1698 Arc::new(struct_fields[0].clone()),
1699 Arc::new(inner_dict) as ArrayRef,
1700 ),
1701 (
1702 Arc::new(struct_fields[1].clone()),
1703 Arc::new(int_array) as ArrayRef,
1704 ),
1705 ]);
1706
1707 let outer_keys = Int8Array::from_iter_values([0, 0, 1, 2]);
1708 let arr1 = DictionaryArray::new(outer_keys, Arc::new(struct_array));
1709
1710 let inner_values2 = StringArray::from(vec![Some("x"), Some("y")]);
1711 let inner_keys2 = Int32Array::from_iter_values([0, 1, 0]);
1712 let inner_dict2 = DictionaryArray::new(inner_keys2, Arc::new(inner_values2));
1713 let int_array2 = Int32Array::from(vec![100, 200, 300]);
1714
1715 let struct_array2 = StructArray::from(vec![
1716 (
1717 Arc::new(struct_fields[0].clone()),
1718 Arc::new(inner_dict2) as ArrayRef,
1719 ),
1720 (
1721 Arc::new(struct_fields[1].clone()),
1722 Arc::new(int_array2) as ArrayRef,
1723 ),
1724 ]);
1725
1726 let outer_keys2 = Int8Array::from_iter_values([0, 1]);
1727 let arr2 = DictionaryArray::new(outer_keys2, Arc::new(struct_array2));
1728
1729 let schema = Arc::new(Schema::new(vec![Field::new(
1730 "dict_struct",
1731 arr1.data_type().clone(),
1732 false,
1733 )]));
1734
1735 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1736 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1737
1738 verify_flight_round_trip(vec![batch1, batch2]).await;
1739 }
1740
1741 async fn verify_dictionary_list_view_resend<O: OffsetSizeTrait>() {
1742 let mut builder =
1743 GenericListViewBuilder::<O, _>::new(StringDictionaryBuilder::<UInt16Type>::new());
1744
1745 builder.append_value(vec![Some("a"), None, Some("b")]);
1746 let arr1 = builder.finish();
1747
1748 builder.append_value(vec![Some("c"), None, Some("d")]);
1749 let arr2 = builder.finish();
1750
1751 let inner = Arc::new(Field::new_dictionary(
1752 "item",
1753 DataType::UInt16,
1754 DataType::Utf8,
1755 true,
1756 ));
1757 let dt = if O::IS_LARGE {
1758 DataType::LargeListView(inner)
1759 } else {
1760 DataType::ListView(inner)
1761 };
1762 let schema = Arc::new(Schema::new(vec![Field::new("dict_list_view", dt, true)]));
1763
1764 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1765 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1766
1767 verify_flight_round_trip(vec![batch1, batch2]).await;
1768 }
1769
1770 #[tokio::test]
1771 async fn test_dictionary_list_view_resend() {
1772 verify_dictionary_list_view_resend::<i32>().await;
1773 }
1774
1775 #[tokio::test]
1776 async fn test_dictionary_large_list_view_resend() {
1777 verify_dictionary_list_view_resend::<i64>().await;
1778 }
1779
1780 #[tokio::test]
1781 async fn test_dictionary_fixed_size_list_resend() {
1782 let mut builder =
1783 FixedSizeListBuilder::new(StringDictionaryBuilder::<UInt16Type>::new(), 2);
1784
1785 builder.values().append_value("a");
1786 builder.values().append_value("b");
1787 builder.append(true);
1788 let arr1 = builder.finish();
1789
1790 builder.values().append_value("c");
1791 builder.values().append_value("d");
1792 builder.append(true);
1793 let arr2 = builder.finish();
1794
1795 let schema = Arc::new(Schema::new(vec![Field::new_fixed_size_list(
1796 "dict_fsl",
1797 Field::new_dictionary("item", DataType::UInt16, DataType::Utf8, true),
1798 2,
1799 true,
1800 )]));
1801
1802 let batch1 = RecordBatch::try_new(schema.clone(), vec![Arc::new(arr1)]).unwrap();
1803 let batch2 = RecordBatch::try_new(schema, vec![Arc::new(arr2)]).unwrap();
1804
1805 verify_flight_round_trip(vec![batch1, batch2]).await;
1806 }
1807
1808 async fn verify_flight_round_trip(batches: Vec<RecordBatch>) {
1809 verify_flight_round_trip_with_options(batches, IpcWriteOptions::default()).await;
1810 }
1811
1812 async fn verify_flight_round_trip_with_options(
1815 batches: Vec<RecordBatch>,
1816 options: IpcWriteOptions,
1817 ) {
1818 let expected_schema = batches.first().unwrap().schema();
1819
1820 let encoder = FlightDataEncoderBuilder::default()
1821 .with_options(options)
1822 .with_dictionary_handling(DictionaryHandling::Resend)
1823 .build(futures::stream::iter(batches.clone().into_iter().map(Ok)));
1824
1825 let mut expected_batches = batches.into_iter();
1826
1827 let mut decoder = FlightDataDecoder::new(encoder);
1828 while let Some(decoded) = decoder.next().await {
1829 let decoded = decoded.unwrap();
1830 match decoded.payload {
1831 DecodedPayload::None => {}
1832 DecodedPayload::Schema(s) => assert_eq!(s, expected_schema),
1833 DecodedPayload::RecordBatch(b) => {
1834 let expected_batch = expected_batches.next().unwrap();
1835 assert_eq!(b, expected_batch);
1836 }
1837 }
1838 }
1839 }
1840
1841 #[test]
1842 fn test_schema_metadata_encoded() {
1843 let schema = Schema::new(vec![Field::new("data", DataType::Int32, false)]).with_metadata(
1844 HashMap::from([("some_key".to_owned(), "some_value".to_owned())]),
1845 );
1846
1847 let mut dictionary_tracker = DictionaryTracker::new(false);
1848
1849 let got = prepare_schema_for_flight(&schema, &mut dictionary_tracker, false);
1850 assert!(got.metadata().contains_key("some_key"));
1851 }
1852
1853 #[tokio::test]
1854 async fn test_list_schema_round_trip() {
1855 let list_item = Field::new("list_item", DataType::Int32, false).with_metadata(
1856 HashMap::from([("level".to_owned(), "list_item".to_owned())]),
1857 );
1858 let mut list_builder = ListBuilder::new(Int32Builder::new()).with_field(list_item);
1859 list_builder.append_value([Some(1), Some(2)]);
1860 list_builder.append_value([Some(3)]);
1861 let list = Arc::new(list_builder.finish()) as ArrayRef;
1862 let list_field = Field::new("list", list.data_type().clone(), false)
1863 .with_metadata(HashMap::from([("level".to_owned(), "list".to_owned())]));
1864
1865 let nested_item = Field::new("nested_item", DataType::Int32, true).with_metadata(
1866 HashMap::from([("level".to_owned(), "nested_item".to_owned())]),
1867 );
1868 let nested_list_builder =
1869 ListBuilder::new(Int32Builder::new()).with_field(nested_item.clone());
1870 let nested_list = Field::new_list("nested_list", nested_item, false).with_metadata(
1871 HashMap::from([("level".to_owned(), "nested_list".to_owned())]),
1872 );
1873 let mut large_list_builder =
1874 LargeListBuilder::new(nested_list_builder).with_field(nested_list);
1875 large_list_builder.values().append_value([Some(4), None]);
1876 large_list_builder.values().append_value([Some(5)]);
1877 large_list_builder.append(true);
1878 large_list_builder.append(false);
1879 let large_list = Arc::new(large_list_builder.finish()) as ArrayRef;
1880 let large_list_field =
1881 Field::new("large_list", large_list.data_type().clone(), true).with_metadata(
1882 HashMap::from([("level".to_owned(), "large_list".to_owned())]),
1883 );
1884
1885 let fixed_size_item = Field::new("fixed_size_item", DataType::Int32, true).with_metadata(
1886 HashMap::from([("level".to_owned(), "fixed_size_item".to_owned())]),
1887 );
1888 let mut fixed_size_list_builder =
1889 FixedSizeListBuilder::new(Int32Builder::new(), 2).with_field(fixed_size_item);
1890 fixed_size_list_builder.values().append_value(6);
1891 fixed_size_list_builder.values().append_null();
1892 fixed_size_list_builder.append(true);
1893 fixed_size_list_builder.values().append_value(7);
1894 fixed_size_list_builder.values().append_value(8);
1895 fixed_size_list_builder.append(true);
1896 let fixed_size_list = Arc::new(fixed_size_list_builder.finish()) as ArrayRef;
1897 let fixed_size_list_field = Field::new(
1898 "fixed_size_list",
1899 fixed_size_list.data_type().clone(),
1900 false,
1901 )
1902 .with_metadata(HashMap::from([(
1903 "level".to_owned(),
1904 "fixed_size_list".to_owned(),
1905 )]));
1906
1907 let schema = Arc::new(
1908 Schema::new(vec![list_field, large_list_field, fixed_size_list_field])
1909 .with_metadata(HashMap::from([("level".to_owned(), "schema".to_owned())])),
1910 );
1911 let batch = RecordBatch::try_new(schema, vec![list, large_list, fixed_size_list]).unwrap();
1912
1913 verify_flight_round_trip(vec![batch]).await;
1914 }
1915
1916 #[test]
1917 fn test_encode_no_column_batch() {
1918 let batch = RecordBatch::try_new_with_options(
1919 Arc::new(Schema::empty()),
1920 vec![],
1921 &RecordBatchOptions::new().with_row_count(Some(10)),
1922 )
1923 .expect("cannot create record batch");
1924
1925 hydrate_dictionaries(&batch, batch.schema()).expect("failed to optimize");
1926 }
1927
1928 fn make_flight_data(
1929 batch: &RecordBatch,
1930 options: &IpcWriteOptions,
1931 ) -> (Vec<FlightData>, FlightData) {
1932 flight_data_from_arrow_batch(batch, options)
1933 }
1934
1935 fn flight_data_from_arrow_batch(
1936 batch: &RecordBatch,
1937 options: &IpcWriteOptions,
1938 ) -> (Vec<FlightData>, FlightData) {
1939 let data_gen = IpcDataGenerator::default();
1940 let mut dictionary_tracker = DictionaryTracker::new(false);
1941 let mut ipc_write_context = IpcWriteContext::default();
1942
1943 let (encoded_dictionaries, encoded_batch) = data_gen
1944 .encode(
1945 batch,
1946 &mut dictionary_tracker,
1947 options,
1948 &mut ipc_write_context,
1949 )
1950 .expect("DictionaryTracker configured above to not error on replacement");
1951
1952 let flight_dictionaries = encoded_dictionaries.into_iter().map(Into::into).collect();
1953 let flight_batch = encoded_batch.into();
1954
1955 (flight_dictionaries, flight_batch)
1956 }
1957
1958 #[test]
1959 fn test_split_batch_for_grpc_response() {
1960 let max_flight_data_size = 1024;
1961
1962 let c = UInt32Array::from(vec![1, 2, 3, 4, 5, 6]);
1964 let batch = RecordBatch::try_from_iter(vec![("a", Arc::new(c) as ArrayRef)])
1965 .expect("cannot create record batch");
1966 let split: Vec<_> = split_batch_for_grpc_response(batch.clone(), max_flight_data_size);
1967 assert_eq!(split.len(), 1);
1968 assert_eq!(batch, split[0]);
1969
1970 let n_rows = max_flight_data_size + 1;
1972 assert!(n_rows % 2 == 1, "should be an odd number");
1973 let c = UInt8Array::from((0..n_rows).map(|i| (i % 256) as u8).collect::<Vec<_>>());
1974 let batch = RecordBatch::try_from_iter(vec![("a", Arc::new(c) as ArrayRef)])
1975 .expect("cannot create record batch");
1976 let split: Vec<_> = split_batch_for_grpc_response(batch.clone(), max_flight_data_size);
1977 assert_eq!(split.len(), 3);
1978 assert_eq!(
1979 split.iter().map(|batch| batch.num_rows()).sum::<usize>(),
1980 n_rows
1981 );
1982 let a = pretty_format_batches(&split).unwrap().to_string();
1983 let b = pretty_format_batches(&[batch]).unwrap().to_string();
1984 assert_eq!(a, b);
1985 }
1986
1987 #[test]
1988 fn test_split_batch_for_grpc_response_sizes() {
1989 verify_split(2000, 2 * 1024, vec![250, 250, 250, 250, 250, 250, 250, 250]);
1991
1992 verify_split(2000, 4 * 1024, vec![500, 500, 500, 500]);
1994
1995 verify_split(2023, 3 * 1024, vec![337, 337, 337, 337, 337, 337, 1]);
1997
1998 verify_split(10, 1, vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
2000
2001 verify_split(10, 1024, vec![10]);
2003 }
2004
2005 fn verify_split(
2009 num_input_rows: u64,
2010 max_flight_data_size_bytes: usize,
2011 expected_sizes: Vec<usize>,
2012 ) {
2013 let array: UInt64Array = (0..num_input_rows).collect();
2014
2015 let batch = RecordBatch::try_from_iter(vec![("a", Arc::new(array) as ArrayRef)])
2016 .expect("cannot create record batch");
2017
2018 let input_rows = batch.num_rows();
2019
2020 let split: Vec<_> =
2021 split_batch_for_grpc_response(batch.clone(), max_flight_data_size_bytes);
2022 let sizes: Vec<_> = split.iter().map(RecordBatch::num_rows).collect();
2023 let output_rows: usize = sizes.iter().sum();
2024
2025 assert_eq!(sizes, expected_sizes, "mismatch for {batch:?}");
2026 assert_eq!(input_rows, output_rows, "mismatch for {batch:?}");
2027 }
2028
2029 #[tokio::test]
2033 async fn flight_data_size_even() {
2034 let s1 = StringArray::from_iter_values(std::iter::repeat_n(".10 bytes.", 1024));
2035 let i1 = Int16Array::from_iter_values(0..1024);
2036 let s2 = StringArray::from_iter_values(std::iter::repeat_n("6bytes", 1024));
2037 let i2 = Int64Array::from_iter_values(0..1024);
2038
2039 let batch = RecordBatch::try_from_iter(vec![
2040 ("s1", Arc::new(s1) as _),
2041 ("i1", Arc::new(i1) as _),
2042 ("s2", Arc::new(s2) as _),
2043 ("i2", Arc::new(i2) as _),
2044 ])
2045 .unwrap();
2046
2047 verify_encoded_split(batch, 88).await;
2048 }
2049
2050 #[tokio::test]
2051 async fn flight_data_size_uneven_variable_lengths() {
2052 let array = StringArray::from_iter_values((0..1024).map(|i| "*".repeat(i)));
2054 let batch = RecordBatch::try_from_iter(vec![("data", Arc::new(array) as _)]).unwrap();
2055
2056 verify_encoded_split(batch, 4304).await;
2059 }
2060
2061 #[tokio::test]
2062 async fn flight_data_size_large_row() {
2063 let array1 = StringArray::from_iter_values(vec![
2065 "*".repeat(500),
2066 "*".repeat(500),
2067 "*".repeat(500),
2068 "*".repeat(500),
2069 ]);
2070 let array2 = StringArray::from_iter_values(vec![
2071 "*".to_string(),
2072 "*".repeat(1000),
2073 "*".repeat(2000),
2074 "*".repeat(4000),
2075 ]);
2076
2077 let array3 = StringArray::from_iter_values(vec![
2078 "*".to_string(),
2079 "*".to_string(),
2080 "*".repeat(1000),
2081 "*".repeat(2000),
2082 ]);
2083
2084 let batch = RecordBatch::try_from_iter(vec![
2085 ("a1", Arc::new(array1) as _),
2086 ("a2", Arc::new(array2) as _),
2087 ("a3", Arc::new(array3) as _),
2088 ])
2089 .unwrap();
2090
2091 verify_encoded_split(batch, 5784).await;
2095 }
2096
2097 #[tokio::test]
2098 async fn flight_data_size_string_dictionary() {
2099 let array: DictionaryArray<Int32Type> = (1..1024)
2101 .map(|i| match i % 3 {
2102 0 => Some("value0"),
2103 1 => Some("value1"),
2104 _ => None,
2105 })
2106 .collect();
2107
2108 let batch = RecordBatch::try_from_iter(vec![("a1", Arc::new(array) as _)]).unwrap();
2109
2110 verify_encoded_split(batch, 56).await;
2111 }
2112
2113 #[tokio::test]
2114 async fn flight_data_size_large_dictionary() {
2115 let values: Vec<_> = (1..1024).map(|i| "**".repeat(i)).collect();
2117
2118 let array: DictionaryArray<Int32Type> = values.iter().map(|s| Some(s.as_str())).collect();
2119
2120 let batch = RecordBatch::try_from_iter(vec![("a1", Arc::new(array) as _)]).unwrap();
2121
2122 verify_encoded_split(batch, 3328).await;
2125 }
2126
2127 #[tokio::test]
2128 async fn flight_data_size_large_dictionary_repeated_non_uniform() {
2129 let values = StringArray::from_iter_values((0..1024).map(|i| "******".repeat(i)));
2131 let keys = Int32Array::from_iter_values((0..3000).map(|i| (3000 - i) % 1024));
2132 let array = DictionaryArray::new(keys, Arc::new(values));
2133
2134 let batch = RecordBatch::try_from_iter(vec![("a1", Arc::new(array) as _)]).unwrap();
2135
2136 verify_encoded_split(batch, 5280).await;
2139 }
2140
2141 #[tokio::test]
2142 async fn flight_data_size_multiple_dictionaries() {
2143 let values1: Vec<_> = (1..1024).map(|i| "**".repeat(i)).collect();
2145 let values2: Vec<_> = (1..1024).map(|i| "**".repeat(i % 10)).collect();
2147 let values3: Vec<_> = (1..1024).map(|i| "**".repeat(i % 100)).collect();
2149
2150 let array1: DictionaryArray<Int32Type> = values1.iter().map(|s| Some(s.as_str())).collect();
2151 let array2: DictionaryArray<Int32Type> = values2.iter().map(|s| Some(s.as_str())).collect();
2152 let array3: DictionaryArray<Int32Type> = values3.iter().map(|s| Some(s.as_str())).collect();
2153
2154 let batch = RecordBatch::try_from_iter(vec![
2155 ("a1", Arc::new(array1) as _),
2156 ("a2", Arc::new(array2) as _),
2157 ("a3", Arc::new(array3) as _),
2158 ])
2159 .unwrap();
2160
2161 verify_encoded_split(batch, 4112).await;
2164 }
2165
2166 fn flight_data_size(d: &FlightData) -> usize {
2168 let flight_descriptor_size = d
2169 .flight_descriptor
2170 .as_ref()
2171 .map(|descriptor| {
2172 let path_len: usize = descriptor.path.iter().map(|p| p.len()).sum();
2173
2174 std::mem::size_of_val(descriptor) + descriptor.cmd.len() + path_len
2175 })
2176 .unwrap_or(0);
2177
2178 flight_descriptor_size + d.app_metadata.len() + d.data_body.len() + d.data_header.len()
2179 }
2180
2181 async fn verify_encoded_split(batch: RecordBatch, allowed_overage: usize) {
2197 let num_rows = batch.num_rows();
2198
2199 let mut max_overage_seen = 0;
2201
2202 for max_flight_data_size in [1024, 2021, 5000] {
2203 println!("Encoding {num_rows} with a maximum size of {max_flight_data_size}");
2204
2205 let mut stream = FlightDataEncoderBuilder::new()
2206 .with_max_flight_data_size(max_flight_data_size)
2207 .with_options(IpcWriteOptions::try_new(8, false, MetadataVersion::V5).unwrap())
2209 .build(futures::stream::iter([Ok(batch.clone())]));
2210
2211 let mut i = 0;
2212 while let Some(data) = stream.next().await.transpose().unwrap() {
2213 let actual_data_size = flight_data_size(&data);
2214
2215 let actual_overage = actual_data_size.saturating_sub(max_flight_data_size);
2216
2217 assert!(
2218 actual_overage <= allowed_overage,
2219 "encoded data[{i}]: actual size {actual_data_size}, \
2220 actual_overage: {actual_overage} \
2221 allowed_overage: {allowed_overage}"
2222 );
2223
2224 i += 1;
2225
2226 max_overage_seen = max_overage_seen.max(actual_overage)
2227 }
2228 }
2229
2230 assert_eq!(
2234 allowed_overage, max_overage_seen,
2235 "Specified overage was too high"
2236 );
2237 }
2238}