1#![cfg_attr(feature = "encryption", doc = "```rust")]
123#![cfg_attr(not(feature = "encryption"), doc = "```ignore")]
124#[cfg(feature = "experimental")]
172#[doc(hidden)]
173pub mod array_reader;
174#[cfg(not(feature = "experimental"))]
175mod array_reader;
176pub(crate) use array_reader::ByteArrayDecoderPlain;
179pub mod arrow_reader;
180pub mod arrow_writer;
181pub mod bloom_filter;
182mod buffer;
183#[cfg(feature = "file_experimental")]
184pub mod file_type;
185pub(crate) use buffer::offset_buffer::OffsetBuffer;
186mod decoder;
187
188#[cfg(feature = "async")]
189pub mod async_reader;
190#[cfg(feature = "async")]
191pub mod async_writer;
192
193pub mod push_decoder;
194
195mod in_memory_row_group;
196mod record_reader;
197
198#[cfg(feature = "experimental")]
199#[doc(hidden)]
200pub mod schema;
201#[cfg(not(feature = "experimental"))]
202mod schema;
203
204use std::fmt::Debug;
205
206pub use self::arrow_writer::ArrowWriter;
207#[cfg(feature = "async")]
208pub use self::async_reader::ParquetRecordBatchStreamBuilder;
209#[cfg(feature = "async")]
210pub use self::async_writer::AsyncArrowWriter;
211use crate::schema::types::SchemaDescriptor;
212use arrow_schema::{FieldRef, Schema};
213
214pub use self::schema::{
215 ArrowSchemaConverter, FieldLevels, add_encoded_arrow_schema_to_metadata, encode_arrow_schema,
216 parquet_to_arrow_field_levels, parquet_to_arrow_field_levels_with_virtual,
217 parquet_to_arrow_schema, parquet_to_arrow_schema_by_columns, virtual_type::*,
218};
219
220pub const ARROW_SCHEMA_META_KEY: &str = "ARROW:schema";
225
226pub const PARQUET_FIELD_ID_META_KEY: &str = "PARQUET:field_id";
232
233#[derive(Debug, Clone, PartialEq, Eq)]
259pub struct ProjectionMask {
260 mask: Option<Vec<bool>>,
280}
281
282impl ProjectionMask {
283 pub fn all() -> Self {
285 Self { mask: None }
286 }
287
288 pub fn none(len: usize) -> Self {
290 Self {
291 mask: Some(vec![false; len]),
292 }
293 }
294
295 pub fn leaves(schema: &SchemaDescriptor, indices: impl IntoIterator<Item = usize>) -> Self {
301 let mut mask = vec![false; schema.num_columns()];
302 for leaf_idx in indices {
303 mask[leaf_idx] = true;
304 }
305 Self { mask: Some(mask) }
306 }
307
308 pub fn roots(schema: &SchemaDescriptor, indices: impl IntoIterator<Item = usize>) -> Self {
314 let num_root_columns = schema.root_schema().get_fields().len();
315 let mut root_mask = vec![false; num_root_columns];
316 for root_idx in indices {
317 root_mask[root_idx] = true;
318 }
319
320 let mask = (0..schema.num_columns())
321 .map(|leaf_idx| {
322 let root_idx = schema.get_column_root_idx(leaf_idx);
323 root_mask[root_idx]
324 })
325 .collect();
326
327 Self { mask: Some(mask) }
328 }
329
330 pub fn columns<'a>(
361 schema: &SchemaDescriptor,
362 names: impl IntoIterator<Item = &'a str>,
363 ) -> Self {
364 let mut mask = vec![false; schema.num_columns()];
365 for name in names {
366 let name_path: Vec<&str> = name.split('.').collect();
367 for (idx, col) in schema.columns().iter().enumerate() {
368 let path = col.path().parts();
369 if name_path.len() > path.len() {
371 continue;
372 }
373 if name_path.iter().zip(path.iter()).all(|(a, b)| a == b) {
375 mask[idx] = true;
376 }
377 }
378 }
379
380 Self { mask: Some(mask) }
381 }
382
383 pub fn leaf_included(&self, leaf_idx: usize) -> bool {
385 self.mask.as_ref().map(|m| m[leaf_idx]).unwrap_or(true)
386 }
387
388 pub fn union(&mut self, other: &Self) {
397 match (self.mask.as_ref(), other.mask.as_ref()) {
398 (None, _) | (_, None) => self.mask = None,
399 (Some(a), Some(b)) => {
400 debug_assert_eq!(a.len(), b.len());
401 let mask = a.iter().zip(b.iter()).map(|(&a, &b)| a || b).collect();
402 self.mask = Some(mask);
403 }
404 }
405 }
406
407 pub fn intersect(&mut self, other: &Self) {
416 match (self.mask.as_ref(), other.mask.as_ref()) {
417 (None, _) => self.mask.clone_from(&other.mask),
418 (_, None) => {}
419 (Some(a), Some(b)) => {
420 debug_assert_eq!(a.len(), b.len());
421 let mask = a.iter().zip(b.iter()).map(|(&a, &b)| a && b).collect();
422 self.mask = Some(mask);
423 }
424 }
425 }
426
427 pub(crate) fn without_nested_types(&self, schema: &SchemaDescriptor) -> Option<Self> {
432 let num_leaves = schema.num_columns();
433
434 let num_roots = schema.root_schema().get_fields().len();
436 let mut root_leaf_counts = vec![0usize; num_roots];
437 for leaf_idx in 0..num_leaves {
438 let root_idx = schema.get_column_root_idx(leaf_idx);
439 root_leaf_counts[root_idx] += 1;
440 }
441
442 let mut included_leaves = Vec::new();
445 for leaf_idx in 0..num_leaves {
446 if self.leaf_included(leaf_idx) {
447 let root = schema.get_column_root(leaf_idx);
448 let root_idx = schema.get_column_root_idx(leaf_idx);
449 if root_leaf_counts[root_idx] == 1 && root.is_primitive() {
450 included_leaves.push(leaf_idx);
451 }
452 }
453 }
454
455 if included_leaves.is_empty() {
456 None
457 } else {
458 Some(ProjectionMask::leaves(schema, included_leaves))
459 }
460 }
461}
462
463pub fn parquet_column<'a>(
467 parquet_schema: &SchemaDescriptor,
468 arrow_schema: &'a Schema,
469 name: &str,
470) -> Option<(usize, &'a FieldRef)> {
471 let (root_idx, field) = arrow_schema.fields.find(name)?;
472 if field.data_type().is_nested() {
473 return None;
480 }
481
482 let parquet_idx = (0..parquet_schema.columns().len())
484 .find(|x| parquet_schema.get_column_root_idx(*x) == root_idx)?;
485 Some((parquet_idx, field))
486}
487
488#[cfg(test)]
489mod test {
490 use crate::arrow::ArrowWriter;
491 use crate::file::metadata::{
492 PageIndexPolicy, ParquetMetaData, ParquetMetaDataOptions, ParquetMetaDataReader,
493 ParquetMetaDataWriter,
494 };
495 use crate::file::properties::{EnabledStatistics, WriterProperties};
496 use crate::schema::parser::parse_message_type;
497 use crate::schema::types::SchemaDescriptor;
498 use arrow_array::{ArrayRef, Int32Array, RecordBatch};
499 use bytes::Bytes;
500 use std::sync::Arc;
501
502 use super::ProjectionMask;
503
504 #[test]
505 fn test_metadata_read_write_partial_offset() {
507 let parquet_bytes = create_parquet_file();
508
509 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
511 let original_metadata = ParquetMetaDataReader::new()
512 .with_metadata_options(Some(options))
513 .parse_and_finish(&parquet_bytes)
514 .unwrap();
515
516 let metadata_bytes = metadata_to_bytes(&original_metadata);
518 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
519 let err = ParquetMetaDataReader::new()
520 .with_metadata_options(Some(options))
521 .with_page_index_policy(PageIndexPolicy::Required) .parse_and_finish(&metadata_bytes)
523 .err()
524 .unwrap();
525 assert_eq!(
526 err.to_string(),
527 "EOF: Parquet file too small. Page index range 82..115 overlaps with file metadata 0..356"
528 );
529 }
530
531 #[test]
532 fn test_metadata_read_write_roundtrip() {
533 let parquet_bytes = create_parquet_file();
534
535 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
537 let original_metadata = ParquetMetaDataReader::new()
538 .with_metadata_options(Some(options))
539 .parse_and_finish(&parquet_bytes)
540 .unwrap();
541
542 let metadata_bytes = metadata_to_bytes(&original_metadata);
544 assert_ne!(
545 metadata_bytes.len(),
546 parquet_bytes.len(),
547 "metadata is subset of parquet"
548 );
549
550 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
551 let roundtrip_metadata = ParquetMetaDataReader::new()
552 .with_metadata_options(Some(options))
553 .parse_and_finish(&metadata_bytes)
554 .unwrap();
555
556 assert_eq!(original_metadata, roundtrip_metadata);
557 }
558
559 #[test]
560 #[cfg_attr(miri, ignore)] fn test_metadata_read_write_roundtrip_page_index() {
562 let parquet_bytes = create_parquet_file();
563
564 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
567 let original_metadata = ParquetMetaDataReader::new()
568 .with_metadata_options(Some(options))
569 .with_page_index_policy(PageIndexPolicy::Required)
570 .parse_and_finish(&parquet_bytes)
571 .unwrap();
572
573 let metadata_bytes = metadata_to_bytes(&original_metadata);
575 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
576 let roundtrip_metadata = ParquetMetaDataReader::new()
577 .with_metadata_options(Some(options))
578 .with_page_index_policy(PageIndexPolicy::Required)
579 .parse_and_finish(&metadata_bytes)
580 .unwrap();
581
582 let original_metadata = normalize_locations(original_metadata);
584 let roundtrip_metadata = normalize_locations(roundtrip_metadata);
585 assert_eq!(
586 format!("{original_metadata:#?}"),
587 format!("{roundtrip_metadata:#?}")
588 );
589 assert_eq!(original_metadata, roundtrip_metadata);
590 }
591
592 #[test]
593 fn test_metadata_read_write_roundtrip_missing_page_index() {
594 let parquet_bytes = create_parquet_file();
595
596 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
598 let original_metadata = ParquetMetaDataReader::new()
599 .with_metadata_options(Some(options))
600 .with_page_index_policy(PageIndexPolicy::Skip)
601 .parse_and_finish(&parquet_bytes)
602 .unwrap();
603
604 let metadata_bytes = metadata_to_bytes_no_page_idx(&original_metadata);
607 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
608 let roundtrip_metadata = ParquetMetaDataReader::new()
609 .with_metadata_options(Some(options))
610 .with_page_index_policy(PageIndexPolicy::Optional)
611 .parse_and_finish(&metadata_bytes)
612 .expect("page index locations should have been cleared");
613
614 assert!(roundtrip_metadata.page_index().is_none());
615 }
616
617 #[test]
618 fn test_metadata_read_write_roundtrip_offset_index_only() {
619 let array: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3]));
621 let batch = RecordBatch::try_from_iter(vec![("id", array)]).unwrap();
622 let props = WriterProperties::builder()
623 .set_statistics_enabled(EnabledStatistics::Chunk)
624 .build();
625 let mut buf = vec![];
626 let mut writer = ArrowWriter::try_new(&mut buf, batch.schema(), Some(props)).unwrap();
627 writer.write(&batch).unwrap();
628 writer.close().unwrap();
629
630 let read = |bytes: &Bytes| {
631 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
632 ParquetMetaDataReader::new()
633 .with_metadata_options(Some(options))
634 .with_page_index_policy(PageIndexPolicy::Optional)
635 .parse_and_finish(bytes)
636 .unwrap()
637 };
638 let original = read(&Bytes::from(buf));
639 let page_index = original.page_index().unwrap();
640 assert!(!page_index.has_column_indexes() && page_index.has_offset_indexes());
641 let roundtrip = read(&metadata_to_bytes(&original));
642 assert_eq!(
643 normalize_locations(original),
644 normalize_locations(roundtrip)
645 );
646 }
647
648 #[test]
649 fn test_metadata_read_write_roundtrip_custom_page_index() {
650 use crate::file::metadata::page_index::PageIndexProvider;
651 use crate::file::page_index::{
652 column_index::ColumnIndexMetaData, offset_index::OffsetIndexMetaData,
653 };
654
655 #[derive(Debug)]
657 struct Forward(Arc<dyn PageIndexProvider>);
658 impl PageIndexProvider for Forward {
659 fn has_offset_indexes(&self) -> bool {
660 self.0.has_offset_indexes()
661 }
662 fn has_column_indexes(&self) -> bool {
663 self.0.has_column_indexes()
664 }
665 fn column_index(&self, rg: usize, col: usize) -> Option<&ColumnIndexMetaData> {
666 self.0.column_index(rg, col)
667 }
668 fn offset_index(&self, rg: usize, col: usize) -> Option<&OffsetIndexMetaData> {
669 self.0.offset_index(rg, col)
670 }
671 fn as_any(&self) -> &dyn std::any::Any {
672 self
673 }
674 }
675
676 let read = |bytes: &Bytes| {
677 let options = ParquetMetaDataOptions::new().with_encoding_stats_as_mask(false);
678 ParquetMetaDataReader::new()
679 .with_metadata_options(Some(options))
680 .with_page_index_policy(PageIndexPolicy::Required)
681 .parse_and_finish(bytes)
682 .unwrap()
683 };
684 let original = read(&create_parquet_file());
685 let provider = Forward(original.page_index().unwrap().clone());
686 let custom = original
687 .clone()
688 .into_builder()
689 .set_page_index(Some(Arc::new(provider)))
690 .build();
691 let roundtrip = read(&metadata_to_bytes(&custom));
692 assert_eq!(
693 normalize_locations(original),
694 normalize_locations(roundtrip)
695 );
696 }
697
698 fn normalize_locations(metadata: ParquetMetaData) -> ParquetMetaData {
703 let mut metadata_builder = metadata.into_builder();
704 for rg in metadata_builder.take_row_groups() {
705 let mut rg_builder = rg.into_builder();
706 for col in rg_builder.take_columns() {
707 rg_builder = rg_builder.add_column_metadata(
708 col.into_builder()
709 .set_offset_index_offset(None)
710 .set_index_page_offset(None)
711 .set_column_index_offset(None)
712 .build()
713 .unwrap(),
714 );
715 }
716 let rg = rg_builder.build().unwrap();
717 metadata_builder = metadata_builder.add_row_group(rg);
718 }
719 metadata_builder.build()
720 }
721
722 fn create_parquet_file() -> Bytes {
724 let mut buf = vec![];
725 let data = vec![100, 200, 201, 300, 102, 33];
726 let array: ArrayRef = Arc::new(Int32Array::from(data));
727 let batch = RecordBatch::try_from_iter(vec![("id", array)]).unwrap();
728 let props = WriterProperties::builder()
729 .set_statistics_enabled(EnabledStatistics::Page)
730 .set_write_page_header_statistics(true)
731 .build();
732
733 let mut writer = ArrowWriter::try_new(&mut buf, batch.schema(), Some(props)).unwrap();
734 writer.write(&batch).unwrap();
735 writer.finish().unwrap();
736 drop(writer);
737
738 Bytes::from(buf)
739 }
740
741 fn metadata_to_bytes(metadata: &ParquetMetaData) -> Bytes {
743 let mut buf = vec![];
744 ParquetMetaDataWriter::new(&mut buf, metadata)
745 .finish()
746 .unwrap();
747 Bytes::from(buf)
748 }
749
750 fn metadata_to_bytes_no_page_idx(metadata: &ParquetMetaData) -> Bytes {
752 let mut buf = vec![];
753 ParquetMetaDataWriter::new(&mut buf, metadata)
754 .with_preserve_page_index_locations(false)
755 .finish()
756 .unwrap();
757 Bytes::from(buf)
758 }
759
760 #[test]
761 fn test_mask_from_column_names() {
762 let schema = parse_schema(
763 "
764 message test_schema {
765 OPTIONAL group a (MAP) {
766 REPEATED group key_value {
767 REQUIRED BYTE_ARRAY key (UTF8);
768 OPTIONAL group value (MAP) {
769 REPEATED group key_value {
770 REQUIRED INT32 key;
771 REQUIRED BOOLEAN value;
772 }
773 }
774 }
775 }
776 REQUIRED INT32 b;
777 REQUIRED DOUBLE c;
778 }
779 ",
780 );
781
782 let mask = ProjectionMask::columns(&schema, ["foo", "bar"]);
783 assert_eq!(mask.mask.unwrap(), vec![false; 5]);
784
785 let mask = ProjectionMask::columns(&schema, []);
786 assert_eq!(mask.mask.unwrap(), vec![false; 5]);
787
788 let mask = ProjectionMask::columns(&schema, ["a", "c"]);
789 assert_eq!(mask.mask.unwrap(), [true, true, true, false, true]);
790
791 let mask = ProjectionMask::columns(&schema, ["a.key_value.key", "c"]);
792 assert_eq!(mask.mask.unwrap(), [true, false, false, false, true]);
793
794 let mask = ProjectionMask::columns(&schema, ["a.key_value.value", "b"]);
795 assert_eq!(mask.mask.unwrap(), [false, true, true, true, false]);
796
797 let schema = parse_schema(
798 "
799 message test_schema {
800 OPTIONAL group a (LIST) {
801 REPEATED group list {
802 OPTIONAL group element (LIST) {
803 REPEATED group list {
804 OPTIONAL group element (LIST) {
805 REPEATED group list {
806 OPTIONAL BYTE_ARRAY element (UTF8);
807 }
808 }
809 }
810 }
811 }
812 }
813 REQUIRED INT32 b;
814 }
815 ",
816 );
817
818 let mask = ProjectionMask::columns(&schema, ["a", "b"]);
819 assert_eq!(mask.mask.unwrap(), [true, true]);
820
821 let mask = ProjectionMask::columns(&schema, ["a.list.element", "b"]);
822 assert_eq!(mask.mask.unwrap(), [true, true]);
823
824 let mask =
825 ProjectionMask::columns(&schema, ["a.list.element.list.element.list.element", "b"]);
826 assert_eq!(mask.mask.unwrap(), [true, true]);
827
828 let mask = ProjectionMask::columns(&schema, ["b"]);
829 assert_eq!(mask.mask.unwrap(), [false, true]);
830
831 let schema = parse_schema(
832 "
833 message test_schema {
834 OPTIONAL INT32 a;
835 OPTIONAL INT32 b;
836 OPTIONAL INT32 c;
837 OPTIONAL INT32 d;
838 OPTIONAL INT32 e;
839 }
840 ",
841 );
842
843 let mask = ProjectionMask::columns(&schema, ["a", "b"]);
844 assert_eq!(mask.mask.unwrap(), [true, true, false, false, false]);
845
846 let mask = ProjectionMask::columns(&schema, ["d", "b", "d"]);
847 assert_eq!(mask.mask.unwrap(), [false, true, false, true, false]);
848
849 let schema = parse_schema(
850 "
851 message test_schema {
852 OPTIONAL INT32 a;
853 OPTIONAL INT32 b;
854 OPTIONAL INT32 a;
855 OPTIONAL INT32 d;
856 OPTIONAL INT32 e;
857 }
858 ",
859 );
860
861 let mask = ProjectionMask::columns(&schema, ["a", "e"]);
862 assert_eq!(mask.mask.unwrap(), [true, false, true, false, true]);
863
864 let schema = parse_schema(
865 "
866 message test_schema {
867 OPTIONAL INT32 a;
868 OPTIONAL INT32 aa;
869 }
870 ",
871 );
872
873 let mask = ProjectionMask::columns(&schema, ["a"]);
874 assert_eq!(mask.mask.unwrap(), [true, false]);
875 }
876
877 #[test]
878 fn test_projection_mask_union() {
879 let mut mask1 = ProjectionMask {
880 mask: Some(vec![true, false, true]),
881 };
882 let mask2 = ProjectionMask {
883 mask: Some(vec![false, true, true]),
884 };
885 mask1.union(&mask2);
886 assert_eq!(mask1.mask, Some(vec![true, true, true]));
887
888 let mut mask1 = ProjectionMask { mask: None };
889 let mask2 = ProjectionMask {
890 mask: Some(vec![false, true, true]),
891 };
892 mask1.union(&mask2);
893 assert_eq!(mask1.mask, None);
894
895 let mut mask1 = ProjectionMask {
896 mask: Some(vec![true, false, true]),
897 };
898 let mask2 = ProjectionMask { mask: None };
899 mask1.union(&mask2);
900 assert_eq!(mask1.mask, None);
901
902 let mut mask1 = ProjectionMask { mask: None };
903 let mask2 = ProjectionMask { mask: None };
904 mask1.union(&mask2);
905 assert_eq!(mask1.mask, None);
906 }
907
908 #[test]
909 fn test_projection_mask_intersect() {
910 let mut mask1 = ProjectionMask {
911 mask: Some(vec![true, false, true]),
912 };
913 let mask2 = ProjectionMask {
914 mask: Some(vec![false, true, true]),
915 };
916 mask1.intersect(&mask2);
917 assert_eq!(mask1.mask, Some(vec![false, false, true]));
918
919 let mut mask1 = ProjectionMask { mask: None };
920 let mask2 = ProjectionMask {
921 mask: Some(vec![false, true, true]),
922 };
923 mask1.intersect(&mask2);
924 assert_eq!(mask1.mask, Some(vec![false, true, true]));
925
926 let mut mask1 = ProjectionMask {
927 mask: Some(vec![true, false, true]),
928 };
929 let mask2 = ProjectionMask { mask: None };
930 mask1.intersect(&mask2);
931 assert_eq!(mask1.mask, Some(vec![true, false, true]));
932
933 let mut mask1 = ProjectionMask { mask: None };
934 let mask2 = ProjectionMask { mask: None };
935 mask1.intersect(&mask2);
936 assert_eq!(mask1.mask, None);
937 }
938
939 #[test]
940 fn test_projection_mask_without_nested_no_nested() {
941 let schema = parse_schema(
943 "
944 message test_schema {
945 OPTIONAL INT32 a;
946 OPTIONAL INT32 b;
947 REQUIRED DOUBLE d;
948 }
949 ",
950 );
951
952 let mask = ProjectionMask::all();
953 assert_eq!(
955 Some(ProjectionMask::leaves(&schema, [0, 1, 2])),
956 mask.without_nested_types(&schema)
957 );
958
959 let mask = ProjectionMask::leaves(&schema, [1, 2]);
961 assert_eq!(Some(mask.clone()), mask.without_nested_types(&schema));
962 }
963
964 #[test]
965 fn test_projection_mask_without_nested_nested() {
966 let schema = parse_schema(
968 "
969 message test_schema {
970 OPTIONAL INT32 a;
971 OPTIONAL group b {
972 REQUIRED INT32 b1;
973 OPTIONAL INT64 b2;
974 }
975 OPTIONAL group c (LIST) {
976 REPEATED group list {
977 OPTIONAL INT32 element;
978 }
979 }
980 REQUIRED DOUBLE d;
981 }
982 ",
983 );
984
985 let mask = ProjectionMask::all();
987 assert_eq!(
988 Some(ProjectionMask::leaves(&schema, [0, 4])),
989 mask.without_nested_types(&schema)
990 );
991
992 let mask = ProjectionMask::leaves(&schema, [1]);
994 assert_eq!(None, mask.without_nested_types(&schema));
995
996 let mask = ProjectionMask::leaves(&schema, [1, 4]);
998 assert_eq!(
999 Some(ProjectionMask::leaves(&schema, [4])),
1000 mask.without_nested_types(&schema)
1001 );
1002
1003 let mask = ProjectionMask::leaves(&schema, [3]);
1005 assert_eq!(None, mask.without_nested_types(&schema));
1006 }
1007
1008 #[test]
1009 fn test_projection_mask_without_nested_map_only() {
1010 let schema = parse_schema(
1012 "
1013 message test_schema {
1014 required group my_map (MAP) {
1015 repeated group key_value {
1016 required binary key (STRING);
1017 optional int32 value;
1018 }
1019 }
1020 }
1021 ",
1022 );
1023
1024 let mask = ProjectionMask::all();
1025 assert_eq!(None, mask.without_nested_types(&schema));
1026
1027 let mask = ProjectionMask::leaves(&schema, [0]);
1029 assert_eq!(None, mask.without_nested_types(&schema));
1030
1031 let mask = ProjectionMask::leaves(&schema, [1]);
1033 assert_eq!(None, mask.without_nested_types(&schema));
1034 }
1035
1036 #[test]
1037 fn test_projection_mask_without_nested_map_with_non_nested() {
1038 let schema = parse_schema(
1041 "
1042 message test_schema {
1043 REQUIRED INT32 a;
1044 required group my_map (MAP) {
1045 repeated group key_value {
1046 required binary key (STRING);
1047 optional int32 value;
1048 }
1049 }
1050 REQUIRED INT32 b;
1051 }
1052 ",
1053 );
1054
1055 let mask = ProjectionMask::all();
1057 assert_eq!(
1058 Some(ProjectionMask::leaves(&schema, [0, 3])),
1059 mask.without_nested_types(&schema)
1060 );
1061
1062 let mask = ProjectionMask::leaves(&schema, [1, 2, 3]);
1064 assert_eq!(
1065 Some(ProjectionMask::leaves(&schema, [3])),
1066 mask.without_nested_types(&schema)
1067 );
1068
1069 let mask = ProjectionMask::leaves(&schema, [1, 2]);
1071 assert_eq!(None, mask.without_nested_types(&schema));
1072 }
1073
1074 #[test]
1075 fn test_projection_mask_without_nested_deeply_nested() {
1076 let schema = parse_schema(
1078 "
1079 message test_schema {
1080 OPTIONAL group a (MAP) {
1081 REPEATED group key_value {
1082 REQUIRED BYTE_ARRAY key (UTF8);
1083 OPTIONAL group value (MAP) {
1084 REPEATED group key_value {
1085 REQUIRED INT32 key;
1086 REQUIRED BOOLEAN value;
1087 }
1088 }
1089 }
1090 }
1091 REQUIRED INT32 b;
1092 REQUIRED DOUBLE c;
1093 ",
1094 );
1095
1096 let mask = ProjectionMask::all();
1097 assert_eq!(
1098 Some(ProjectionMask::leaves(&schema, [3, 4])),
1099 mask.without_nested_types(&schema)
1100 );
1101
1102 let mask = ProjectionMask::leaves(&schema, [0, 4]);
1104 assert_eq!(
1105 Some(ProjectionMask::leaves(&schema, [4])),
1106 mask.without_nested_types(&schema)
1107 );
1108
1109 let mask = ProjectionMask::leaves(&schema, [1, 2, 3]);
1111 assert_eq!(
1112 Some(ProjectionMask::leaves(&schema, [3])),
1113 mask.without_nested_types(&schema)
1114 );
1115
1116 let mask = ProjectionMask::leaves(&schema, [0]);
1118 assert_eq!(None, mask.without_nested_types(&schema));
1119 }
1120
1121 #[test]
1122 fn test_projection_mask_without_nested_list() {
1123 let schema = parse_schema(
1125 "
1126 message test_schema {
1127 required group my_list (LIST) {
1128 repeated group list {
1129 optional binary element (STRING);
1130 }
1131 }
1132 REQUIRED INT32 b;
1133 }
1134 ",
1135 );
1136
1137 let mask = ProjectionMask::all();
1138 assert_eq!(
1139 Some(ProjectionMask::leaves(&schema, [1])),
1140 mask.without_nested_types(&schema),
1141 );
1142
1143 let mask = ProjectionMask::leaves(&schema, [0]);
1145 assert_eq!(None, mask.without_nested_types(&schema));
1146
1147 let mask = ProjectionMask::leaves(&schema, [0, 1]);
1149 assert_eq!(
1150 Some(ProjectionMask::leaves(&schema, [1])),
1151 mask.without_nested_types(&schema),
1152 );
1153 }
1154
1155 #[test]
1156 fn test_projection_mask_without_nested_single_leaf_struct() {
1157 let schema = parse_schema(
1159 "
1160 message test_schema {
1161 OPTIONAL group address {
1162 REQUIRED BYTE_ARRAY street (UTF8);
1163 }
1164 REQUIRED INT32 id;
1165 }
1166 ",
1167 );
1168
1169 let mask = ProjectionMask::leaves(&schema, [0]);
1171 assert_eq!(None, mask.without_nested_types(&schema));
1172
1173 let mask = ProjectionMask::leaves(&schema, [0, 1]);
1175 assert_eq!(
1176 Some(ProjectionMask::leaves(&schema, [1])),
1177 mask.without_nested_types(&schema)
1178 );
1179
1180 let mask = ProjectionMask::all();
1182 assert_eq!(
1183 Some(ProjectionMask::leaves(&schema, [1])),
1184 mask.without_nested_types(&schema)
1185 );
1186 }
1187
1188 fn parse_schema(schema: &str) -> SchemaDescriptor {
1190 let parquet_group_type = parse_message_type(schema).unwrap();
1191 SchemaDescriptor::new(Arc::new(parquet_group_type))
1192 }
1193}