Skip to main content

query_planning/source/
footer_facts.rs

1//! Parquet footers supplied to planning by whoever read them.
2//!
3//! Planning consumes footers; it does not open the files they came from. The
4//! caller (source preparation, which already loads and caches these footers)
5//! passes what it has. A footer is therefore read once per source, and each
6//! decision that needs one reuses that read.
7
8use parquet::file::metadata::ParquetMetaData;
9
10/// Footers the caller already loaded, one slot per file of a
11/// [`LocalParquetSource`](super::LocalParquetSource), in `files` order.
12///
13/// A `None` slot means the caller has no footer for that file, and every
14/// decision that needs one skips without guessing. That keeps the
15/// conservative outcome the previous in-planning read produced for a source it
16/// could not open: the optimization does not apply, and the plan stays correct.
17/// Whether an unreadable file is an error at all is source preparation's call,
18/// not a pruning decision's.
19#[derive(Debug, Clone, Copy, Default)]
20pub struct SourceFooterFacts<'a> {
21    per_file: &'a [Option<&'a ParquetMetaData>],
22}
23
24impl<'a> SourceFooterFacts<'a> {
25    /// Supplies one footer slot per source file, in `files` order.
26    pub const fn new(per_file: &'a [Option<&'a ParquetMetaData>]) -> Self {
27        Self { per_file }
28    }
29
30    /// Supplies no footers, so every footer-dependent decision is skipped.
31    pub const fn none() -> Self {
32        Self { per_file: &[] }
33    }
34
35    /// The footer for `file_index`, when the caller supplied one.
36    pub(crate) fn footer(&self, file_index: usize) -> Option<&'a ParquetMetaData> {
37        self.per_file.get(file_index).copied().flatten()
38    }
39}