1use std::collections::HashSet;
16use std::ops::Range;
17
18use datatypes::arrow::datatypes::Schema as ArrowSchema;
19use datatypes::extension::json::{JSON2_REMAINDER_FIELD_NAME, is_json2_extension_type};
20use parquet::arrow::ProjectionMask;
21use parquet::basic::{ConvertedType, Type as PhysicalType};
22use parquet::schema::types::{ColumnDescriptor, SchemaDescriptor};
23
24use crate::error::Result as MitoResult;
25
26pub type ParquetNestedPath = Vec<String>;
28
29#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct ParquetReadColumns {
32 root_indices: Vec<usize>,
38 cols: Vec<ParquetReadColumn>,
39 has_nested: bool,
40}
41
42impl ParquetReadColumns {
43 pub fn from_deduped(cols: Vec<ParquetReadColumn>) -> Self {
50 let has_nested = cols.iter().any(|col| !col.nested_paths.is_empty());
51 let root_indices = cols.iter().map(|col| col.root_index).collect();
52 Self {
53 root_indices,
54 cols,
55 has_nested,
56 }
57 }
58
59 pub fn from_deduped_root_indices(root_indices: impl IntoIterator<Item = usize>) -> Self {
64 let root_indices = root_indices.into_iter().collect::<Vec<_>>();
65 let cols = root_indices
66 .iter()
67 .copied()
68 .map(ParquetReadColumn::new)
69 .collect();
70 Self {
71 root_indices,
72 cols,
73 has_nested: false,
74 }
75 }
76
77 pub fn columns(&self) -> &[ParquetReadColumn] {
78 &self.cols
79 }
80
81 pub fn has_nested(&self) -> bool {
82 self.has_nested
83 }
84
85 pub fn root_indices_iter(&self) -> impl Iterator<Item = usize> + '_ {
86 self.root_indices.iter().copied()
87 }
88
89 pub fn root_indices(&self) -> &[usize] {
91 &self.root_indices
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct ParquetReadColumn {
108 root_index: usize,
110 nested_paths: Vec<ParquetNestedPath>,
117}
118
119impl ParquetReadColumn {
120 pub fn new(root_index: usize) -> Self {
121 Self {
122 root_index,
123 nested_paths: vec![],
124 }
125 }
126
127 pub fn with_nested_paths(self, nested_paths: Vec<ParquetNestedPath>) -> Self {
128 Self {
129 nested_paths,
130 ..self
131 }
132 }
133
134 pub fn merge_nested_paths(&mut self, nested_paths: Vec<ParquetNestedPath>) {
136 let reads_whole_root = self.nested_paths.is_empty() || nested_paths.is_empty();
137 if reads_whole_root {
138 self.nested_paths = vec![];
140 } else {
141 self.nested_paths.extend(nested_paths);
142 }
143 }
144
145 pub fn root_index(&self) -> usize {
146 self.root_index
147 }
148
149 pub fn nested_paths(&self) -> &[ParquetNestedPath] {
150 &self.nested_paths
151 }
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub(crate) enum NestedSelectionPolicy {
157 Json2,
165}
166
167impl NestedSelectionPolicy {
168 fn select_leaves(
170 self,
171 schema: &SchemaDescriptor,
172 leaf_range: Range<usize>,
173 col: &ParquetReadColumn,
174 selected: &mut HashSet<usize>,
175 ) {
176 select_json2_leaves(schema, leaf_range, col, selected);
177 }
178}
179
180#[derive(Clone)]
182pub struct ProjectionMaskPlan {
183 pub mask: ProjectionMask,
185 pub projected_root_presence: Vec<bool>,
195}
196
197pub(crate) fn build_projection_plan(
217 parquet_read_cols: &ParquetReadColumns,
218 parquet_schema_desc: &SchemaDescriptor,
219 source_schema: &ArrowSchema,
220) -> MitoResult<ProjectionMaskPlan> {
221 if !parquet_read_cols.has_nested() {
222 let mask =
223 ProjectionMask::roots(parquet_schema_desc, parquet_read_cols.root_indices_iter());
224
225 return Ok(ProjectionMaskPlan {
226 mask,
227 projected_root_presence: vec![true; parquet_read_cols.columns().len()],
228 });
229 }
230
231 let (matched_leaves, matched_roots) =
232 build_parquet_leaves_indices(parquet_schema_desc, parquet_read_cols, source_schema)?;
233
234 let projected_root_presence = parquet_read_cols
235 .columns()
236 .iter()
237 .map(|col| matched_roots.contains(&col.root_index()))
238 .collect();
239
240 let mask = ProjectionMask::leaves(parquet_schema_desc, matched_leaves);
241
242 Ok(ProjectionMaskPlan {
243 mask,
244 projected_root_presence,
245 })
246}
247
248fn build_parquet_leaves_indices(
254 parquet_schema_desc: &SchemaDescriptor,
255 projection: &ParquetReadColumns,
256 source_schema: &ArrowSchema,
257) -> MitoResult<(Vec<usize>, HashSet<usize>)> {
258 let root_leaf_ranges = group_requested_leaf_ranges(parquet_schema_desc, projection);
259
260 let mut matched_leaves = HashSet::new();
261 let mut matched_roots = HashSet::with_capacity(projection.columns().len());
262
263 for col in projection.columns() {
264 let before = matched_leaves.len();
265
266 let leaf_range = root_leaf_ranges[col.root_index()].clone();
267
268 if col.nested_paths().is_empty() {
269 matched_leaves.extend(leaf_range);
270 } else if is_json2_extension_type(&source_schema.fields()[col.root_index()]) {
271 NestedSelectionPolicy::Json2.select_leaves(
272 parquet_schema_desc,
273 leaf_range,
274 col,
275 &mut matched_leaves,
276 );
277 } else {
278 select_prefix_leaves(parquet_schema_desc, leaf_range, col, &mut matched_leaves);
279 }
280
281 if matched_leaves.len() > before {
283 matched_roots.insert(col.root_index());
284 }
285 }
286
287 let mut matched_leaves = matched_leaves.into_iter().collect::<Vec<_>>();
288 matched_leaves.sort_unstable();
289
290 Ok((matched_leaves, matched_roots))
291}
292
293fn group_requested_leaf_ranges(
295 schema: &SchemaDescriptor,
296 projection: &ParquetReadColumns,
297) -> Vec<Range<usize>> {
298 let root_count = schema.root_schema().get_fields().len();
299 let mut requested = vec![false; root_count];
300 for col in projection.columns() {
301 requested[col.root_index()] = true;
302 }
303
304 let mut ranges = vec![0..0; root_count];
305 let mut leaf_idx = 0;
306 while leaf_idx < schema.num_columns() {
307 let root_idx = schema.get_column_root_idx(leaf_idx);
308 let start = leaf_idx;
309 while leaf_idx < schema.num_columns() && schema.get_column_root_idx(leaf_idx) == root_idx {
310 leaf_idx += 1;
311 }
312 if requested[root_idx] {
313 ranges[root_idx] = start..leaf_idx;
314 }
315 }
316 ranges
317}
318
319fn select_json2_leaves(
321 schema: &SchemaDescriptor,
322 leaf_range: Range<usize>,
323 col: &ParquetReadColumn,
324 selected: &mut HashSet<usize>,
325) {
326 let prefix_matched = select_prefix_leaves(schema, leaf_range, col, selected);
327 let mut needs_remainder = false;
328 for (matched, path) in prefix_matched.iter().zip(&col.nested_paths) {
329 if *matched {
330 needs_remainder |= path_points_to_struct(schema, col.root_index, path);
331 } else if let Some(idx) = find_nearest_variant_parent(schema, col.root_index, path) {
332 selected.insert(idx);
333 } else {
334 needs_remainder = true;
335 }
336 }
337 if needs_remainder {
338 selected.extend(find_remainder_leaves(schema, col.root_index));
339 }
340}
341
342fn select_prefix_leaves(
344 schema: &SchemaDescriptor,
345 leaf_range: Range<usize>,
346 col: &ParquetReadColumn,
347 selected: &mut HashSet<usize>,
348) -> Vec<bool> {
349 let mut prefix_matched = vec![false; col.nested_paths().len()];
350 for leaf_idx in leaf_range {
351 let leaf_path = schema.columns()[leaf_idx].path().parts();
352 let mut matched_leaf = false;
353 for (path, matched) in col.nested_paths().iter().zip(&mut prefix_matched) {
354 if leaf_path.starts_with(path) {
355 *matched = true;
356 matched_leaf = true;
357 }
358 }
359 if matched_leaf {
360 selected.insert(leaf_idx);
361 }
362 }
363 prefix_matched
364}
365
366fn path_points_to_struct(
371 parquet_schema_desc: &SchemaDescriptor,
372 root_idx: usize,
373 path: &[String],
374) -> bool {
375 let Some(mut field) = parquet_schema_desc.root_schema().get_fields().get(root_idx) else {
376 return false;
377 };
378 for name in path.iter().skip(1) {
379 if !field.is_group() {
380 return false;
381 }
382 let Some(child) = field.get_fields().iter().find(|field| field.name() == name) else {
383 return false;
384 };
385 field = child;
386 }
387 field.is_group()
388}
389
390fn find_remainder_leaves(parquet_schema_desc: &SchemaDescriptor, root_idx: usize) -> Vec<usize> {
396 parquet_schema_desc
397 .columns()
398 .iter()
399 .enumerate()
400 .filter_map(|(i, column)| {
401 let path = column.path().parts();
402 (parquet_schema_desc.get_column_root_idx(i) == root_idx
403 && path.get(1).is_some_and(|x| x == JSON2_REMAINDER_FIELD_NAME))
404 .then_some(i)
405 })
406 .collect::<Vec<_>>()
407}
408
409fn find_nearest_variant_parent(
410 parquet_schema_desc: &SchemaDescriptor,
411 root_idx: usize,
412 nested_path: &[String],
413) -> Option<usize> {
414 if nested_path.len() <= 1 {
416 return None;
417 }
418
419 for parent_len in (2..nested_path.len()).rev() {
422 let parent_path = &nested_path[..parent_len];
423 for (leaf_idx, leaf_col) in parquet_schema_desc.columns().iter().enumerate() {
424 if parquet_schema_desc.get_column_root_idx(leaf_idx) != root_idx {
425 continue;
426 }
427 if leaf_col.path().parts() == parent_path && is_variant_leaf(leaf_col) {
428 return Some(leaf_idx);
429 }
430 }
431 }
432
433 None
434}
435
436fn is_variant_leaf(leaf_col: &ColumnDescriptor) -> bool {
437 matches!(
440 leaf_col.physical_type(),
441 PhysicalType::BYTE_ARRAY | PhysicalType::FIXED_LEN_BYTE_ARRAY
442 ) && leaf_col.logical_type_ref().is_none()
443 && leaf_col.converted_type() == ConvertedType::NONE
444}
445
446#[cfg(test)]
447mod tests {
448 use std::sync::Arc;
449
450 use datatypes::arrow::datatypes::{DataType, Field, Fields, Schema as ArrowSchema};
451 use datatypes::extension::json::{Json2ExtensionType, JsonMetadata};
452 use datatypes::json::JsonSettings;
453 use parquet::basic::{LogicalType, Repetition, VariantType};
454 use parquet::errors::ParquetError;
455 use parquet::schema::types::Type;
456
457 use super::*;
458
459 #[test]
460 fn test_build_projection_mask_without_nested_paths() {
461 let parquet_schema_desc = build_test_nested_parquet_schema();
462 let projection = ParquetReadColumns::from_deduped_root_indices([0, 1]);
463
464 let plan = build_projection_plan(&projection, &parquet_schema_desc, &[None; 2]);
465
466 assert_eq!(vec![true, true], plan.projected_root_presence);
467 assert_eq!(
468 ProjectionMask::roots(&parquet_schema_desc, [0, 1]),
469 plan.mask
470 );
471 }
472
473 #[test]
474 fn test_reads_whole_root() {
475 let parquet_schema_desc = build_test_nested_parquet_schema();
476
477 let projection = ParquetReadColumns::from_deduped(vec![ParquetReadColumn::new(0)]);
478
479 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
480 &parquet_schema_desc,
481 &projection,
482 &[None; 2],
483 );
484 assert_eq!(vec![0, 1, 2], matched_leaves);
485 assert_eq!(HashSet::from([0]), matched_roots);
486 }
487
488 #[test]
489 fn test_filters_nested_paths() {
490 let parquet_schema_desc = build_test_nested_parquet_schema();
491
492 let projection = ParquetReadColumns::from_deduped(vec![
493 ParquetReadColumn::new(0)
494 .with_nested_paths(vec![vec!["j".to_string(), "b".to_string()]]),
495 ParquetReadColumn::new(1),
496 ]);
497
498 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
499 &parquet_schema_desc,
500 &projection,
501 &[None; 2],
502 );
503 assert_eq!(vec![1, 2, 3], matched_leaves);
504 assert_eq!(HashSet::from([0, 1]), matched_roots);
505 }
506
507 #[test]
508 fn test_reads_middle_level_path() {
509 let parquet_schema_desc = build_test_nested_parquet_schema();
510
511 let projection = ParquetReadColumns::from_deduped(vec![
512 ParquetReadColumn::new(0)
513 .with_nested_paths(vec![vec!["j".to_string(), "b".to_string()]]),
514 ]);
515
516 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
517 &parquet_schema_desc,
518 &projection,
519 &[None; 2],
520 );
521 assert_eq!(vec![1, 2], matched_leaves);
522 assert_eq!(HashSet::from([0]), matched_roots);
523 }
524
525 #[test]
526 fn test_parent_path_covers_redundant_child_path() {
527 let parquet_schema_desc = build_test_nested_parquet_schema();
528 let nested_paths = vec![
529 vec!["j".to_string(), "b".to_string()],
530 vec!["j".to_string(), "b".to_string(), "c".to_string()],
531 ];
532
533 let read_column = ParquetReadColumn::new(0).with_nested_paths(nested_paths);
534 let projection = ParquetReadColumns::from_deduped(vec![read_column]);
535
536 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
537 &parquet_schema_desc,
538 &projection,
539 &[None; 2],
540 );
541 assert_eq!(vec![1, 2], matched_leaves);
542 assert_eq!(HashSet::from([0]), matched_roots);
543 }
544
545 #[test]
546 fn test_reads_leaf_level_path() {
547 let parquet_schema_desc = build_test_nested_parquet_schema();
548
549 let projection =
550 ParquetReadColumns::from_deduped(vec![ParquetReadColumn::new(0).with_nested_paths(
551 vec![vec!["j".to_string(), "b".to_string(), "c".to_string()]],
552 )]);
553
554 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
555 &parquet_schema_desc,
556 &projection,
557 &[None; 2],
558 );
559 assert_eq!(vec![1], matched_leaves);
560 assert_eq!(HashSet::from([0]), matched_roots);
561 }
562
563 #[test]
564 fn test_build_projection_mask_with_unmatched_roots() {
565 let parquet_schema_desc = build_test_nested_parquet_schema();
566
567 let projection = ParquetReadColumns::from_deduped(vec![
568 ParquetReadColumn::new(0)
569 .with_nested_paths(vec![vec!["j".to_string(), "missing".to_string()]]),
570 ParquetReadColumn::new(1),
571 ]);
572
573 let plan = build_projection_plan(&projection, &parquet_schema_desc, &[None; 2]);
574
575 assert_eq!(vec![false, true], plan.projected_root_presence);
576 assert_eq!(
577 ProjectionMask::leaves(&parquet_schema_desc, vec![3]),
578 plan.mask
579 );
580 }
581
582 #[test]
583 fn test_v2_routes_missing_path_to_remainder() -> Result<(), ParquetError> {
584 let parquet = build_test_v2_schema()?;
585 let projection =
586 ParquetReadColumns::from_deduped(vec![ParquetReadColumn::new(0).with_nested_paths(
587 vec![
588 vec!["j".to_string(), "cold".to_string()],
589 vec!["j".to_string(), "another".to_string()],
590 ],
591 )]);
592
593 let plan =
594 build_projection_plan(&projection, &parquet, &[Some(NestedSelectionPolicy::Json2)]);
595
596 assert_eq!(vec![true], plan.projected_root_presence);
597 assert_eq!(ProjectionMask::leaves(&parquet, [0, 1]), plan.mask);
598 Ok(())
599 }
600
601 #[test]
602 fn test_v2_explicit_path_does_not_read_remainder() -> Result<(), ParquetError> {
603 let parquet = build_test_v2_schema()?;
604 let projection = ParquetReadColumns::from_deduped(vec![
605 ParquetReadColumn::new(0)
606 .with_nested_paths(vec![vec!["j".to_string(), "hot".to_string()]]),
607 ]);
608
609 let plan =
610 build_projection_plan(&projection, &parquet, &[Some(NestedSelectionPolicy::Json2)]);
611
612 assert_eq!(vec![true], plan.projected_root_presence);
613 assert_eq!(ProjectionMask::leaves(&parquet, [3]), plan.mask);
614 Ok(())
615 }
616
617 #[test]
618 fn test_v2_container_path_reads_remainder() -> Result<(), ParquetError> {
619 let parquet = build_test_v2_schema()?;
620 let projection = ParquetReadColumns::from_deduped(vec![
621 ParquetReadColumn::new(0)
622 .with_nested_paths(vec![vec!["j".to_string(), "commit".to_string()]]),
623 ]);
624
625 let plan =
626 build_projection_plan(&projection, &parquet, &[Some(NestedSelectionPolicy::Json2)]);
627
628 assert_eq!(vec![true], plan.projected_root_presence);
629 assert_eq!(ProjectionMask::leaves(&parquet, [0, 1, 2]), plan.mask);
630 Ok(())
631 }
632
633 #[test]
637 fn test_v2_variant_parent_path_reads_parent() -> Result<(), ParquetError> {
638 let parquet = build_test_v2_schema()?;
639 let projection =
640 ParquetReadColumns::from_deduped(vec![ParquetReadColumn::new(0).with_nested_paths(
641 vec![vec![
642 "j".to_string(),
643 "opaque".to_string(),
644 "leaf".to_string(),
645 ]],
646 )]);
647
648 let plan =
649 build_projection_plan(&projection, &parquet, &[Some(NestedSelectionPolicy::Json2)]);
650
651 assert_eq!(vec![true], plan.projected_root_presence);
652 assert_eq!(ProjectionMask::leaves(&parquet, [4]), plan.mask);
653 Ok(())
654 }
655
656 #[test]
657 fn test_merges_mixed_paths() {
658 let parquet_schema_desc = build_test_nested_parquet_schema();
659
660 let projection =
661 ParquetReadColumns::from_deduped(vec![ParquetReadColumn::new(0).with_nested_paths(
662 vec![
663 vec!["j".to_string(), "a".to_string()],
664 vec!["j".to_string(), "b".to_string(), "d".to_string()],
665 ],
666 )]);
667
668 let (matched_leaves, matched_roots) = build_parquet_leaves_indices_with_policies(
669 &parquet_schema_desc,
670 &projection,
671 &[None; 2],
672 );
673 assert_eq!(vec![0, 2], matched_leaves);
674 assert_eq!(HashSet::from([0]), matched_roots);
675 }
676
677 #[test]
678 fn test_merge_nested_paths_extends_paths() {
679 let mut col = ParquetReadColumn::new(0)
680 .with_nested_paths(vec![vec!["j".to_string(), "a".to_string()]]);
681
682 col.merge_nested_paths(vec![vec!["j".to_string(), "b".to_string()]]);
683
684 assert_eq!(
685 &[
686 vec!["j".to_string(), "a".to_string()],
687 vec!["j".to_string(), "b".to_string()],
688 ],
689 col.nested_paths()
690 );
691 }
692
693 #[test]
694 fn test_merge_nested_paths_with_whole_root() {
695 let mut col = ParquetReadColumn::new(0)
696 .with_nested_paths(vec![vec!["j".to_string(), "a".to_string()]]);
697
698 col.merge_nested_paths(vec![]);
699
700 assert!(col.nested_paths().is_empty());
701 }
702
703 fn build_test_nested_parquet_schema() -> SchemaDescriptor {
712 let leaf_a = Arc::new(
713 Type::primitive_type_builder("a", parquet::basic::Type::INT64)
714 .with_repetition(Repetition::REQUIRED)
715 .build()
716 .unwrap(),
717 );
718 let leaf_c = Arc::new(
719 Type::primitive_type_builder("c", parquet::basic::Type::INT64)
720 .with_repetition(Repetition::REQUIRED)
721 .build()
722 .unwrap(),
723 );
724 let leaf_d = Arc::new(
725 Type::primitive_type_builder("d", parquet::basic::Type::INT64)
726 .with_repetition(Repetition::REQUIRED)
727 .build()
728 .unwrap(),
729 );
730 let group_b = Arc::new(
731 Type::group_type_builder("b")
732 .with_repetition(Repetition::REQUIRED)
733 .with_fields(vec![leaf_c, leaf_d])
734 .build()
735 .unwrap(),
736 );
737 let root_j = Arc::new(
738 Type::group_type_builder("j")
739 .with_repetition(Repetition::REQUIRED)
740 .with_fields(vec![leaf_a, group_b])
741 .build()
742 .unwrap(),
743 );
744 let root_k = Arc::new(
745 Type::primitive_type_builder("k", parquet::basic::Type::INT64)
746 .with_repetition(Repetition::REQUIRED)
747 .build()
748 .unwrap(),
749 );
750 let schema = Arc::new(
751 Type::group_type_builder("schema")
752 .with_fields(vec![root_j, root_k])
753 .build()
754 .unwrap(),
755 );
756
757 SchemaDescriptor::new(schema)
758 }
759
760 fn build_test_v2_schema() -> Result<SchemaDescriptor, ParquetError> {
761 let metadata = Arc::new(
762 Type::primitive_type_builder("metadata", parquet::basic::Type::BYTE_ARRAY)
763 .with_repetition(Repetition::REQUIRED)
764 .build()?,
765 );
766 let value = Arc::new(
767 Type::primitive_type_builder("value", parquet::basic::Type::BYTE_ARRAY)
768 .with_repetition(Repetition::REQUIRED)
769 .build()?,
770 );
771 let remainder = Arc::new(
772 Type::group_type_builder(JSON2_REMAINDER_FIELD_NAME)
773 .with_repetition(Repetition::OPTIONAL)
774 .with_logical_type(Some(LogicalType::Variant(VariantType {
775 specification_version: None,
776 })))
777 .with_fields(vec![metadata, value])
778 .build()?,
779 );
780 let operation = Arc::new(
781 Type::primitive_type_builder("operation", parquet::basic::Type::INT64)
782 .with_repetition(Repetition::OPTIONAL)
783 .build()?,
784 );
785 let commit = Arc::new(
786 Type::group_type_builder("commit")
787 .with_repetition(Repetition::OPTIONAL)
788 .with_fields(vec![operation])
789 .build()?,
790 );
791 let hot = Arc::new(
792 Type::primitive_type_builder("hot", parquet::basic::Type::INT64)
793 .with_repetition(Repetition::OPTIONAL)
794 .build()?,
795 );
796 let opaque = Arc::new(
800 Type::primitive_type_builder("opaque", parquet::basic::Type::BYTE_ARRAY)
801 .with_repetition(Repetition::OPTIONAL)
802 .build()?,
803 );
804 let root = Arc::new(
805 Type::group_type_builder("j")
806 .with_repetition(Repetition::OPTIONAL)
807 .with_fields(vec![remainder, commit, hot, opaque])
808 .build()?,
809 );
810 Ok(SchemaDescriptor::new(Arc::new(
811 Type::group_type_builder("schema")
812 .with_fields(vec![root])
813 .build()?,
814 )))
815 }
816
817 fn source_schema(policies: &[Option<NestedSelectionPolicy>]) -> ArrowSchema {
818 ArrowSchema::new(
819 policies
820 .iter()
821 .enumerate()
822 .map(|(index, policy)| {
823 let field = Field::new(
824 format!("root_{index}"),
825 DataType::Struct(Fields::empty()),
826 true,
827 );
828 match policy {
829 None => field,
830 Some(NestedSelectionPolicy::Json2) => {
831 field.with_extension_type(Json2ExtensionType::new(Arc::new(
832 JsonMetadata::new(JsonSettings::default()),
833 )))
834 }
835 }
836 })
837 .collect::<Vec<_>>(),
838 )
839 }
840
841 fn build_projection_plan(
842 cols: &ParquetReadColumns,
843 parquet_schema: &SchemaDescriptor,
844 policies: &[Option<NestedSelectionPolicy>],
845 ) -> ProjectionMaskPlan {
846 super::build_projection_plan(cols, parquet_schema, &source_schema(policies)).unwrap()
847 }
848
849 fn build_parquet_leaves_indices_with_policies(
850 parquet_schema: &SchemaDescriptor,
851 projection: &ParquetReadColumns,
852 policies: &[Option<NestedSelectionPolicy>],
853 ) -> (Vec<usize>, HashSet<usize>) {
854 super::build_parquet_leaves_indices(parquet_schema, projection, &source_schema(policies))
855 .unwrap()
856 }
857}