From 735469a3d38297fcde40e7b29e7f242236fd3607 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 30 Apr 2026 10:30:44 +0200 Subject: [PATCH 1/4] Replace unwraps in ast/ Replace if x.is_some() { x.as_ref().unwrap() } with if let Some(x) = x { x } --- src/ast/ddl.rs | 3 +-- src/ast/helpers/stmt_data_loading.rs | 16 ++++++-------- src/ast/mod.rs | 31 +++++++++++----------------- src/ast/query.rs | 15 +++++++------- 4 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 67aefb3928..067f4b8df3 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -2113,8 +2113,7 @@ impl fmt::Display for ColumnOption { GeneratedAs::ExpStored => "", }; write!(f, "GENERATED {when} AS IDENTITY")?; - if sequence_options.is_some() { - let so = sequence_options.as_ref().unwrap(); + if let Some(so) = sequence_options { if !so.is_empty() { write!(f, " (")?; } diff --git a/src/ast/helpers/stmt_data_loading.rs b/src/ast/helpers/stmt_data_loading.rs index dfc1f4b0bf..5e997bac70 100644 --- a/src/ast/helpers/stmt_data_loading.rs +++ b/src/ast/helpers/stmt_data_loading.rs @@ -86,18 +86,14 @@ pub struct StageLoadSelectItem { impl fmt::Display for StageParamsObject { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let url = &self.url.as_ref(); - let storage_integration = &self.storage_integration.as_ref(); - let endpoint = &self.endpoint.as_ref(); - - if url.is_some() { - write!(f, " URL='{}'", url.unwrap())?; + if let Some(ref url) = self.url { + write!(f, " URL='{url}'")?; } - if storage_integration.is_some() { - write!(f, " STORAGE_INTEGRATION={}", storage_integration.unwrap())?; + if let Some(ref storage_integration) = self.storage_integration { + write!(f, " STORAGE_INTEGRATION={storage_integration}")?; } - if endpoint.is_some() { - write!(f, " ENDPOINT='{}'", endpoint.unwrap())?; + if let Some(ref endpoint) = self.endpoint { + write!(f, " ENDPOINT='{endpoint}'")?; } if !self.credentials.options.is_empty() { write!(f, " CREDENTIALS=({})", self.credentials)?; diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 886bea26d5..16f7db97fe 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1853,16 +1853,10 @@ impl fmt::Display for Expr { negated, } => { let not_ = if *negated { "NOT " } else { "" }; - if form.is_none() { - write!(f, "{expr} IS {not_}NORMALIZED") + if let Some(form) = form { + write!(f, "{} IS {}{} NORMALIZED", expr, not_, form) } else { - write!( - f, - "{} IS {}{} NORMALIZED", - expr, - not_, - form.as_ref().unwrap() - ) + write!(f, "{expr} IS {not_}NORMALIZED") } } Expr::SimilarTo { @@ -5741,8 +5735,8 @@ impl fmt::Display for Statement { write!(f, " SESSION")?; } write!(f, " STATUS")?; - if filter.is_some() { - write!(f, " {}", filter.as_ref().unwrap())?; + if let Some(filter) = filter { + write!(f, " {}", filter)?; } Ok(()) } @@ -5759,8 +5753,8 @@ impl fmt::Display for Statement { write!(f, " SESSION")?; } write!(f, " VARIABLES")?; - if filter.is_some() { - write!(f, " {}", filter.as_ref().unwrap())?; + if let Some(filter) = filter { + write!(f, " {}", filter)?; } Ok(()) } @@ -6172,8 +6166,8 @@ impl fmt::Display for Statement { if !copy_options.options.is_empty() { write!(f, " COPY_OPTIONS=({copy_options})")?; } - if comment.is_some() { - write!(f, " COMMENT='{}'", comment.as_ref().unwrap())?; + if let Some(comment) = comment { + write!(f, " COMMENT='{}'", comment)?; } Ok(()) } @@ -6260,12 +6254,11 @@ impl fmt::Display for Statement { } Statement::Pragma { name, value, is_eq } => { write!(f, "PRAGMA {name}")?; - if value.is_some() { - let val = value.as_ref().unwrap(); + if let Some(value) = value { if *is_eq { - write!(f, " = {val}")?; + write!(f, " = {value}")?; } else { - write!(f, "({val})")?; + write!(f, "({value})")?; } } Ok(()) diff --git a/src/ast/query.rs b/src/ast/query.rs index bbdd7540af..35f3288a8e 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -307,15 +307,14 @@ pub struct Table { impl fmt::Display for Table { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(ref schema_name) = self.schema_name { - write!( - f, - "TABLE {}.{}", - schema_name, - self.table_name.as_ref().unwrap(), - )?; + if let Some(ref table_name) = self.table_name { + if let Some(ref schema_name) = self.schema_name { + write!(f, "TABLE {}.{}", schema_name, table_name,)?; + } else { + write!(f, "TABLE {}", table_name)?; + } } else { - write!(f, "TABLE {}", self.table_name.as_ref().unwrap(),)?; + write!(f, "TABLE")?; } Ok(()) } From e0b8b947ec2432a76ac22b583e5437339affd1f8 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 30 Apr 2026 14:15:36 +0200 Subject: [PATCH 2/4] Fix invalid utf8 slicing in EscapeQuotedString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This could previously panick with multi-byte utf8 characters: datafusion-sqlparser-rs-896df239ce2264c8/847ddf3/src/ast/value.rs:583:53: end byte index 271 is not a char boundary; it is inside '�' (bytes 270..273 of string) --- src/ast/value.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/value.rs b/src/ast/value.rs index 5f069f36cc..ecb7f78f99 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -577,7 +577,8 @@ impl fmt::Display for EscapeQuotedString<'_> { // The quote is not escaped. // Including idx in the range, so the quote at idx will be printed twice: // in this call to write_str() and in the next one. - f.write_str(&self.string[start_idx..=idx])?; + let end_idx = idx + ch.len_utf8(); + f.write_str(&self.string[start_idx..end_idx])?; start_idx = idx; } } From 4db5f57bdbd61001a55518a9c5942f983ba1745a Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 30 Apr 2026 14:33:22 +0200 Subject: [PATCH 3/4] Avoid unwrap in parse_flush --- src/parser/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 668c520e5e..8958b755de 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1009,7 +1009,7 @@ impl<'a> Parser<'a> { FlushType::OptimizerCosts } else if self.parse_keywords(&[Keyword::RELAY, Keyword::LOGS]) { if self.parse_keywords(&[Keyword::FOR, Keyword::CHANNEL]) { - channel = Some(self.parse_object_name(false).unwrap().to_string()); + channel = Some(self.parse_object_name(false)?.to_string()); } FlushType::RelayLogs } else if self.parse_keywords(&[Keyword::SLOW, Keyword::LOGS]) { From 3209f3c27f03c8aa485acdc70ca15856e20902fd Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Tue, 5 May 2026 16:50:32 +0200 Subject: [PATCH 4/4] Add test for EscapeQuotedString multibyte handling --- src/ast/value.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ast/value.rs b/src/ast/value.rs index ecb7f78f99..ade7decf9a 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -708,3 +708,12 @@ impl fmt::Display for TrimWhereField { }) } } + +#[cfg(test)] +#[test] +fn test_escape_quoted_string_with_multibyte_quote_char() { + assert_eq!( + format!("{}", escape_quoted_string("a🦀b🦀c", '🦀')), + "a🦀🦀b🦀🦀c" + ); +}