From 94d658bb15ca36eb15593834f251f0f9d9a0a194 Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Sat, 2 May 2026 17:53:39 +0530 Subject: [PATCH 1/6] From -> Try_From --- datafusion/common/src/config.rs | 195 +++++++++++++++--- .../datasource-parquet/src/file_format.rs | 4 +- datafusion/datasource-parquet/src/source.rs | 3 +- 3 files changed, 174 insertions(+), 28 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index 2889259dd4820..211aeba690db7 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -2862,10 +2862,15 @@ impl ConfigField for ConfigFileEncryptionProperties { } #[cfg(feature = "parquet_encryption")] -impl From for FileEncryptionProperties { - fn from(val: ConfigFileEncryptionProperties) -> Self { +impl TryFrom for FileEncryptionProperties { + type Error = DataFusionError; + + fn try_from(val: ConfigFileEncryptionProperties) -> Result { let mut fep = FileEncryptionProperties::builder( - hex::decode(val.footer_key_as_hex).unwrap(), + hex::decode(val.footer_key_as_hex) + .map_err(|e| { + DataFusionError::Configuration(format!("Unable to decode hex footer key from ConfigFileEncryptionProperties: {e}")) + })?, ) .with_plaintext_footer(!val.encrypt_footer) .with_aad_prefix_storage(val.store_aad_prefix); @@ -2873,17 +2878,26 @@ impl From for FileEncryptionProperties { if !val.footer_key_metadata_as_hex.is_empty() { fep = fep.with_footer_key_metadata( hex::decode(&val.footer_key_metadata_as_hex) - .expect("Invalid footer key metadata"), + .map_err(|e| { + DataFusionError::Configuration(format!("Unable to decode hex footer key metadata from ConfigFileEncryptionProperties: {e}")) + })?, ); } for (column_name, encryption_props) in val.column_encryption_properties.iter() { let encryption_key = hex::decode(&encryption_props.column_key_as_hex) - .expect("Invalid column encryption key"); + .map_err(|e| { + DataFusionError::Configuration(format!("Unable to decode hex encryption key metadata for column {column_name}: {e}")) + })?; let key_metadata = encryption_props .column_metadata_as_hex .as_ref() - .map(|x| hex::decode(x).expect("Invalid column metadata")); + .map(|x| hex::decode(x)) + .transpose() + .map_err(|e| { + DataFusionError::Configuration(format!("Unable to decode hex column metadata for column {column_name}: {e}")) + })?; + match key_metadata { Some(key_metadata) => { fep = fep.with_column_key_and_metadata( @@ -2899,11 +2913,18 @@ impl From for FileEncryptionProperties { } if !val.aad_prefix_as_hex.is_empty() { - let aad_prefix: Vec = - hex::decode(&val.aad_prefix_as_hex).expect("Invalid AAD prefix"); + let aad_prefix: Vec = hex::decode(&val.aad_prefix_as_hex).map_err(|e| { + DataFusionError::Configuration(format!( + "Unable to decode hex AAD prefix from ConfigFileEncryptionProperties: {e}" + )) + })?; fep = fep.with_aad_prefix(aad_prefix); } - Arc::unwrap_or_clone(fep.build().unwrap()) + Ok(Arc::unwrap_or_clone(fep.build().map_err(|e| { + DataFusionError::Configuration(format!( + "Could not build FileEncryptionProperties: {e}" + )) + })?)) } } @@ -3019,36 +3040,54 @@ impl ConfigField for ConfigFileDecryptionProperties { } #[cfg(feature = "parquet_encryption")] -impl From for FileDecryptionProperties { - fn from(val: ConfigFileDecryptionProperties) -> Self { +impl TryFrom for FileDecryptionProperties { + type Error = DataFusionError; + + fn try_from(val: ConfigFileDecryptionProperties) -> Result { let mut column_names: Vec<&str> = Vec::new(); let mut column_keys: Vec> = Vec::new(); for (col_name, decryption_properties) in val.column_decryption_properties.iter() { + let column_key_as_hex = hex::decode(&decryption_properties.column_key_as_hex).map_err(|e| { + DataFusionError::Configuration(format! + ("Could not decode hex column key from ConfigFileDecryptionProperties for column name {col_name}: {e}.")) + })?; column_names.push(col_name.as_str()); - column_keys.push( - hex::decode(&decryption_properties.column_key_as_hex) - .expect("Invalid column decryption key"), - ); + column_keys.push(column_key_as_hex); } - let mut fep = FileDecryptionProperties::builder( - hex::decode(val.footer_key_as_hex).expect("Invalid footer key"), - ) - .with_column_keys(column_names, column_keys) - .unwrap(); + let footer_key = hex::decode(val.footer_key_as_hex).map_err(|e| { + DataFusionError::Configuration(format!( + "Could not decode hex footer key from ConfigFileDecryptionProperties: {e}." + )) + })?; + + let mut fep = FileDecryptionProperties::builder(footer_key) + .with_column_keys(column_names, column_keys) + .map_err(|e| { + DataFusionError::Configuration(format!( + "Could not set column keys on FileDecryptionPropertiesBuilder: {e}." + )) + })?; if !val.footer_signature_verification { fep = fep.disable_footer_signature_verification(); } if !val.aad_prefix_as_hex.is_empty() { - let aad_prefix = - hex::decode(&val.aad_prefix_as_hex).expect("Invalid AAD prefix"); + let aad_prefix = hex::decode(&val.aad_prefix_as_hex).map_err(|e| { + DataFusionError::Configuration(format!( + "Could not decode hex AAD prefix from ConfigFileDecryptionProperties: {e}." + )) + })?; fep = fep.with_aad_prefix(aad_prefix); } - Arc::unwrap_or_clone(fep.build().unwrap()) + Ok(Arc::unwrap_or_clone(fep.build().map_err(|e| { + DataFusionError::Configuration(format!( + "Could not build FileDecryptionProperties: {e}." + )) + })?)) } } @@ -3586,13 +3625,13 @@ mod tests { let config_encrypt = ConfigFileEncryptionProperties::from(&file_encryption_properties); let encryption_properties_built = - Arc::new(FileEncryptionProperties::from(config_encrypt.clone())); + Arc::new(FileEncryptionProperties::try_from(config_encrypt.clone()).unwrap()); assert_eq!(file_encryption_properties, encryption_properties_built); let config_decrypt = ConfigFileDecryptionProperties::try_from(&decryption_properties).unwrap(); let decryption_properties_built = - Arc::new(FileDecryptionProperties::from(config_decrypt.clone())); + Arc::new(FileDecryptionProperties::try_from(config_decrypt.clone()).unwrap()); assert_eq!(decryption_properties, decryption_properties_built); /////////////////////////////////////////////////////////////////////////////////// @@ -3678,6 +3717,112 @@ mod tests { ); } + #[cfg(feature = "parquet_encryption")] + #[test] + fn parquet_encryption_invalid_hex_errors_encryption() { + use crate::config::ColumnEncryptionProperties; + use crate::config::ConfigFileEncryptionProperties; + use parquet::encryption::encrypt::FileEncryptionProperties; + + // Encryption: invalid footer key hex + let mut enc = ConfigFileEncryptionProperties::default(); + enc.footer_key_as_hex = "not_hex".to_string(); + let err = FileEncryptionProperties::try_from(enc) + .unwrap_err() + .to_string(); + assert!(err.contains("Unable to decode hex footer key")); + + // Encryption: invalid footer key metadata hex + let mut enc = ConfigFileEncryptionProperties::default(); + enc.footer_key_as_hex = hex::encode(b"0123456789012345"); + enc.footer_key_metadata_as_hex = "zz".to_string(); + let err = FileEncryptionProperties::try_from(enc) + .unwrap_err() + .to_string(); + assert!(err.contains("Unable to decode hex footer key metadata")); + + // Encryption: invalid column key hex + let mut enc = ConfigFileEncryptionProperties::default(); + enc.footer_key_as_hex = hex::encode(b"0123456789012345"); + enc.column_encryption_properties.insert( + "col1".to_string(), + ColumnEncryptionProperties { + column_key_as_hex: "bad".to_string(), + column_metadata_as_hex: None, + }, + ); + let err = FileEncryptionProperties::try_from(enc) + .unwrap_err() + .to_string(); + assert!( + err.contains("Unable to decode hex encryption key metadata for column col1") + ); + + // Encryption: invalid column metadata hex + let mut enc = ConfigFileEncryptionProperties::default(); + enc.footer_key_as_hex = hex::encode(b"0123456789012345"); + enc.column_encryption_properties.insert( + "col1".to_string(), + ColumnEncryptionProperties { + column_key_as_hex: hex::encode(b"1234567890123450"), + column_metadata_as_hex: Some("zz".to_string()), + }, + ); + let err = FileEncryptionProperties::try_from(enc) + .unwrap_err() + .to_string(); + assert!(err.contains("Unable to decode hex column metadata for column col1")); + + // Encryption: invalid AAD prefix hex + let mut enc = ConfigFileEncryptionProperties::default(); + enc.footer_key_as_hex = hex::encode(b"0123456789012345"); + enc.aad_prefix_as_hex = "zz".to_string(); + let err = FileEncryptionProperties::try_from(enc) + .unwrap_err() + .to_string(); + assert!(err.contains("Unable to decode hex AAD prefix")); + } + + #[cfg(feature = "parquet_encryption")] + #[test] + fn parquet_encryption_invalid_hex_errors_decryption() { + use crate::config::ColumnDecryptionProperties; + use crate::config::ConfigFileDecryptionProperties; + use parquet::encryption::decrypt::FileDecryptionProperties; + + // Decryption: invalid column key hex + let mut dec = ConfigFileDecryptionProperties::default(); + dec.footer_key_as_hex = hex::encode(b"0123456789012345"); + dec.column_decryption_properties.insert( + "col1".to_string(), + ColumnDecryptionProperties { + column_key_as_hex: "bad".to_string(), + }, + ); + let err = FileDecryptionProperties::try_from(dec) + .unwrap_err() + .to_string(); + assert!(err.contains("Could not decode hex column key")); + assert!(err.contains("col1")); + + // Decryption: invalid footer key hex + let mut dec = ConfigFileDecryptionProperties::default(); + dec.footer_key_as_hex = "bad".to_string(); + let err = FileDecryptionProperties::try_from(dec) + .unwrap_err() + .to_string(); + assert!(err.contains("Could not decode hex footer key")); + + // Decryption: invalid AAD prefix hex + let mut dec = ConfigFileDecryptionProperties::default(); + dec.footer_key_as_hex = hex::encode(b"0123456789012345"); + dec.aad_prefix_as_hex = "zz".to_string(); + let err = FileDecryptionProperties::try_from(dec) + .unwrap_err() + .to_string(); + assert!(err.contains("Could not decode hex AAD prefix")); + } + #[cfg(feature = "parquet_encryption")] #[test] fn parquet_encryption_factory_config() { diff --git a/datafusion/datasource-parquet/src/file_format.rs b/datafusion/datasource-parquet/src/file_format.rs index d97077d609efd..5676ee940c7b8 100644 --- a/datafusion/datasource-parquet/src/file_format.rs +++ b/datafusion/datasource-parquet/src/file_format.rs @@ -308,7 +308,7 @@ async fn get_file_decryption_properties( file_path: &Path, ) -> Result>> { Ok(match &options.crypto.file_decryption { - Some(cfd) => Some(Arc::new(FileDecryptionProperties::from(cfd.clone()))), + Some(cfd) => Some(Arc::new(FileDecryptionProperties::try_from(cfd.clone())?)), None => match &options.crypto.factory_id { Some(factory_id) => { let factory = @@ -1284,7 +1284,7 @@ async fn set_writer_encryption_properties( if let Some(file_encryption_properties) = parquet_opts.crypto.file_encryption { // Encryption properties have been specified directly return Ok(builder.with_file_encryption_properties(Arc::new( - FileEncryptionProperties::from(file_encryption_properties), + FileEncryptionProperties::try_from(file_encryption_properties)?, ))); } else if let Some(encryption_factory_id) = &parquet_opts.crypto.factory_id.as_ref() { // Encryption properties will be generated by an encryption factory diff --git a/datafusion/datasource-parquet/src/source.rs b/datafusion/datasource-parquet/src/source.rs index a014c8b2726e7..787f882908e9b 100644 --- a/datafusion/datasource-parquet/src/source.rs +++ b/datafusion/datasource-parquet/src/source.rs @@ -543,7 +543,8 @@ impl FileSource for ParquetSource { .crypto .file_decryption .clone() - .map(FileDecryptionProperties::from) + .map(FileDecryptionProperties::try_from) + .transpose()? .map(Arc::new); let coerce_int96 = self From 854d6b8baa8d224a10b6b47d5adb5779bc0fb4f0 Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Sat, 2 May 2026 18:18:39 +0530 Subject: [PATCH 2/6] lint fixes --- datafusion/common/src/config.rs | 48 +++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index 211aeba690db7..9889e7505a5de 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -2892,7 +2892,7 @@ impl TryFrom for FileEncryptionProperties { let key_metadata = encryption_props .column_metadata_as_hex .as_ref() - .map(|x| hex::decode(x)) + .map(hex::decode) .transpose() .map_err(|e| { DataFusionError::Configuration(format!("Unable to decode hex column metadata for column {column_name}: {e}")) @@ -3723,27 +3723,36 @@ mod tests { use crate::config::ColumnEncryptionProperties; use crate::config::ConfigFileEncryptionProperties; use parquet::encryption::encrypt::FileEncryptionProperties; + use std::collections::HashMap; + + let valid_footer_key_as_hex = hex::encode(b"0123456789012345"); + + let mut enc = ConfigFileEncryptionProperties { + encrypt_footer: true, + footer_key_as_hex: valid_footer_key_as_hex.clone(), + footer_key_metadata_as_hex: String::new(), + column_encryption_properties: HashMap::new(), + aad_prefix_as_hex: String::new(), + store_aad_prefix: false, + }; // Encryption: invalid footer key hex - let mut enc = ConfigFileEncryptionProperties::default(); enc.footer_key_as_hex = "not_hex".to_string(); - let err = FileEncryptionProperties::try_from(enc) + let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); assert!(err.contains("Unable to decode hex footer key")); + enc.footer_key_as_hex = valid_footer_key_as_hex.clone(); // Encryption: invalid footer key metadata hex - let mut enc = ConfigFileEncryptionProperties::default(); - enc.footer_key_as_hex = hex::encode(b"0123456789012345"); enc.footer_key_metadata_as_hex = "zz".to_string(); - let err = FileEncryptionProperties::try_from(enc) + let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); assert!(err.contains("Unable to decode hex footer key metadata")); + enc.footer_key_metadata_as_hex = String::new(); // Encryption: invalid column key hex - let mut enc = ConfigFileEncryptionProperties::default(); - enc.footer_key_as_hex = hex::encode(b"0123456789012345"); enc.column_encryption_properties.insert( "col1".to_string(), ColumnEncryptionProperties { @@ -3757,10 +3766,9 @@ mod tests { assert!( err.contains("Unable to decode hex encryption key metadata for column col1") ); + enc.column_encryption_properties.clear(); // Encryption: invalid column metadata hex - let mut enc = ConfigFileEncryptionProperties::default(); - enc.footer_key_as_hex = hex::encode(b"0123456789012345"); enc.column_encryption_properties.insert( "col1".to_string(), ColumnEncryptionProperties { @@ -3772,10 +3780,9 @@ mod tests { .unwrap_err() .to_string(); assert!(err.contains("Unable to decode hex column metadata for column col1")); + enc.column_encryption_properties.clear(); // Encryption: invalid AAD prefix hex - let mut enc = ConfigFileEncryptionProperties::default(); - enc.footer_key_as_hex = hex::encode(b"0123456789012345"); enc.aad_prefix_as_hex = "zz".to_string(); let err = FileEncryptionProperties::try_from(enc) .unwrap_err() @@ -3789,10 +3796,18 @@ mod tests { use crate::config::ColumnDecryptionProperties; use crate::config::ConfigFileDecryptionProperties; use parquet::encryption::decrypt::FileDecryptionProperties; + use std::collections::HashMap; + + let valid_footer_key_as_hex = hex::encode(b"0123456789012345"); + + let mut dec = ConfigFileDecryptionProperties { + footer_key_as_hex: valid_footer_key_as_hex.clone(), + column_decryption_properties: HashMap::new(), + aad_prefix_as_hex: String::new(), + footer_signature_verification: true, + }; // Decryption: invalid column key hex - let mut dec = ConfigFileDecryptionProperties::default(); - dec.footer_key_as_hex = hex::encode(b"0123456789012345"); dec.column_decryption_properties.insert( "col1".to_string(), ColumnDecryptionProperties { @@ -3804,18 +3819,17 @@ mod tests { .to_string(); assert!(err.contains("Could not decode hex column key")); assert!(err.contains("col1")); + dec.column_decryption_properties.clear(); // Decryption: invalid footer key hex - let mut dec = ConfigFileDecryptionProperties::default(); dec.footer_key_as_hex = "bad".to_string(); let err = FileDecryptionProperties::try_from(dec) .unwrap_err() .to_string(); assert!(err.contains("Could not decode hex footer key")); + dec.footer_key_as_hex = valid_footer_key_as_hex; // Decryption: invalid AAD prefix hex - let mut dec = ConfigFileDecryptionProperties::default(); - dec.footer_key_as_hex = hex::encode(b"0123456789012345"); dec.aad_prefix_as_hex = "zz".to_string(); let err = FileDecryptionProperties::try_from(dec) .unwrap_err() From 84da70f943d733451a610bea033ea3fbfb1bee50 Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Sat, 2 May 2026 18:32:53 +0530 Subject: [PATCH 3/6] more lint issues solved --- datafusion/common/src/config.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index 9889e7505a5de..25d310d762d3e 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -3760,7 +3760,7 @@ mod tests { column_metadata_as_hex: None, }, ); - let err = FileEncryptionProperties::try_from(enc) + let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); assert!( @@ -3776,7 +3776,7 @@ mod tests { column_metadata_as_hex: Some("zz".to_string()), }, ); - let err = FileEncryptionProperties::try_from(enc) + let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); assert!(err.contains("Unable to decode hex column metadata for column col1")); @@ -3784,7 +3784,7 @@ mod tests { // Encryption: invalid AAD prefix hex enc.aad_prefix_as_hex = "zz".to_string(); - let err = FileEncryptionProperties::try_from(enc) + let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); assert!(err.contains("Unable to decode hex AAD prefix")); @@ -3814,7 +3814,7 @@ mod tests { column_key_as_hex: "bad".to_string(), }, ); - let err = FileDecryptionProperties::try_from(dec) + let err = FileDecryptionProperties::try_from(dec.clone()) .unwrap_err() .to_string(); assert!(err.contains("Could not decode hex column key")); @@ -3823,7 +3823,7 @@ mod tests { // Decryption: invalid footer key hex dec.footer_key_as_hex = "bad".to_string(); - let err = FileDecryptionProperties::try_from(dec) + let err = FileDecryptionProperties::try_from(dec.clone()) .unwrap_err() .to_string(); assert!(err.contains("Could not decode hex footer key")); @@ -3831,7 +3831,7 @@ mod tests { // Decryption: invalid AAD prefix hex dec.aad_prefix_as_hex = "zz".to_string(); - let err = FileDecryptionProperties::try_from(dec) + let err = FileDecryptionProperties::try_from(dec.clone()) .unwrap_err() .to_string(); assert!(err.contains("Could not decode hex AAD prefix")); From 552abe7570d98d5addeb67315669f103c5425e32 Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Sun, 3 May 2026 21:54:26 +0530 Subject: [PATCH 4/6] Fixed comments --- datafusion/common/src/config.rs | 6 +- .../library-user-guide/upgrading/54.0.0.md | 103 ++++++++++++++++++ 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index 25d310d762d3e..d238e5cd131f5 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -2887,7 +2887,7 @@ impl TryFrom for FileEncryptionProperties { for (column_name, encryption_props) in val.column_encryption_properties.iter() { let encryption_key = hex::decode(&encryption_props.column_key_as_hex) .map_err(|e| { - DataFusionError::Configuration(format!("Unable to decode hex encryption key metadata for column {column_name}: {e}")) + DataFusionError::Configuration(format!("Unable to decode hex encryption key for column {column_name}: {e}")) })?; let key_metadata = encryption_props .column_metadata_as_hex @@ -3763,9 +3763,7 @@ mod tests { let err = FileEncryptionProperties::try_from(enc.clone()) .unwrap_err() .to_string(); - assert!( - err.contains("Unable to decode hex encryption key metadata for column col1") - ); + assert!(err.contains("Unable to decode hex encryption key for column col1")); enc.column_encryption_properties.clear(); // Encryption: invalid column metadata hex diff --git a/docs/source/library-user-guide/upgrading/54.0.0.md b/docs/source/library-user-guide/upgrading/54.0.0.md index 34d1f7c61eaf1..bcb9723b23a4a 100644 --- a/docs/source/library-user-guide/upgrading/54.0.0.md +++ b/docs/source/library-user-guide/upgrading/54.0.0.md @@ -447,6 +447,109 @@ let config_decryption_properties = ConfigFileDecryptionProperties::try_from(&dec See [#21602](https://github.com/apache/datafusion/issues/21602) and [PR #21603](https://github.com/apache/datafusion/pull/21603) for details. +### Conversion from `ConfigFileEncryptionProperties` / `ConfigFileDecryptionProperties` is now fallible + +Previously, `datafusion_common::config::ConfigFileEncryptionProperties` and +`datafusion_common::config::ConfigFileDecryptionProperties` implemented infallible +conversions into Parquet's encryption/decryption types: + +- `impl From for parquet::encryption::encrypt::FileEncryptionProperties` +- `impl From for parquet::encryption::decrypt::FileDecryptionProperties` + +These conversions may need to decode hex-encoded keys and other configuration values, which can fail. +They now use `TryFrom` and return a `Result`: + +- `impl TryFrom for FileEncryptionProperties` +- `impl TryFrom for FileDecryptionProperties` + +**Migration guide:** + +Replace `from()` / `into()` with `try_from()` / `try_into()` and handle the resulting `Result`. + +**Before:** + +```rust,ignore +use datafusion_common::config::{ + ColumnDecryptionProperties, ColumnEncryptionProperties, ConfigFileDecryptionProperties, + ConfigFileEncryptionProperties, +}; +use parquet::encryption::decrypt::FileDecryptionProperties; +use parquet::encryption::encrypt::FileEncryptionProperties; +use std::collections::HashMap; + +let config_encryption = ConfigFileEncryptionProperties { + encrypt_footer: true, + footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), + footer_key_metadata_as_hex: "aabbccddeeff".to_string(), + column_encryption_properties: HashMap::from([( + "my_col".to_string(), + ColumnEncryptionProperties { + column_key_as_hex: "deadbeef".to_string(), + column_metadata_as_hex: Some("010203".to_string()), + }, + )]), + aad_prefix_as_hex: "cafebabe".to_string(), + store_aad_prefix: false, +}; + +let config_decryption = ConfigFileDecryptionProperties { + footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), + column_decryption_properties: HashMap::from([( + "my_col".to_string(), + ColumnDecryptionProperties { + column_key_as_hex: "deadbeef".to_string(), + }, + )]), + aad_prefix_as_hex: "cafebabe".to_string(), + footer_signature_verification: true, +}; + +let file_encryption: FileEncryptionProperties = config_encryption.into(); +let file_decryption: FileDecryptionProperties = config_decryption.into(); +``` + +**After:** + +```rust,ignore +use datafusion_common::config::{ + ColumnDecryptionProperties, ColumnEncryptionProperties, ConfigFileDecryptionProperties, + ConfigFileEncryptionProperties, +}; +use parquet::encryption::decrypt::FileDecryptionProperties; +use parquet::encryption::encrypt::FileEncryptionProperties; +use std::collections::HashMap; + +let config_encryption = ConfigFileEncryptionProperties { + encrypt_footer: true, + footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), + footer_key_metadata_as_hex: "aabbccddeeff".to_string(), + column_encryption_properties: HashMap::from([( + "my_col".to_string(), + ColumnEncryptionProperties { + column_key_as_hex: "deadbeef".to_string(), + column_metadata_as_hex: Some("010203".to_string()), + }, + )]), + aad_prefix_as_hex: "cafebabe".to_string(), + store_aad_prefix: false, +}; + +let config_decryption = ConfigFileDecryptionProperties { + footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), + column_decryption_properties: HashMap::from([( + "my_col".to_string(), + ColumnDecryptionProperties { + column_key_as_hex: "deadbeef".to_string(), + }, + )]), + aad_prefix_as_hex: "cafebabe".to_string(), + footer_signature_verification: true, +}; + +let file_encryption = FileEncryptionProperties::try_from(config_encryption)?; +let file_decryption = FileDecryptionProperties::try_from(config_decryption)?; +``` + ### `approx_percentile_cont`, `approx_percentile_cont_with_weight`, `approx_median` now coerce to floats The type signatures of `approx_percentile_cont`, `approx_percentile_cont_with_weight`, and From 2ae481e42d94dac58810b12eebf4fdd23af6822e Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Mon, 4 May 2026 23:55:50 +0530 Subject: [PATCH 5/6] Updated variable name --- datafusion/common/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index d238e5cd131f5..7d32f2a88fd9c 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -3048,12 +3048,12 @@ impl TryFrom for FileDecryptionProperties { let mut column_keys: Vec> = Vec::new(); for (col_name, decryption_properties) in val.column_decryption_properties.iter() { - let column_key_as_hex = hex::decode(&decryption_properties.column_key_as_hex).map_err(|e| { + let column_key = hex::decode(&decryption_properties.column_key_as_hex).map_err(|e| { DataFusionError::Configuration(format! ("Could not decode hex column key from ConfigFileDecryptionProperties for column name {col_name}: {e}.")) })?; column_names.push(col_name.as_str()); - column_keys.push(column_key_as_hex); + column_keys.push(column_key); } let footer_key = hex::decode(val.footer_key_as_hex).map_err(|e| { From f84b281676a1c0cf41c2920390fc41c2f4764fb0 Mon Sep 17 00:00:00 2001 From: Soham Bhattacharjee Date: Tue, 5 May 2026 02:24:51 +0530 Subject: [PATCH 6/6] Update in documentation --- .../library-user-guide/upgrading/54.0.0.md | 103 ++++-------------- 1 file changed, 21 insertions(+), 82 deletions(-) diff --git a/docs/source/library-user-guide/upgrading/54.0.0.md b/docs/source/library-user-guide/upgrading/54.0.0.md index bcb9723b23a4a..e6885fbdfa947 100644 --- a/docs/source/library-user-guide/upgrading/54.0.0.md +++ b/docs/source/library-user-guide/upgrading/54.0.0.md @@ -451,16 +451,13 @@ See [#21602](https://github.com/apache/datafusion/issues/21602) and Previously, `datafusion_common::config::ConfigFileEncryptionProperties` and `datafusion_common::config::ConfigFileDecryptionProperties` implemented infallible -conversions into Parquet's encryption/decryption types: - -- `impl From for parquet::encryption::encrypt::FileEncryptionProperties` -- `impl From for parquet::encryption::decrypt::FileDecryptionProperties` - +conversions into Parquet's encryption/decryption types (via `From` / `Into`). These conversions may need to decode hex-encoded keys and other configuration values, which can fail. -They now use `TryFrom` and return a `Result`: -- `impl TryFrom for FileEncryptionProperties` -- `impl TryFrom for FileDecryptionProperties` +They now use `TryFrom` / `TryInto` and return a `Result`: + +- `impl TryFrom for parquet::encryption::encrypt::FileEncryptionProperties` +- `impl TryFrom for parquet::encryption::decrypt::FileDecryptionProperties` **Migration guide:** @@ -469,87 +466,29 @@ Replace `from()` / `into()` with `try_from()` / `try_into()` and handle the resu **Before:** ```rust,ignore -use datafusion_common::config::{ - ColumnDecryptionProperties, ColumnEncryptionProperties, ConfigFileDecryptionProperties, - ConfigFileEncryptionProperties, -}; -use parquet::encryption::decrypt::FileDecryptionProperties; -use parquet::encryption::encrypt::FileEncryptionProperties; -use std::collections::HashMap; - -let config_encryption = ConfigFileEncryptionProperties { - encrypt_footer: true, - footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), - footer_key_metadata_as_hex: "aabbccddeeff".to_string(), - column_encryption_properties: HashMap::from([( - "my_col".to_string(), - ColumnEncryptionProperties { - column_key_as_hex: "deadbeef".to_string(), - column_metadata_as_hex: Some("010203".to_string()), - }, - )]), - aad_prefix_as_hex: "cafebabe".to_string(), - store_aad_prefix: false, -}; - -let config_decryption = ConfigFileDecryptionProperties { - footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), - column_decryption_properties: HashMap::from([( - "my_col".to_string(), - ColumnDecryptionProperties { - column_key_as_hex: "deadbeef".to_string(), - }, - )]), - aad_prefix_as_hex: "cafebabe".to_string(), - footer_signature_verification: true, -}; - -let file_encryption: FileEncryptionProperties = config_encryption.into(); -let file_decryption: FileDecryptionProperties = config_decryption.into(); +let file_encryption_properties: FileEncryptionProperties = config_encryption_properties.into(); +// or +let file_decryption_properties = FileDecryptionProperties::from(config_decryption_properties); ``` +( +where `config_encryption_properties` is a `ConfigFileEncryptionProperties` and +`config_decryption_properties` is a `ConfigFileDecryptionProperties` +) + **After:** ```rust,ignore -use datafusion_common::config::{ - ColumnDecryptionProperties, ColumnEncryptionProperties, ConfigFileDecryptionProperties, - ConfigFileEncryptionProperties, -}; -use parquet::encryption::decrypt::FileDecryptionProperties; -use parquet::encryption::encrypt::FileEncryptionProperties; -use std::collections::HashMap; - -let config_encryption = ConfigFileEncryptionProperties { - encrypt_footer: true, - footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), - footer_key_metadata_as_hex: "aabbccddeeff".to_string(), - column_encryption_properties: HashMap::from([( - "my_col".to_string(), - ColumnEncryptionProperties { - column_key_as_hex: "deadbeef".to_string(), - column_metadata_as_hex: Some("010203".to_string()), - }, - )]), - aad_prefix_as_hex: "cafebabe".to_string(), - store_aad_prefix: false, -}; - -let config_decryption = ConfigFileDecryptionProperties { - footer_key_as_hex: "00112233445566778899aabbccddeeff".to_string(), - column_decryption_properties: HashMap::from([( - "my_col".to_string(), - ColumnDecryptionProperties { - column_key_as_hex: "deadbeef".to_string(), - }, - )]), - aad_prefix_as_hex: "cafebabe".to_string(), - footer_signature_verification: true, -}; - -let file_encryption = FileEncryptionProperties::try_from(config_encryption)?; -let file_decryption = FileDecryptionProperties::try_from(config_decryption)?; +let file_encryption_properties: FileEncryptionProperties = + config_encryption_properties.try_into()?; +// or +let file_decryption_properties = + FileDecryptionProperties::try_from(config_decryption_properties)?; ``` +See [#21974](https://github.com/apache/datafusion/issues/21974) and +[PR #21985](https://github.com/apache/datafusion/pull/21985) for details. + ### `approx_percentile_cont`, `approx_percentile_cont_with_weight`, `approx_median` now coerce to floats The type signatures of `approx_percentile_cont`, `approx_percentile_cont_with_weight`, and