From 4497a686a502de581eb654d51ecf1f9a55edd300 Mon Sep 17 00:00:00 2001 From: Roopesh S <119874392+TechWizard9999@users.noreply.github.com> Date: Fri, 6 Nov 2026 12:36:45 +0530 Subject: [PATCH] fix parse_url ansi --- .../spark/src/function/url/parse_url.rs | 36 ++++++++++++++++--- .../test_files/spark/url/parse_url.slt | 21 +++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/datafusion/spark/src/function/url/parse_url.rs b/datafusion/spark/src/function/url/parse_url.rs index 7d03f9d824c67..edb967bc9a889 100644 --- a/datafusion/spark/src/function/url/parse_url.rs +++ b/datafusion/spark/src/function/url/parse_url.rs @@ -180,8 +180,11 @@ impl ScalarUDFImpl for ParseUrl { } fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result { - let ScalarFunctionArgs { args, .. } = args; - make_scalar_function(spark_parse_url, vec![])(&args) + let enable_ansi_mode = args.config_options.execution.enable_ansi_mode; + make_scalar_function( + move |arrays: &[ArrayRef]| spark_parse_url(arrays, enable_ansi_mode), + vec![], + )(&args.args) } } @@ -200,8 +203,11 @@ impl ScalarUDFImpl for ParseUrl { /// - A string array with extracted URL components /// - `None` values where extraction failed or component doesn't exist /// - The output array type (StringArray or LargeStringArray) is determined by input types -fn spark_parse_url(args: &[ArrayRef]) -> Result { - spark_handled_parse_url(args, |x| x) +fn spark_parse_url(args: &[ArrayRef], enable_ansi_mode: bool) -> Result { + spark_handled_parse_url(args, |x| match x { + Err(_) if !enable_ansi_mode => Ok(None), + result => result, + }) } pub fn spark_handled_parse_url( @@ -622,4 +628,26 @@ mod tests { let msg = format!("{err}"); assert!(msg.contains("expects STRING arguments")); } + + #[test] + fn test_malformed_url_null_unless_ansi() -> Result<()> { + let urls = sa(&[ + Some("https://example.com/a"), + Some("inva lid://example.com"), + ]); + let parts = sa(&[Some("HOST"), Some("HOST")]); + + let out = spark_parse_url(&[Arc::clone(&urls), Arc::clone(&parts)], false)?; + let out_sa = out.as_any().downcast_ref::().unwrap(); + assert_eq!(out_sa.value(0), "example.com"); + assert!(out_sa.is_null(1)); + + let err = spark_parse_url(&[Arc::clone(&urls), parts], true).unwrap_err(); + assert!(format!("{err}").contains("The url is invalid")); + + // Argument errors are not turned into NULL + let err = spark_parse_url(from_ref(&urls), false).unwrap_err(); + assert!(format!("{err}").contains("expects 2 or 3 arguments")); + Ok(()) + } } diff --git a/datafusion/sqllogictest/test_files/spark/url/parse_url.slt b/datafusion/sqllogictest/test_files/spark/url/parse_url.slt index 595b264cdcf3e..9abda98dff66a 100644 --- a/datafusion/sqllogictest/test_files/spark/url/parse_url.slt +++ b/datafusion/sqllogictest/test_files/spark/url/parse_url.slt @@ -330,9 +330,30 @@ NULL statement error 'parse_url' does not support zero arguments SELECT parse_url(); +# A malformed URL returns NULL when ANSI mode is off (the default) +query T +SELECT parse_url('inva lid://spark.apache.org/path?query=1', 'QUERY'); +---- +NULL + +query T +SELECT parse_url('http://spark.apache.org:99999/path', 'HOST'); +---- +NULL + +# A malformed URL raises an error when ANSI mode is on +statement ok +set datafusion.execution.enable_ansi_mode = true; + query error DataFusion error: Execution error: The url is invalid: inva lid://spark\.apache\.org/path\?query=1\. Use `try_parse_url` to tolerate invalid URL and return NULL instead\. SQLSTATE: 22P02 SELECT parse_url('inva lid://spark.apache.org/path?query=1', 'QUERY'); +query error DataFusion error: Execution error: InvalidPort +SELECT parse_url('http://spark.apache.org:99999/path', 'HOST'); + +statement ok +set datafusion.execution.enable_ansi_mode = false; + # NULL argument handling (Sail PR #1393) # NULL URL should return NULL query T