@@ -1184,7 +1184,7 @@ impl SessionContext {
11841184 builder. with_object_list_cache_limit ( limit)
11851185 }
11861186 "list_files_cache_ttl" => {
1187- let duration = Self :: parse_duration ( value) ?;
1187+ let duration = Self :: parse_duration ( variable , value) ?;
11881188 builder. with_object_list_cache_ttl ( Some ( duration) )
11891189 }
11901190 _ => return plan_err ! ( "Unknown runtime configuration: {variable}" ) ,
@@ -1323,21 +1323,27 @@ impl SessionContext {
13231323 }
13241324 }
13251325
1326- fn parse_duration ( duration : & str ) -> Result < Duration > {
1326+ fn parse_duration ( config_name : & str , duration : & str ) -> Result < Duration > {
1327+ if duration. trim ( ) . is_empty ( ) {
1328+ return Err ( plan_datafusion_err ! (
1329+ "Duration should not be empty or blank for '{config_name}'"
1330+ ) ) ;
1331+ }
1332+
13271333 let mut minutes = None ;
13281334 let mut seconds = None ;
13291335
13301336 for duration in duration. split_inclusive ( & [ 'm' , 's' ] ) {
13311337 let ( number, unit) = duration. split_at ( duration. len ( ) - 1 ) ;
13321338 let number: u64 = number. parse ( ) . map_err ( |_| {
1333- plan_datafusion_err ! ( "Failed to parse number from duration '{duration}'" )
1339+ plan_datafusion_err ! ( "Failed to parse number from duration '{duration}' for '{config_name}' " )
13341340 } ) ?;
13351341
13361342 match unit {
13371343 "m" if minutes. is_none ( ) && seconds. is_none ( ) => minutes = Some ( number) ,
13381344 "s" if seconds. is_none ( ) => seconds = Some ( number) ,
1339- _ => plan_err ! (
1340- "Invalid duration, unit must be either 'm' (minutes), or 's' (seconds), and be in the correct order"
1345+ other => plan_err ! (
1346+ "Invalid duration unit: '{other}'. The unit must be either 'm' (minutes), or 's' (seconds), and be in the correct order for '{config_name}' "
13411347 ) ?,
13421348 }
13431349 }
@@ -1347,7 +1353,9 @@ impl SessionContext {
13471353 ) ;
13481354
13491355 if duration. is_zero ( ) {
1350- return plan_err ! ( "Duration must be greater than 0 seconds" ) ;
1356+ return plan_err ! (
1357+ "Duration must be greater than 0 seconds for '{config_name}'"
1358+ ) ;
13511359 }
13521360
13531361 Ok ( duration)
@@ -2803,21 +2811,33 @@ mod tests {
28032811
28042812 #[ test]
28052813 fn test_parse_duration ( ) {
2814+ const LIST_FILES_CACHE_TTL : & str = "datafusion.runtime.list_files_cache_ttl" ;
2815+
28062816 // Valid durations
28072817 for ( duration, want) in [
28082818 ( "1s" , Duration :: from_secs ( 1 ) ) ,
28092819 ( "1m" , Duration :: from_secs ( 60 ) ) ,
28102820 ( "1m0s" , Duration :: from_secs ( 60 ) ) ,
28112821 ( "1m1s" , Duration :: from_secs ( 61 ) ) ,
28122822 ] {
2813- let have = SessionContext :: parse_duration ( duration) . unwrap ( ) ;
2823+ let have =
2824+ SessionContext :: parse_duration ( LIST_FILES_CACHE_TTL , duration) . unwrap ( ) ;
28142825 assert_eq ! ( want, have) ;
28152826 }
28162827
28172828 // Invalid durations
2818- for duration in [ "0s" , "0m" , "1s0m" , "1s1m" ] {
2819- let have = SessionContext :: parse_duration ( duration) ;
2829+ for duration in [
2830+ "0s" , "0m" , "1s0m" , "1s1m" , "XYZ" , "1h" , "XYZm2s" , "" , " " , "-1m" , "1m 1s" ,
2831+ "1m1s " , " 1m1s" ,
2832+ ] {
2833+ let have = SessionContext :: parse_duration ( LIST_FILES_CACHE_TTL , duration) ;
28202834 assert ! ( have. is_err( ) ) ;
2835+ assert ! (
2836+ have. unwrap_err( )
2837+ . message( )
2838+ . to_string( )
2839+ . contains( LIST_FILES_CACHE_TTL )
2840+ ) ;
28212841 }
28222842 }
28232843
0 commit comments