@@ -3184,9 +3184,11 @@ impl<'a> Parser<'a> {
3184
3184
{
3185
3185
let expr2 = self.parse_expr()?;
3186
3186
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)
3187
3189
} else {
3188
3190
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",
3190
3192
self.peek_token(),
3191
3193
)
3192
3194
}
@@ -3851,7 +3853,7 @@ impl<'a> Parser<'a> {
3851
3853
/// If the current token is the `expected` keyword, consume the token.
3852
3854
/// Otherwise, return an error.
3853
3855
///
3854
- // todo deprecate infavor of expected_keyword_is
3856
+ // todo deprecate in favor of expected_keyword_is
3855
3857
pub fn expect_keyword(&mut self, expected: Keyword) -> Result<TokenWithSpan, ParserError> {
3856
3858
if self.parse_keyword(expected) {
3857
3859
Ok(self.get_current_token().clone())
@@ -8453,6 +8455,33 @@ impl<'a> Parser<'a> {
8453
8455
}
8454
8456
}
8455
8457
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
+
8456
8485
pub fn parse_enum_values(&mut self) -> Result<Vec<EnumMember>, ParserError> {
8457
8486
self.expect_token(&Token::LParen)?;
8458
8487
let values = self.parse_comma_separated(|parser| {
@@ -8979,7 +9008,7 @@ impl<'a> Parser<'a> {
8979
9008
}
8980
9009
}
8981
9010
8982
- /// Parse a table object for insetion
9011
+ /// Parse a table object for insertion
8983
9012
/// e.g. `some_database.some_table` or `FUNCTION some_table_func(...)`
8984
9013
pub fn parse_table_object(&mut self) -> Result<TableObject, ParserError> {
8985
9014
if self.dialect.supports_insert_table_function() && self.parse_keyword(Keyword::FUNCTION) {
@@ -11887,7 +11916,7 @@ impl<'a> Parser<'a> {
11887
11916
} else {
11888
11917
let mut name = self.parse_grantee_name()?;
11889
11918
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:
11891
11920
// <Namespace>:<GroupName> or <Namespace>:<UserName>
11892
11921
// https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-access-control-native-idp.html
11893
11922
let ident = self.parse_identifier()?;
@@ -12883,7 +12912,7 @@ impl<'a> Parser<'a> {
12883
12912
Ok(WithFill { from, to, step })
12884
12913
}
12885
12914
12886
- // Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect)
12915
+ // Parse a set of comma separated INTERPOLATE expressions (ClickHouse dialect)
12887
12916
// that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier
12888
12917
pub fn parse_interpolations(&mut self) -> Result<Option<Interpolate>, ParserError> {
12889
12918
if !self.parse_keyword(Keyword::INTERPOLATE) {
@@ -14432,7 +14461,7 @@ mod tests {
14432
14461
assert_eq!(
14433
14462
ast,
14434
14463
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"
14436
14465
.to_string()
14437
14466
))
14438
14467
);
0 commit comments