19
19
20
20
use std:: any:: Any ;
21
21
use std:: collections:: { BTreeMap , HashMap } ;
22
+ use std:: error:: Error ;
22
23
use std:: fmt:: { self , Display } ;
23
24
use std:: str:: FromStr ;
24
25
@@ -29,7 +30,9 @@ use crate::{DataFusionError, Result};
29
30
30
31
/// A macro that wraps a configuration struct and automatically derives
31
32
/// [`Default`] and [`ConfigField`] for it, allowing it to be used
32
- /// in the [`ConfigOptions`] configuration tree
33
+ /// in the [`ConfigOptions`] configuration tree.
34
+ ///
35
+ /// `transform` is used to normalize values before parsing.
33
36
///
34
37
/// For example,
35
38
///
@@ -38,7 +41,7 @@ use crate::{DataFusionError, Result};
38
41
/// /// Amazing config
39
42
/// pub struct MyConfig {
40
43
/// /// Field 1 doc
41
- /// field1: String, default = "".to_string()
44
+ /// field1: String, transform = str::to_lowercase, default = "".to_string()
42
45
///
43
46
/// /// Field 2 doc
44
47
/// field2: usize, default = 232
@@ -67,9 +70,12 @@ use crate::{DataFusionError, Result};
67
70
/// fn set(&mut self, key: &str, value: &str) -> Result<()> {
68
71
/// let (key, rem) = key.split_once('.').unwrap_or((key, ""));
69
72
/// match key {
70
- /// "field1" => self.field1.set(rem, value),
71
- /// "field2" => self.field2.set(rem, value),
72
- /// "field3" => self.field3.set(rem, value),
73
+ /// "field1" => {
74
+ /// let value = str::to_lowercase(value);
75
+ /// self.field1.set(rem, value.as_ref())
76
+ /// },
77
+ /// "field2" => self.field2.set(rem, value.as_ref()),
78
+ /// "field3" => self.field3.set(rem, value.as_ref()),
73
79
/// _ => _internal_err!(
74
80
/// "Config value \"{}\" not found on MyConfig",
75
81
/// key
@@ -102,15 +108,14 @@ use crate::{DataFusionError, Result};
102
108
/// ```
103
109
///
104
110
/// NB: Misplaced commas may result in nonsensical errors
105
- ///
106
111
#[ macro_export]
107
112
macro_rules! config_namespace {
108
113
(
109
114
$( #[ doc = $struct_d: tt] ) *
110
115
$vis: vis struct $struct_name: ident {
111
116
$(
112
117
$( #[ doc = $d: tt] ) *
113
- $field_vis: vis $field_name: ident : $field_type: ty, default = $default: expr
118
+ $field_vis: vis $field_name: ident : $field_type: ty, $ ( warn = $warn : expr , ) ? $ ( transform = $transform : expr , ) ? default = $default: expr
114
119
) * $( , ) *
115
120
}
116
121
) => {
@@ -127,9 +132,14 @@ macro_rules! config_namespace {
127
132
impl ConfigField for $struct_name {
128
133
fn set( & mut self , key: & str , value: & str ) -> Result <( ) > {
129
134
let ( key, rem) = key. split_once( '.' ) . unwrap_or( ( key, "" ) ) ;
135
+
130
136
match key {
131
137
$(
132
- stringify!( $field_name) => self . $field_name. set( rem, value) ,
138
+ stringify!( $field_name) => {
139
+ $( let value = $transform( value) ; ) ?
140
+ $( log:: warn!( $warn) ; ) ?
141
+ self . $field_name. set( rem, value. as_ref( ) )
142
+ } ,
133
143
) *
134
144
_ => return _config_err!(
135
145
"Config value \" {}\" not found on {}" , key, stringify!( $struct_name)
@@ -211,12 +221,15 @@ config_namespace! {
211
221
/// When set to true, SQL parser will normalize ident (convert ident to lowercase when not quoted)
212
222
pub enable_ident_normalization: bool , default = true
213
223
214
- /// When set to true, SQL parser will normalize options value (convert value to lowercase)
215
- pub enable_options_value_normalization: bool , default = true
224
+ /// When set to true, SQL parser will normalize options value (convert value to lowercase).
225
+ /// Note that this option is ignored and will be removed in the future. All case-insensitive values
226
+ /// are normalized automatically.
227
+ pub enable_options_value_normalization: bool , warn = "`enable_options_value_normalization` is deprecated and ignored" , default = false
216
228
217
229
/// Configure the SQL dialect used by DataFusion's parser; supported values include: Generic,
218
230
/// MySQL, PostgreSQL, Hive, SQLite, Snowflake, Redshift, MsSQL, ClickHouse, BigQuery, and Ansi.
219
231
pub dialect: String , default = "generic" . to_string( )
232
+ // no need to lowercase because `sqlparser::dialect_from_str`] is case-insensitive
220
233
221
234
/// If true, permit lengths for `VARCHAR` such as `VARCHAR(20)`, but
222
235
/// ignore the length. If false, error if a `VARCHAR` with a length is
@@ -431,7 +444,7 @@ config_namespace! {
431
444
///
432
445
/// Note that this default setting is not the same as
433
446
/// the default parquet writer setting.
434
- pub compression: Option <String >, default = Some ( "zstd(3)" . into( ) )
447
+ pub compression: Option <String >, transform = str :: to_lowercase , default = Some ( "zstd(3)" . into( ) )
435
448
436
449
/// (writing) Sets if dictionary encoding is enabled. If NULL, uses
437
450
/// default parquet writer setting
@@ -444,7 +457,7 @@ config_namespace! {
444
457
/// Valid values are: "none", "chunk", and "page"
445
458
/// These values are not case sensitive. If NULL, uses
446
459
/// default parquet writer setting
447
- pub statistics_enabled: Option <String >, default = Some ( "page" . into( ) )
460
+ pub statistics_enabled: Option <String >, transform = str :: to_lowercase , default = Some ( "page" . into( ) )
448
461
449
462
/// (writing) Sets max statistics size for any column. If NULL, uses
450
463
/// default parquet writer setting
@@ -470,7 +483,7 @@ config_namespace! {
470
483
/// delta_byte_array, rle_dictionary, and byte_stream_split.
471
484
/// These values are not case sensitive. If NULL, uses
472
485
/// default parquet writer setting
473
- pub encoding: Option <String >, default = None
486
+ pub encoding: Option <String >, transform = str :: to_lowercase , default = None
474
487
475
488
/// (writing) Use any available bloom filters when reading parquet files
476
489
pub bloom_filter_on_read: bool , default = true
@@ -971,29 +984,45 @@ impl<F: ConfigField + Default> ConfigField for Option<F> {
971
984
}
972
985
}
973
986
987
+ fn default_transform < T > ( input : & str ) -> Result < T >
988
+ where
989
+ T : FromStr ,
990
+ <T as FromStr >:: Err : Sync + Send + Error + ' static ,
991
+ {
992
+ input. parse ( ) . map_err ( |e| {
993
+ DataFusionError :: Context (
994
+ format ! (
995
+ "Error parsing '{}' as {}" ,
996
+ input,
997
+ std:: any:: type_name:: <T >( )
998
+ ) ,
999
+ Box :: new ( DataFusionError :: External ( Box :: new ( e) ) ) ,
1000
+ )
1001
+ } )
1002
+ }
1003
+
974
1004
#[ macro_export]
975
1005
macro_rules! config_field {
976
1006
( $t: ty) => {
1007
+ config_field!( $t, value => default_transform( value) ?) ;
1008
+ } ;
1009
+
1010
+ ( $t: ty, $arg: ident => $transform: expr) => {
977
1011
impl ConfigField for $t {
978
1012
fn visit<V : Visit >( & self , v: & mut V , key: & str , description: & ' static str ) {
979
1013
v. some( key, self , description)
980
1014
}
981
1015
982
- fn set( & mut self , _: & str , value: & str ) -> Result <( ) > {
983
- * self = value. parse( ) . map_err( |e| {
984
- DataFusionError :: Context (
985
- format!( concat!( "Error parsing {} as " , stringify!( $t) , ) , value) ,
986
- Box :: new( DataFusionError :: External ( Box :: new( e) ) ) ,
987
- )
988
- } ) ?;
1016
+ fn set( & mut self , _: & str , $arg: & str ) -> Result <( ) > {
1017
+ * self = $transform;
989
1018
Ok ( ( ) )
990
1019
}
991
1020
}
992
1021
} ;
993
1022
}
994
1023
995
1024
config_field ! ( String ) ;
996
- config_field ! ( bool ) ;
1025
+ config_field ! ( bool , value => default_transform ( value . to_lowercase ( ) . as_str ( ) ) ? ) ;
997
1026
config_field ! ( usize ) ;
998
1027
config_field ! ( f64 ) ;
999
1028
config_field ! ( u64 ) ;
@@ -1508,7 +1537,7 @@ macro_rules! config_namespace_with_hashmap {
1508
1537
$vis: vis struct $struct_name: ident {
1509
1538
$(
1510
1539
$( #[ doc = $d: tt] ) *
1511
- $field_vis: vis $field_name: ident : $field_type: ty, default = $default: expr
1540
+ $field_vis: vis $field_name: ident : $field_type: ty, $ ( transform = $transform : expr , ) ? default = $default: expr
1512
1541
) * $( , ) *
1513
1542
}
1514
1543
) => {
@@ -1527,7 +1556,10 @@ macro_rules! config_namespace_with_hashmap {
1527
1556
let ( key, rem) = key. split_once( '.' ) . unwrap_or( ( key, "" ) ) ;
1528
1557
match key {
1529
1558
$(
1530
- stringify!( $field_name) => self . $field_name. set( rem, value) ,
1559
+ stringify!( $field_name) => {
1560
+ $( let value = $transform( value) ; ) ?
1561
+ self . $field_name. set( rem, value. as_ref( ) )
1562
+ } ,
1531
1563
) *
1532
1564
_ => _config_err!(
1533
1565
"Config value \" {}\" not found on {}" , key, stringify!( $struct_name)
@@ -1606,7 +1638,7 @@ config_namespace_with_hashmap! {
1606
1638
/// lzo, brotli(level), lz4, zstd(level), and lz4_raw.
1607
1639
/// These values are not case-sensitive. If NULL, uses
1608
1640
/// default parquet options
1609
- pub compression: Option <String >, default = None
1641
+ pub compression: Option <String >, transform = str :: to_lowercase , default = None
1610
1642
1611
1643
/// Sets if statistics are enabled for the column
1612
1644
/// Valid values are: "none", "chunk", and "page"
0 commit comments