diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a5b167a17..72f3e6dfd 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -4099,13 +4099,21 @@ impl<'a> Parser<'a> { ), } } else if Token::DoubleColon == *tok { - Ok(Expr::Cast { + let cast = Expr::Cast { kind: CastKind::DoubleColon, expr: Box::new(expr), data_type: self.parse_data_type()?, array: false, format: None, - }) + }; + if dialect_of!(self is SnowflakeDialect) && self.parse_keyword(Keyword::COLLATE) { + Ok(Expr::Collate { + expr: Box::new(cast), + collation: self.parse_object_name(false)?, + }) + } else { + Ok(cast) + } } else if Token::ExclamationMark == *tok && self.dialect.supports_factorial_operator() { Ok(Expr::UnaryOp { op: UnaryOperator::PGPostfixFactorial, diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 2661eb035..f1b9213e5 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5105,6 +5105,18 @@ fn test_timestamp_ntz_with_precision() { } } +#[test] +fn test_collate_after_double_colon_cast() { + let select = snowflake().verified_only_select("SELECT 'ñ'::VARCHAR COLLATE 'es'"); + match expr_from_projection(only(&select.projection)) { + Expr::Collate { expr, collation } => { + assert_eq!(collation.to_string(), "'es'"); + assert!(matches!(expr.as_ref(), Expr::Cast { .. })); + } + expr => panic!("Expected COLLATE expression, got {expr:?}"), + } +} + #[test] fn test_drop_constraints() { snowflake().verified_stmt("ALTER TABLE tbl DROP PRIMARY KEY");