Skip to content

Commit 5915f4c

Browse files
authored
Support static partition columns for MV (#89)
* Support static partition columns for MV * runtime checks * unit test for dynamic partition columns * lint
1 parent 169eb66 commit 5915f4c

File tree

3 files changed

+167
-38
lines changed

3 files changed

+167
-38
lines changed

src/materialized.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use datafusion::{
4141
catalog::TableProvider,
4242
datasource::listing::{ListingTable, ListingTableUrl},
4343
};
44+
use datafusion_common::DataFusionError;
4445
use datafusion_expr::LogicalPlan;
4546
use itertools::Itertools;
4647

@@ -110,6 +111,14 @@ pub trait Materialized: ListingTableLike {
110111
fn config(&self) -> MaterializedConfig {
111112
MaterializedConfig::default()
112113
}
114+
115+
/// Which partition columns are 'static'.
116+
/// Static partition columns are those that are used in incremental view maintenance.
117+
/// These should be a prefix of the full set of partition columns returned by [`ListingTableLike::partition_columns`].
118+
/// The rest of the partition columns are 'dynamic' and their values will be generated at runtime during incremental refresh.
119+
fn static_partition_columns(&self) -> Vec<String> {
120+
<Self as ListingTableLike>::partition_columns(self)
121+
}
113122
}
114123

115124
/// Register a [`Materialized`] implementation in this registry.
@@ -122,13 +131,38 @@ pub fn register_materialized<T: Materialized>() {
122131
}
123132

124133
/// Attempt to cast the given TableProvider into a [`Materialized`].
125-
/// If the table's type has not been registered using [`register_materialized`], will return `None`.
126-
pub fn cast_to_materialized(table: &dyn TableProvider) -> Option<&dyn Materialized> {
127-
TABLE_TYPE_REGISTRY.cast_to_materialized(table).or_else(|| {
128-
TABLE_TYPE_REGISTRY
129-
.cast_to_decorator(table)
130-
.and_then(|decorator| cast_to_materialized(decorator.base()))
131-
})
134+
/// If the table's type has not been registered using [`register_materialized`], will return `Ok(None)`.
135+
///
136+
/// Does a runtime check on some invariants of `Materialized` and returns an error if they are violated.
137+
/// In particular, checks that the static partition columns are a prefix of all partition columns.
138+
pub fn cast_to_materialized(
139+
table: &dyn TableProvider,
140+
) -> Result<Option<&dyn Materialized>, DataFusionError> {
141+
let materialized = match TABLE_TYPE_REGISTRY
142+
.cast_to_materialized(table)
143+
.map(Ok)
144+
.or_else(|| {
145+
TABLE_TYPE_REGISTRY
146+
.cast_to_decorator(table)
147+
.and_then(|decorator| cast_to_materialized(decorator.base()).transpose())
148+
})
149+
.transpose()?
150+
{
151+
None => return Ok(None),
152+
Some(m) => m,
153+
};
154+
155+
let static_partition_cols = materialized.static_partition_columns();
156+
let all_partition_cols = materialized.partition_columns();
157+
158+
if materialized.partition_columns()[..static_partition_cols.len()] != static_partition_cols[..]
159+
{
160+
return Err(DataFusionError::Plan(format!(
161+
"Materialized view's static partition columns ({static_partition_cols:?}) must be a prefix of all partition columns ({all_partition_cols:?})"
162+
)));
163+
}
164+
165+
Ok(Some(materialized))
132166
}
133167

134168
/// A `TableProvider` that decorates other `TableProvider`s.

0 commit comments

Comments
 (0)