@@ -3184,9 +3184,11 @@ impl<'a> Parser<'a> {
31843184 {
31853185 let expr2 = self.parse_expr()?;
31863186 Ok(Expr::IsNotDistinctFrom(Box::new(expr), Box::new(expr2)))
3187+ } else if let Ok(is_normalized) = self.parse_unicode_is_normalized(expr) {
3188+ Ok(is_normalized)
31873189 } else {
31883190 self.expected(
3189- "[NOT] NULL or TRUE| FALSE or [NOT] DISTINCT FROM after IS",
3191+ "[NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS",
31903192 self.peek_token(),
31913193 )
31923194 }
@@ -3851,7 +3853,7 @@ impl<'a> Parser<'a> {
38513853 /// If the current token is the `expected` keyword, consume the token.
38523854 /// Otherwise, return an error.
38533855 ///
3854- // todo deprecate infavor of expected_keyword_is
3856+ // todo deprecate in favor of expected_keyword_is
38553857 pub fn expect_keyword(&mut self, expected: Keyword) -> Result<TokenWithSpan, ParserError> {
38563858 if self.parse_keyword(expected) {
38573859 Ok(self.get_current_token().clone())
@@ -8453,6 +8455,33 @@ impl<'a> Parser<'a> {
84538455 }
84548456 }
84558457
8458+ /// Parse a literal unicode normalization clause
8459+ pub fn parse_unicode_is_normalized(&mut self, expr: Expr) -> Result<Expr, ParserError> {
8460+ let neg = self.parse_keyword(Keyword::NOT);
8461+ let normalized_form = self.maybe_parse(|parser| {
8462+ match parser.parse_one_of_keywords(&[
8463+ Keyword::NFC,
8464+ Keyword::NFD,
8465+ Keyword::NFKC,
8466+ Keyword::NFKD,
8467+ ]) {
8468+ Some(Keyword::NFC) => Ok(NormalizationForm::NFC),
8469+ Some(Keyword::NFD) => Ok(NormalizationForm::NFD),
8470+ Some(Keyword::NFKC) => Ok(NormalizationForm::NFKC),
8471+ Some(Keyword::NFKD) => Ok(NormalizationForm::NFKD),
8472+ _ => parser.expected("unicode normalization form", parser.peek_token()),
8473+ }
8474+ })?;
8475+ if self.parse_keyword(Keyword::NORMALIZED) {
8476+ return Ok(Expr::IsNormalized {
8477+ expr: Box::new(expr),
8478+ form: normalized_form,
8479+ negated: neg,
8480+ });
8481+ }
8482+ self.expected("unicode normalization form", self.peek_token())
8483+ }
8484+
84568485 pub fn parse_enum_values(&mut self) -> Result<Vec<EnumMember>, ParserError> {
84578486 self.expect_token(&Token::LParen)?;
84588487 let values = self.parse_comma_separated(|parser| {
@@ -8979,7 +9008,7 @@ impl<'a> Parser<'a> {
89799008 }
89809009 }
89819010
8982- /// Parse a table object for insetion
9011+ /// Parse a table object for insertion
89839012 /// e.g. `some_database.some_table` or `FUNCTION some_table_func(...)`
89849013 pub fn parse_table_object(&mut self) -> Result<TableObject, ParserError> {
89859014 if self.dialect.supports_insert_table_function() && self.parse_keyword(Keyword::FUNCTION) {
@@ -11887,7 +11916,7 @@ impl<'a> Parser<'a> {
1188711916 } else {
1188811917 let mut name = self.parse_grantee_name()?;
1188911918 if self.consume_token(&Token::Colon) {
11890- // Redshift supports namespace prefix for extenrnal users and groups:
11919+ // Redshift supports namespace prefix for external users and groups:
1189111920 // <Namespace>:<GroupName> or <Namespace>:<UserName>
1189211921 // https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-access-control-native-idp.html
1189311922 let ident = self.parse_identifier()?;
@@ -12883,7 +12912,7 @@ impl<'a> Parser<'a> {
1288312912 Ok(WithFill { from, to, step })
1288412913 }
1288512914
12886- // Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect)
12915+ // Parse a set of comma separated INTERPOLATE expressions (ClickHouse dialect)
1288712916 // that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier
1288812917 pub fn parse_interpolations(&mut self) -> Result<Option<Interpolate>, ParserError> {
1288912918 if !self.parse_keyword(Keyword::INTERPOLATE) {
@@ -14432,7 +14461,7 @@ mod tests {
1443214461 assert_eq!(
1443314462 ast,
1443414463 Err(ParserError::ParserError(
14435- "Expected: [NOT] NULL or TRUE| FALSE or [NOT] DISTINCT FROM after IS, found: a at Line: 1, Column: 16"
14464+ "Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: a at Line: 1, Column: 16"
1443614465 .to_string()
1443714466 ))
1443814467 );
0 commit comments