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