From ab09aea13fc7b696cca0e4d16c03690a6d004846 Mon Sep 17 00:00:00 2001 From: DrakeLin Date: Tue, 2 Dec 2025 22:13:50 +0000 Subject: [PATCH 1/5] fix --- kernel/src/actions/mod.rs | 68 +------ kernel/src/checkpoint/mod.rs | 3 +- kernel/src/table_changes/log_replay.rs | 32 +-- kernel/src/table_changes/log_replay/tests.rs | 24 ++- kernel/src/table_changes/mod.rs | 22 +-- kernel/src/table_configuration.rs | 183 ++---------------- kernel/src/transaction/mod.rs | 4 +- .../cdf-column-mapping-name-mode-3-7.tar.zst | Bin 6349 -> 5794 bytes kernel/tests/data/cdf-table-with-dv.tar.zst | Bin 4112 -> 1700 bytes .../_delta_log/00000000000000000000.json | 2 +- 10 files changed, 65 insertions(+), 273 deletions(-) diff --git a/kernel/src/actions/mod.rs b/kernel/src/actions/mod.rs index 0dc4c26cba..c423bac32f 100644 --- a/kernel/src/actions/mod.rs +++ b/kernel/src/actions/mod.rs @@ -2,8 +2,7 @@ //! specification](https://github.com/delta-io/delta/blob/master/PROTOCOL.md) use std::collections::HashMap; -use std::fmt::{Debug, Display}; -use std::hash::Hash; +use std::fmt::Debug; use std::str::FromStr; use std::sync::{Arc, LazyLock}; @@ -24,7 +23,6 @@ use url::Url; use visitors::{MetadataVisitor, ProtocolVisitor}; use delta_kernel_derive::{internal_api, IntoEngineData, ToSchema}; -use itertools::Itertools; use serde::{Deserialize, Serialize}; const KERNEL_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -568,33 +566,6 @@ impl Protocol { self.has_table_feature(&TableFeature::CatalogManaged) || self.has_table_feature(&TableFeature::CatalogOwnedPreview) } - - pub(crate) fn is_cdf_supported(&self) -> bool { - // TODO: we should probably expand this to ~all supported reader features instead of gating - // on a subset here. missing ones are: - // - variantType - // - typeWidening - // - catalogManaged - static CDF_SUPPORTED_READER_FEATURES: LazyLock> = LazyLock::new(|| { - vec![ - TableFeature::DeletionVectors, - TableFeature::ColumnMapping, - TableFeature::TimestampWithoutTimezone, - TableFeature::V2Checkpoint, - TableFeature::VacuumProtocolCheck, - ] - }); - match self.reader_features() { - // if min_reader_version = 3 and all reader features are subset of supported => OK - Some(reader_features) if self.min_reader_version() == 3 => { - ensure_supported_features(reader_features, &CDF_SUPPORTED_READER_FEATURES).is_ok() - } - // if min_reader_version = 1 or 2 and there are no reader features => OK - None => (1..=2).contains(&self.min_reader_version()), - // any other protocol is not supported - _ => false, - } - } } // TODO: implement Scalar::From> so we can derive IntoEngineData using a macro (issue#1083) @@ -636,43 +607,6 @@ impl IntoEngineData for Protocol { } } -// given `table_features`, check if they are subset of `supported_features` -pub(crate) fn ensure_supported_features( - table_features: &[T], - supported_features: &[T], -) -> DeltaResult<()> -where - T: Display + FromStr + Hash + Eq, - ::Err: Display, -{ - // first check if all features are supported, else we proceed to craft an error message - if table_features - .iter() - .all(|feature| supported_features.contains(feature)) - { - return Ok(()); - } - - // we get the type name (TableFeature) for better error messages - let features_type = std::any::type_name::() - .rsplit("::") - .next() - .unwrap_or("table feature"); - - // NB: we didn't do this above to avoid allocation in the common case - let mut unsupported = table_features - .iter() - .filter(|feature| !supported_features.contains(*feature)); - - Err(Error::Unsupported(format!( - "Found unsupported {}s: \"{}\". Supported {}s: \"{}\"", - features_type, - unsupported.join("\", \""), - features_type, - supported_features.iter().join("\", \""), - ))) -} - #[derive(Debug, Clone, PartialEq, Eq, ToSchema)] #[internal_api] #[cfg_attr(test, derive(Serialize, Default), serde(rename_all = "camelCase"))] diff --git a/kernel/src/checkpoint/mod.rs b/kernel/src/checkpoint/mod.rs index 790749dd07..0cf647034e 100644 --- a/kernel/src/checkpoint/mod.rs +++ b/kernel/src/checkpoint/mod.rs @@ -101,6 +101,7 @@ use crate::log_replay::LogReplayProcessor; use crate::path::ParsedLogPath; use crate::schema::{DataType, SchemaRef, StructField, StructType, ToSchema as _}; use crate::snapshot::SnapshotRef; +use crate::table_features::TableFeature; use crate::table_properties::TableProperties; use crate::{DeltaResult, Engine, EngineData, Error, EvaluationHandlerExtension, FileMeta}; @@ -232,7 +233,7 @@ impl CheckpointWriter { let is_v2_checkpoints_supported = self .snapshot .table_configuration() - .is_v2_checkpoint_write_supported(); + .is_feature_supported(&TableFeature::V2Checkpoint); let actions = self.snapshot.log_segment().read_actions( engine, diff --git a/kernel/src/table_changes/log_replay.rs b/kernel/src/table_changes/log_replay.rs index 3af81b7ca2..195b668b01 100644 --- a/kernel/src/table_changes/log_replay.rs +++ b/kernel/src/table_changes/log_replay.rs @@ -18,9 +18,10 @@ use crate::scan::state::DvInfo; use crate::schema::{ ColumnNamesAndTypes, DataType, SchemaRef, StructField, StructType, ToSchema as _, }; -use crate::table_changes::check_cdf_table_properties; use crate::table_changes::scan_file::{cdf_scan_row_expression, cdf_scan_row_schema}; use crate::table_configuration::TableConfiguration; +use crate::table_features::Operation; +use crate::table_features::TableFeature; use crate::utils::require; use crate::{DeltaResult, Engine, EngineData, Error, PredicateRef, RowVisitor}; @@ -186,15 +187,10 @@ impl LogReplayScanner { visitor.visit_rows_of(actions.as_ref())?; let metadata_opt = Metadata::try_new_from_data(actions.as_ref())?; + let has_metadata_update = metadata_opt.is_some(); let protocol_opt = Protocol::try_new_from_data(actions.as_ref())?; + let has_protocol_update = protocol_opt.is_some(); - // Validate protocol and metadata if present - if let Some(ref protocol) = protocol_opt { - require!( - protocol.is_cdf_supported(), - Error::change_data_feed_unsupported(commit_file.version) - ); - } if let Some(ref metadata) = metadata_opt { let schema = metadata.parse_schema()?; // Currently, schema compatibility is defined as having equal schema types. In the @@ -204,13 +200,10 @@ impl LogReplayScanner { table_schema.as_ref() == &schema, Error::change_data_feed_incompatible_schema(table_schema, &schema) ); - let table_properties = metadata.parse_table_properties(); - check_cdf_table_properties(&table_properties) - .map_err(|_| Error::change_data_feed_unsupported(commit_file.version))?; } // Update table configuration with any new Protocol or Metadata from this commit - if metadata_opt.is_some() || protocol_opt.is_some() { + if has_metadata_update || has_protocol_update { *table_configuration = TableConfiguration::try_new_from( table_configuration, metadata_opt, @@ -218,6 +211,21 @@ impl LogReplayScanner { commit_file.version, )?; } + + // If metadata is updated, check if Change Data Feed is supported + if has_metadata_update { + require!( + table_configuration.is_feature_enabled(&TableFeature::ChangeDataFeed), + Error::change_data_feed_unsupported(commit_file.version) + ); + } + + // If protocol is updated, check if Change Data Feed is supported + if has_protocol_update { + table_configuration + .ensure_operation_supported(Operation::Cdf) + .map_err(|_| Error::change_data_feed_unsupported(commit_file.version))?; + } } // We resolve the remove deletion vector map after visiting the entire commit. if has_cdc_action { diff --git a/kernel/src/table_changes/log_replay/tests.rs b/kernel/src/table_changes/log_replay/tests.rs index b772430986..8cb15f88f5 100644 --- a/kernel/src/table_changes/log_replay/tests.rs +++ b/kernel/src/table_changes/log_replay/tests.rs @@ -41,7 +41,8 @@ fn get_default_table_config(table_root: &url::Url) -> TableConfiguration { ]), ) .unwrap(); - let protocol = Protocol::try_new(1, 1, None::>, None::>).unwrap(); + // CDF requires min_writer_version = 4 + let protocol = Protocol::try_new(1, 4, None::>, None::>).unwrap(); TableConfiguration::try_new(metadata, protocol, table_root.clone(), 0).unwrap() } @@ -167,7 +168,7 @@ async fn metadata_protocol() { 3, 7, Some([TableFeature::DeletionVectors]), - Some([TableFeature::DeletionVectors]), + Some([TableFeature::DeletionVectors, TableFeature::ChangeDataFeed]), ) .unwrap(), ), @@ -230,8 +231,14 @@ async fn unsupported_reader_feature() { Protocol::try_new( 3, 7, - Some([TableFeature::DeletionVectors, TableFeature::TypeWidening]), - Some([TableFeature::DeletionVectors, TableFeature::TypeWidening]), + Some([ + TableFeature::DeletionVectors, + TableFeature::unknown("unsupportedReaderFeature"), + ]), + Some([ + TableFeature::DeletionVectors, + TableFeature::unknown("unsupportedReaderFeature"), + ]), ) .unwrap(), )]) @@ -323,25 +330,24 @@ async fn unsupported_protocol_feature_midstream() { // First commit: Basic protocol with CDF enabled mock_table .commit([ - protocol_action(1, 1, None, None), + protocol_action(2, 6, None, None), metadata_with_cdf(get_schema()), ]) .await; - // Second commit: Protocol update with unsupported feature (TypeWidening) + // Second commit: Protocol update with unsupported feature mock_table .commit([protocol_action( 3, 7, - Some(vec![TableFeature::TypeWidening]), - Some(vec![TableFeature::TypeWidening]), + Some(vec![TableFeature::unknown("unsupportedFeature")]), + Some(vec![TableFeature::unknown("unsupportedFeature")]), )]) .await; assert_midstream_failure(engine, &mock_table); } -// Note: This should be removed once type widening support is added for CDF #[tokio::test] async fn incompatible_schemas_fail() { async fn assert_incompatible_schema(commit_schema: StructType, cdf_schema: StructType) { diff --git a/kernel/src/table_changes/mod.rs b/kernel/src/table_changes/mod.rs index 359ae7a991..6c51e51ec5 100644 --- a/kernel/src/table_changes/mod.rs +++ b/kernel/src/table_changes/mod.rs @@ -42,8 +42,7 @@ use crate::schema::{DataType, Schema, StructField, StructType}; use crate::snapshot::{Snapshot, SnapshotRef}; use crate::table_configuration::TableConfiguration; use crate::table_features::Operation; -use crate::table_properties::TableProperties; -use crate::utils::require; +use crate::table_features::TableFeature; use crate::{DeltaResult, Engine, Error, Version}; mod log_replay; @@ -168,12 +167,12 @@ impl TableChanges { // [`check_cdf_table_properties`] to fail early. This also ensures that column mapping is // disabled. // - // We also check the [`Protocol`] using [`ensure_cdf_read_supported`] to verify that - // we support CDF with those features enabled. - // // Note: We must still check each metadata and protocol action in the CDF range. let check_table_config = |snapshot: &Snapshot| { - if snapshot.table_configuration().is_cdf_read_supported() { + if snapshot + .table_configuration() + .is_feature_enabled(&TableFeature::ChangeDataFeed) + { Ok(()) } else { Err(Error::change_data_feed_unsupported(snapshot.version())) @@ -240,17 +239,6 @@ impl TableChanges { } } -/// Ensures that change data feed is enabled in `table_properties`. See the documentation -/// of [`TableChanges`] for more details. -// TODO: move to TableProperties and normalize with the check in TableConfiguration -fn check_cdf_table_properties(table_properties: &TableProperties) -> DeltaResult<()> { - require!( - table_properties.enable_change_data_feed.unwrap_or(false), - Error::unsupported("Change data feed is not enabled") - ); - Ok(()) -} - #[cfg(test)] mod tests { use super::*; diff --git a/kernel/src/table_configuration.rs b/kernel/src/table_configuration.rs index c81a42edd2..29c9251337 100644 --- a/kernel/src/table_configuration.rs +++ b/kernel/src/table_configuration.rs @@ -41,8 +41,8 @@ pub(crate) enum InCommitTimestampEnablement { /// Holds all the configuration for a table at a specific version. This includes the supported /// reader and writer features, table properties, schema, version, and table root. This can be used /// to check whether a table supports a feature or has it enabled. For example, deletion vector -/// support can be checked with [`TableConfiguration::is_deletion_vector_supported`] and deletion -/// vector write enablement can be checked with [`TableConfiguration::is_deletion_vector_enabled`]. +/// support can be checked with [`TableConfiguration::is_feature_supported`] and deletion +/// vector write enablement can be checked with [`TableConfiguration::is_feature_enabled`]. /// /// [`TableConfiguration`] performs checks upon construction with `TableConfiguration::try_new` /// to validate that Metadata and Protocol are correctly formatted and mutually compatible. @@ -143,6 +143,7 @@ impl TableConfiguration { } /// The [`Protocol`] of this table at this version. + #[allow(unused)] #[internal_api] pub(crate) fn protocol(&self) -> &Protocol { &self.protocol @@ -372,110 +373,6 @@ impl TableConfiguration { Ok(()) } - /// Returns `true` if kernel supports reading Change Data Feed on this table. - /// See the documentation of [`TableChanges`] for more details. - /// - /// [`TableChanges`]: crate::table_changes::TableChanges - #[internal_api] - pub(crate) fn is_cdf_read_supported(&self) -> bool { - let protocol_supported = self.protocol.is_cdf_supported(); - let cdf_enabled = self - .table_properties - .enable_change_data_feed - .unwrap_or(false); - protocol_supported && cdf_enabled - } - - /// Returns `true` if deletion vectors is supported on this table. To support deletion vectors, - /// a table must support reader version 3, writer version 7, and the deletionVectors feature in - /// both the protocol's readerFeatures and writerFeatures. - /// - /// See: - #[internal_api] - #[allow(unused)] // needed to compile w/o default features - pub(crate) fn is_deletion_vector_supported(&self) -> bool { - self.protocol() - .has_table_feature(&TableFeature::DeletionVectors) - && self.protocol.min_reader_version() == 3 - && self.protocol.min_writer_version() == 7 - } - - /// Returns `true` if writing deletion vectors is enabled for this table. This is the case - /// when the deletion vectors is supported on this table and the `delta.enableDeletionVectors` - /// table property is set to `true`. - /// - /// See: - #[internal_api] - #[allow(unused)] // needed to compile w/o default features - pub(crate) fn is_deletion_vector_enabled(&self) -> bool { - self.is_deletion_vector_supported() - && self - .table_properties - .enable_deletion_vectors - .unwrap_or(false) - } - - /// Returns `true` if the table supports the appendOnly table feature. To support this feature: - /// - The table must have a writer version between 2 and 7 (inclusive) - /// - If the table is on writer version 7, it must have the [`TableFeature::AppendOnly`] - /// writer feature. - pub(crate) fn is_append_only_supported(&self) -> bool { - let protocol = &self.protocol; - match protocol.min_writer_version() { - 7 if protocol.has_table_feature(&TableFeature::AppendOnly) => true, - version => (2..=6).contains(&version), - } - } - - #[allow(unused)] - pub(crate) fn is_append_only_enabled(&self) -> bool { - self.is_append_only_supported() && self.table_properties.append_only.unwrap_or(false) - } - - /// Returns `true` if the table supports the column invariant table feature. - #[allow(unused)] - pub(crate) fn is_invariants_supported(&self) -> bool { - let protocol = &self.protocol; - match protocol.min_writer_version() { - 7 if protocol.has_table_feature(&TableFeature::Invariants) => true, - version => (2..=6).contains(&version), - } - } - - /// Returns `true` if V2 checkpoint is supported on this table. To support V2 checkpoint, - /// a table must support reader version 3, writer version 7, and the v2Checkpoint feature in - /// both the protocol's readerFeatures and writerFeatures. - /// - /// See: - pub(crate) fn is_v2_checkpoint_write_supported(&self) -> bool { - self.protocol() - .has_table_feature(&TableFeature::V2Checkpoint) - } - - /// Returns `true` if the table supports writing in-commit timestamps. - /// - /// To support this feature the table must: - /// - Have a min_writer_version of 7 - /// - Have the [`TableFeature::InCommitTimestamp`] writer feature. - #[allow(unused)] - pub(crate) fn is_in_commit_timestamps_supported(&self) -> bool { - self.protocol().min_writer_version() == 7 - && self - .protocol() - .has_table_feature(&TableFeature::InCommitTimestamp) - } - - /// Returns `true` if in-commit timestamps is supported and it is enabled. In-commit timestamps - /// is enabled when the `delta.enableInCommitTimestamps` configuration is set to `true`. - #[allow(unused)] - pub(crate) fn is_in_commit_timestamps_enabled(&self) -> bool { - self.is_in_commit_timestamps_supported() - && self - .table_properties() - .enable_in_commit_timestamps - .unwrap_or(false) - } - /// Returns information about in-commit timestamp enablement state. /// /// Returns an error if only one of the enablement properties is present, as this indicates @@ -484,7 +381,7 @@ impl TableConfiguration { pub(crate) fn in_commit_timestamp_enablement( &self, ) -> DeltaResult { - if !self.is_in_commit_timestamps_enabled() { + if !self.is_feature_enabled(&TableFeature::InCommitTimestamp) { return Ok(InCommitTimestampEnablement::NotEnabled); } @@ -511,42 +408,6 @@ impl TableConfiguration { } } - /// Returns `true` if the table supports writing domain metadata. - /// - /// To support this feature the table must: - /// - Have a min_writer_version of 7. - /// - Have the [`TableFeature::DomainMetadata`] writer feature. - #[allow(unused)] - pub(crate) fn is_domain_metadata_supported(&self) -> bool { - self.protocol().min_writer_version() == 7 - && self - .protocol() - .has_table_feature(&TableFeature::DomainMetadata) - } - - /// Returns `true` if the table supports writing row tracking metadata. - /// - /// To support this feature the table must: - /// - Have a min_writer_version of 7. - /// - Have the [`TableFeature::RowTracking`] writer feature. - pub(crate) fn is_row_tracking_supported(&self) -> bool { - self.protocol().min_writer_version() == 7 - && self - .protocol() - .has_table_feature(&TableFeature::RowTracking) - } - - /// Returns `true` if row tracking is enabled for this table. - /// - /// In order to enable row tracking the table must: - /// - Support row tracking (see [`Self::is_row_tracking_supported`]). - /// - Have the `delta.enableRowTracking` table property set to `true`. - #[allow(unused)] - pub(crate) fn is_row_tracking_enabled(&self) -> bool { - self.is_row_tracking_supported() - && self.table_properties().enable_row_tracking.unwrap_or(false) - } - /// Returns `true` if row tracking is suspended for this table. /// /// Row tracking is suspended when the `delta.rowTrackingSuspended` table property is set to `true`. @@ -568,7 +429,7 @@ impl TableConfiguration { /// Note: We ignore [`is_row_tracking_enabled`] at this point because Kernel does not /// preserve row IDs and row commit versions yet. pub(crate) fn should_write_row_tracking(&self) -> bool { - self.is_row_tracking_supported() && !self.is_row_tracking_suspended() + self.is_feature_supported(&TableFeature::RowTracking) && !self.is_row_tracking_suspended() } /// Returns true if the protocol uses legacy reader version (< 3) @@ -781,8 +642,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_deletion_vector_supported()); - assert!(!table_config.is_deletion_vector_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::DeletionVectors)); + assert!(!table_config.is_feature_enabled(&TableFeature::DeletionVectors)); } #[test] @@ -812,8 +673,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_deletion_vector_supported()); - assert!(table_config.is_deletion_vector_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::DeletionVectors)); + assert!(table_config.is_feature_enabled(&TableFeature::DeletionVectors)); } #[test] @@ -915,8 +776,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_in_commit_timestamps_supported()); - assert!(table_config.is_in_commit_timestamps_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::InCommitTimestamp)); + assert!(table_config.is_feature_enabled(&TableFeature::InCommitTimestamp)); // When ICT is enabled from table creation (version 0), it's perfectly normal // for enablement properties to be missing let info = table_config.in_commit_timestamp_enablement().unwrap(); @@ -959,8 +820,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_in_commit_timestamps_supported()); - assert!(table_config.is_in_commit_timestamps_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::InCommitTimestamp)); + assert!(table_config.is_feature_enabled(&TableFeature::InCommitTimestamp)); let info = table_config.in_commit_timestamp_enablement().unwrap(); assert_eq!( info, @@ -1000,8 +861,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_in_commit_timestamps_supported()); - assert!(table_config.is_in_commit_timestamps_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::InCommitTimestamp)); + assert!(table_config.is_feature_enabled(&TableFeature::InCommitTimestamp)); assert!(matches!( table_config.in_commit_timestamp_enablement(), Err(Error::Generic(msg)) if msg.contains("In-commit timestamp enabled, but enablement timestamp is missing") @@ -1020,8 +881,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(table_config.is_in_commit_timestamps_supported()); - assert!(!table_config.is_in_commit_timestamps_enabled()); + assert!(table_config.is_feature_supported(&TableFeature::InCommitTimestamp)); + assert!(!table_config.is_feature_enabled(&TableFeature::InCommitTimestamp)); let info = table_config.in_commit_timestamp_enablement().unwrap(); assert_eq!(info, InCommitTimestampEnablement::NotEnabled); } @@ -1057,8 +918,8 @@ mod test { .unwrap(); let table_root = Url::try_from("file:///").unwrap(); let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap(); - assert!(!table_config.is_deletion_vector_supported()); - assert!(!table_config.is_deletion_vector_enabled()); + assert!(!table_config.is_feature_supported(&TableFeature::DeletionVectors)); + assert!(!table_config.is_feature_enabled(&TableFeature::DeletionVectors)); } #[test] @@ -1403,12 +1264,6 @@ mod test { assert!(!config.is_feature_info_enabled(&feature, &custom_feature_info)); } - #[test] - fn test_v2_checkpoint_supported() { - let config = create_mock_table_config(&[], &[TableFeature::V2Checkpoint]); - assert!(config.is_v2_checkpoint_write_supported()); - } - #[test] fn test_ensure_operation_supported_reads() { let config = create_mock_table_config(&[], &[]); diff --git a/kernel/src/transaction/mod.rs b/kernel/src/transaction/mod.rs index 350a196207..f2d5586fc3 100644 --- a/kernel/src/transaction/mod.rs +++ b/kernel/src/transaction/mod.rs @@ -26,7 +26,7 @@ use crate::scan::log_replay::{ use crate::scan::scan_row_schema; use crate::schema::{ArrayType, MapType, SchemaRef, StructField, StructType, StructTypeBuilder}; use crate::snapshot::SnapshotRef; -use crate::table_features::Operation; +use crate::table_features::{Operation, TableFeature}; use crate::utils::{current_time_ms, require}; use crate::{ DataType, DeltaResult, Engine, EngineData, Expression, ExpressionRef, IntoEngineData, @@ -462,7 +462,7 @@ impl Transaction { && !self .read_snapshot .table_configuration() - .is_domain_metadata_supported() + .is_feature_supported(&TableFeature::DomainMetadata) { return Err(Error::unsupported("Domain metadata operations require writer version 7 and the 'domainMetadata' writer feature")); } diff --git a/kernel/tests/data/cdf-column-mapping-name-mode-3-7.tar.zst b/kernel/tests/data/cdf-column-mapping-name-mode-3-7.tar.zst index bb7a606d37455903f1546fd01205fe14ac3e2a96..ce7bd9968a2ea1b73e69cab3abf0b4d1dc804b32 100644 GIT binary patch literal 5794 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 literal 6349 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 PNXlS8@Nh7m#g`TX4RY~^ diff --git a/kernel/tests/data/cdf-table-with-dv.tar.zst b/kernel/tests/data/cdf-table-with-dv.tar.zst index d3aa6574de324461f82d0daa6e143d193d51079d..480e784882b6e93ac965f5cc9763b6d5cc72aa08 100644 GIT binary patch literal 1700 zcmV;V23z?kwJ-eySiLj=N?RlnLlAMR00000002e+AdUb4Py_%#WDF^6ag5^ z1B>Jq>4NyA8$T!X6^#cpOqU7^Y2%{FxL-0B$=wSCz+~Lr17I>11sQiQ;O-mlPQcv< zxVr#%58&OCtMJUQm2Eax#%(ArqnFaS zicuJcQ>jerD)ngnXmNKK^Ym{YgE#!r#Qx}gID>xr-I02aZy$?N_Lm#x?(5x+!77EQ zs}IE}0pqj6s!ISS6!WMt3I^kjsT|KpC#Aa~{An;g;tz*HkIyJ_pm4jaG3c=XgF~?d zgLzjKKIyLLRv|5BFk8l*qrxKFR@&b(_}et8{cZHL*kKZo41X)%{C-hPNk$MYHK(D9IjfEej~X@3me{Zn>T`*=kje;Sqc zM@)V;81u^F5G>+pQ?pn97^d%(<-$u0`DF%m_0xJ+dtV? z^rd}_B7#_dc}o0oNA7Dg?tW^7VQF$=4fc9GMv zsK=NoXc+n6RPbP7gQ8UNnS>uGq(&`TD<$>j&`svyeX;I-8a)oh@a+BKlx9{aI?caSt?#3XA_b|qA_XX*GO7RnkA5H9! zSd;r=4EiT+XDuSk;7^zR5E^?IlY|-k(*7rQ;uf{&OHHHHnm#L?_0s61*u|L*8qAr| ztX3?u>Xm`$^&>of7Zj4>$36+=J$Fco7ru`SIVvvr+ccW?1Ax4!VIf0^kO+v#1b_fx z43Gi=8G)HG0}`MhVUWZi3?N`Y02zT200M{*06+jB0we$eBp^y5S{LCHDh(fu)^c{v z$H0}z*(I$8ZNPe9F{($=wDA&~2OGZMLQO+8sXHZX{HgZDx=y#fa^;=s0yX zPC^I(XD!SJSVz>PQ78Z^ifpGP$gL&lA2f;<2CoQX1*Wk9+nNE%^7S`>QQ&NO;Z-84 zBNG1e;arj4WBsVJv zDdA)X0vj~;JN6vlh!7hmwR`|W8{Gi5>WmuTouvI4A1lg%Xc&M2#-U(^K&H)q>R|!M zV9N?@o$buE1G4!MasYS;0n!5vH@z5gxS+np4Ns8T-ZX=n4AFXd$zF`~h$%hPG|9t< uir3q<1}<=(pYxLjTrhW2m9+$^n<5_Y;5Jh|=+OWgB(_=9GaL=Wsn%O4wjL({ literal 4112 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 O3XnknU{>>wo^yS@)6{1G diff --git a/kernel/tests/data/table-with-cdf/_delta_log/00000000000000000000.json b/kernel/tests/data/table-with-cdf/_delta_log/00000000000000000000.json index 09bf8dbb27..0728498906 100644 --- a/kernel/tests/data/table-with-cdf/_delta_log/00000000000000000000.json +++ b/kernel/tests/data/table-with-cdf/_delta_log/00000000000000000000.json @@ -1,4 +1,4 @@ {"commitInfo":{"timestamp":1704392842074,"operation":"Manual Update","operationParameters":{},"isolationLevel":"Serializable","isBlindAppend":true,"operationMetrics":{},"engineInfo":"Apache-Spark/3.5.0 Delta-Lake/3.1.0-SNAPSHOT","txnId":"95ec924a-6859-4433-8008-6d6b4a0e3ba5"}} -{"protocol":{"minReaderVersion":3,"minWriterVersion":7, "readerFeatures":[], "writerFeatures":[]}} +{"protocol":{"minReaderVersion":1,"minWriterVersion":4}} {"metaData":{"id":"testId","format":{"provider":"parquet","options":{}},"schemaString":"{\"type\":\"struct\",\"fields\":[{\"name\":\"part\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}},{\"name\":\"id\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}}]}","partitionColumns":[],"configuration":{"delta.enableChangeDataFeed": "true"}}} {"add":{"path":"fake/path/1","partitionValues":{},"size":1,"modificationTime":1,"dataChange":true}} From d282c84436d864bf8c4514be69f3c58570df1190 Mon Sep 17 00:00:00 2001 From: DrakeLin Date: Tue, 2 Dec 2025 22:48:26 +0000 Subject: [PATCH 2/5] fix --- kernel/src/actions/mod.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/kernel/src/actions/mod.rs b/kernel/src/actions/mod.rs index c423bac32f..914f539b3b 100644 --- a/kernel/src/actions/mod.rs +++ b/kernel/src/actions/mod.rs @@ -1487,21 +1487,6 @@ mod tests { assert!(protocol.validate_table_features().is_err()); } - #[test] - fn test_ensure_supported_features() { - let supported_features = [TableFeature::ColumnMapping, TableFeature::DeletionVectors]; - let table_features = vec![TableFeature::ColumnMapping]; - ensure_supported_features(&table_features, &supported_features).unwrap(); - // test unknown features - let table_features = vec![TableFeature::ColumnMapping, TableFeature::unknown("idk")]; - let error = ensure_supported_features(&table_features, &supported_features).unwrap_err(); - match error { - Error::Unsupported(e) if e == - "Found unsupported TableFeatures: \"idk\". Supported TableFeatures: \"columnMapping\", \"deletionVectors\"" - => {}, - _ => panic!("Expected unsupported error, got: {error}"), - } - } #[test] fn test_parse_table_feature_never_fails() { // parse a non-str From 93ed4a4aee0a7b3da99e77d83fb8f6038d5c2509 Mon Sep 17 00:00:00 2001 From: DrakeLin Date: Tue, 2 Dec 2025 23:04:18 +0000 Subject: [PATCH 3/5] fix --- ffi/src/table_changes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffi/src/table_changes.rs b/ffi/src/table_changes.rs index a7556d3a2a..9b84e3c00f 100644 --- a/ffi/src/table_changes.rs +++ b/ffi/src/table_changes.rs @@ -372,7 +372,7 @@ mod tests { }} {"protocol": { "minReaderVersion": 1, - "minWriterVersion": 2 + "minWriterVersion": 4 }} {"metaData": { "id": "5fba94ed-9794-4965-ba6e-6ee3c0d22af9", From 6bee3dbd8f953e3cf5d3f5f54855d6f752d9bdfa Mon Sep 17 00:00:00 2001 From: DrakeLin Date: Wed, 3 Dec 2025 00:14:50 +0000 Subject: [PATCH 4/5] fix --- kernel/src/table_configuration.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/src/table_configuration.rs b/kernel/src/table_configuration.rs index 29c9251337..b23d6dbe37 100644 --- a/kernel/src/table_configuration.rs +++ b/kernel/src/table_configuration.rs @@ -504,6 +504,7 @@ impl TableConfiguration { /// Generic method to check if a feature is supported in the protocol. /// This does NOT check if the feature is enabled via table properties. + #[internal_api] #[allow(dead_code)] pub(crate) fn is_feature_supported(&self, feature: &TableFeature) -> bool { let Some(info) = feature.info() else { @@ -517,6 +518,7 @@ impl TableConfiguration { /// A feature is enabled if: /// 1. It is supported in the protocol /// 2. The enablement check passes + #[internal_api] #[allow(dead_code)] pub(crate) fn is_feature_enabled(&self, feature: &TableFeature) -> bool { let Some(info) = feature.info() else { From 42cac7009bce3334621ed64d1b9b2918a2d317f7 Mon Sep 17 00:00:00 2001 From: DrakeLin Date: Wed, 3 Dec 2025 00:15:05 +0000 Subject: [PATCH 5/5] fix --- kernel/src/table_configuration.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/src/table_configuration.rs b/kernel/src/table_configuration.rs index b23d6dbe37..aab505225a 100644 --- a/kernel/src/table_configuration.rs +++ b/kernel/src/table_configuration.rs @@ -505,7 +505,6 @@ impl TableConfiguration { /// Generic method to check if a feature is supported in the protocol. /// This does NOT check if the feature is enabled via table properties. #[internal_api] - #[allow(dead_code)] pub(crate) fn is_feature_supported(&self, feature: &TableFeature) -> bool { let Some(info) = feature.info() else { return false; @@ -519,7 +518,6 @@ impl TableConfiguration { /// 1. It is supported in the protocol /// 2. The enablement check passes #[internal_api] - #[allow(dead_code)] pub(crate) fn is_feature_enabled(&self, feature: &TableFeature) -> bool { let Some(info) = feature.info() else { return false;