Skip to content

Commit 2163da3

Browse files
committed
Merge branch 'main' into solontsev/clickhouse-mergetree-fix
2 parents 3868aba + b0bcc46 commit 2163da3

File tree

6 files changed

+82
-33
lines changed

6 files changed

+82
-33
lines changed

src/ast/ddl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1709,7 +1709,7 @@ pub struct ColumnPolicyProperty {
17091709
/// ```
17101710
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
17111711
pub with: bool,
1712-
pub policy_name: Ident,
1712+
pub policy_name: ObjectName,
17131713
pub using_columns: Option<Vec<Ident>>,
17141714
}
17151715

src/ast/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ pub enum Expr {
809809
any: bool,
810810
expr: Box<Expr>,
811811
pattern: Box<Expr>,
812-
escape_char: Option<String>,
812+
escape_char: Option<Value>,
813813
},
814814
/// `ILIKE` (case-insensitive `LIKE`)
815815
ILike {
@@ -819,14 +819,14 @@ pub enum Expr {
819819
any: bool,
820820
expr: Box<Expr>,
821821
pattern: Box<Expr>,
822-
escape_char: Option<String>,
822+
escape_char: Option<Value>,
823823
},
824824
/// SIMILAR TO regex
825825
SimilarTo {
826826
negated: bool,
827827
expr: Box<Expr>,
828828
pattern: Box<Expr>,
829-
escape_char: Option<String>,
829+
escape_char: Option<Value>,
830830
},
831831
/// MySQL: RLIKE regex or REGEXP regex
832832
RLike {
@@ -1488,7 +1488,7 @@ impl fmt::Display for Expr {
14881488
} => match escape_char {
14891489
Some(ch) => write!(
14901490
f,
1491-
"{} {}LIKE {}{} ESCAPE '{}'",
1491+
"{} {}LIKE {}{} ESCAPE {}",
14921492
expr,
14931493
if *negated { "NOT " } else { "" },
14941494
if *any { "ANY " } else { "" },
@@ -1513,7 +1513,7 @@ impl fmt::Display for Expr {
15131513
} => match escape_char {
15141514
Some(ch) => write!(
15151515
f,
1516-
"{} {}ILIKE {}{} ESCAPE '{}'",
1516+
"{} {}ILIKE {}{} ESCAPE {}",
15171517
expr,
15181518
if *negated { "NOT " } else { "" },
15191519
if *any { "ANY" } else { "" },
@@ -1568,7 +1568,7 @@ impl fmt::Display for Expr {
15681568
} => match escape_char {
15691569
Some(ch) => write!(
15701570
f,
1571-
"{} {}SIMILAR TO {} ESCAPE '{}'",
1571+
"{} {}SIMILAR TO {} ESCAPE {}",
15721572
expr,
15731573
if *negated { "NOT " } else { "" },
15741574
pattern,
@@ -9372,12 +9372,12 @@ impl Display for RowAccessPolicy {
93729372
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
93739373
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
93749374
pub struct Tag {
9375-
pub key: Ident,
9375+
pub key: ObjectName,
93769376
pub value: String,
93779377
}
93789378

93799379
impl Tag {
9380-
pub fn new(key: Ident, value: String) -> Self {
9380+
pub fn new(key: ObjectName, value: String) -> Self {
93819381
Self { key, value }
93829382
}
93839383
}

src/dialect/snowflake.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,7 @@ fn parse_column_policy_property(
11891189
parser: &mut Parser,
11901190
with: bool,
11911191
) -> Result<ColumnPolicyProperty, ParserError> {
1192-
let policy_name = parser.parse_identifier()?;
1192+
let policy_name = parser.parse_object_name(false)?;
11931193
let using_columns = if parser.parse_keyword(Keyword::USING) {
11941194
parser.expect_token(&Token::LParen)?;
11951195
let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;

src/parser/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,9 +3654,9 @@ impl<'a> Parser<'a> {
36543654
}
36553655

36563656
/// Parse the `ESCAPE CHAR` portion of `LIKE`, `ILIKE`, and `SIMILAR TO`
3657-
pub fn parse_escape_char(&mut self) -> Result<Option<String>, ParserError> {
3657+
pub fn parse_escape_char(&mut self) -> Result<Option<Value>, ParserError> {
36583658
if self.parse_keyword(Keyword::ESCAPE) {
3659-
Ok(Some(self.parse_literal_string()?))
3659+
Ok(Some(self.parse_value()?.into()))
36603660
} else {
36613661
Ok(None)
36623662
}
@@ -7884,7 +7884,7 @@ impl<'a> Parser<'a> {
78847884
}
78857885

78867886
pub(crate) fn parse_tag(&mut self) -> Result<Tag, ParserError> {
7887-
let name = self.parse_identifier()?;
7887+
let name = self.parse_object_name(false)?;
78887888
self.expect_token(&Token::Eq)?;
78897889
let value = self.parse_literal_string()?;
78907890

tests/sqlparser_common.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,7 +2040,7 @@ fn parse_ilike() {
20402040
pattern: Box::new(Expr::Value(
20412041
(Value::SingleQuotedString("%a".to_string())).with_empty_span()
20422042
)),
2043-
escape_char: Some('^'.to_string()),
2043+
escape_char: Some(Value::SingleQuotedString('^'.to_string())),
20442044
any: false,
20452045
},
20462046
select.selection.unwrap()
@@ -2104,7 +2104,7 @@ fn parse_like() {
21042104
pattern: Box::new(Expr::Value(
21052105
(Value::SingleQuotedString("%a".to_string())).with_empty_span()
21062106
)),
2107-
escape_char: Some('^'.to_string()),
2107+
escape_char: Some(Value::SingleQuotedString('^'.to_string())),
21082108
any: false,
21092109
},
21102110
select.selection.unwrap()
@@ -2167,7 +2167,24 @@ fn parse_similar_to() {
21672167
pattern: Box::new(Expr::Value(
21682168
(Value::SingleQuotedString("%a".to_string())).with_empty_span()
21692169
)),
2170-
escape_char: Some('^'.to_string()),
2170+
escape_char: Some(Value::SingleQuotedString('^'.to_string())),
2171+
},
2172+
select.selection.unwrap()
2173+
);
2174+
2175+
let sql = &format!(
2176+
"SELECT * FROM customers WHERE name {}SIMILAR TO '%a' ESCAPE NULL",
2177+
if negated { "NOT " } else { "" }
2178+
);
2179+
let select = verified_only_select(sql);
2180+
assert_eq!(
2181+
Expr::SimilarTo {
2182+
expr: Box::new(Expr::Identifier(Ident::new("name"))),
2183+
negated,
2184+
pattern: Box::new(Expr::Value(
2185+
(Value::SingleQuotedString("%a".to_string())).with_empty_span()
2186+
)),
2187+
escape_char: Some(Value::Null),
21712188
},
21722189
select.selection.unwrap()
21732190
);
@@ -2185,7 +2202,7 @@ fn parse_similar_to() {
21852202
pattern: Box::new(Expr::Value(
21862203
(Value::SingleQuotedString("%a".to_string())).with_empty_span()
21872204
)),
2188-
escape_char: Some('^'.to_string()),
2205+
escape_char: Some(Value::SingleQuotedString('^'.to_string())),
21892206
})),
21902207
select.selection.unwrap()
21912208
);

tests/sqlparser_snowflake.rs

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ fn test_snowflake_create_table_with_tag() {
270270
assert_eq!("my_table", name.to_string());
271271
assert_eq!(
272272
Some(vec![
273-
Tag::new("A".into(), "TAG A".to_string()),
274-
Tag::new("B".into(), "TAG B".to_string())
273+
Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".to_string()),
274+
Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".to_string())
275275
]),
276276
with_tags
277277
);
@@ -291,8 +291,8 @@ fn test_snowflake_create_table_with_tag() {
291291
assert_eq!("my_table", name.to_string());
292292
assert_eq!(
293293
Some(vec![
294-
Tag::new("A".into(), "TAG A".to_string()),
295-
Tag::new("B".into(), "TAG B".to_string())
294+
Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".to_string()),
295+
Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".to_string())
296296
]),
297297
with_tags
298298
);
@@ -731,7 +731,7 @@ fn test_snowflake_create_table_with_columns_masking_policy() {
731731
option: ColumnOption::Policy(ColumnPolicy::MaskingPolicy(
732732
ColumnPolicyProperty {
733733
with,
734-
policy_name: "p".into(),
734+
policy_name: ObjectName::from(vec![Ident::new("p")]),
735735
using_columns,
736736
}
737737
))
@@ -765,7 +765,7 @@ fn test_snowflake_create_table_with_columns_projection_policy() {
765765
option: ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(
766766
ColumnPolicyProperty {
767767
with,
768-
policy_name: "p".into(),
768+
policy_name: ObjectName::from(vec![Ident::new("p")]),
769769
using_columns: None,
770770
}
771771
))
@@ -802,8 +802,14 @@ fn test_snowflake_create_table_with_columns_tags() {
802802
option: ColumnOption::Tags(TagsColumnOption {
803803
with,
804804
tags: vec![
805-
Tag::new("A".into(), "TAG A".into()),
806-
Tag::new("B".into(), "TAG B".into()),
805+
Tag::new(
806+
ObjectName::from(vec![Ident::new("A")]),
807+
"TAG A".into()
808+
),
809+
Tag::new(
810+
ObjectName::from(vec![Ident::new("B")]),
811+
"TAG B".into()
812+
),
807813
]
808814
}),
809815
}],
@@ -846,7 +852,7 @@ fn test_snowflake_create_table_with_several_column_options() {
846852
option: ColumnOption::Policy(ColumnPolicy::MaskingPolicy(
847853
ColumnPolicyProperty {
848854
with: true,
849-
policy_name: "p1".into(),
855+
policy_name: ObjectName::from(vec![Ident::new("p1")]),
850856
using_columns: Some(vec!["a".into(), "b".into()]),
851857
}
852858
)),
@@ -856,8 +862,14 @@ fn test_snowflake_create_table_with_several_column_options() {
856862
option: ColumnOption::Tags(TagsColumnOption {
857863
with: true,
858864
tags: vec![
859-
Tag::new("A".into(), "TAG A".into()),
860-
Tag::new("B".into(), "TAG B".into()),
865+
Tag::new(
866+
ObjectName::from(vec![Ident::new("A")]),
867+
"TAG A".into()
868+
),
869+
Tag::new(
870+
ObjectName::from(vec![Ident::new("B")]),
871+
"TAG B".into()
872+
),
861873
]
862874
}),
863875
}
@@ -878,7 +890,7 @@ fn test_snowflake_create_table_with_several_column_options() {
878890
option: ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(
879891
ColumnPolicyProperty {
880892
with: false,
881-
policy_name: "p2".into(),
893+
policy_name: ObjectName::from(vec![Ident::new("p2")]),
882894
using_columns: None,
883895
}
884896
)),
@@ -888,8 +900,14 @@ fn test_snowflake_create_table_with_several_column_options() {
888900
option: ColumnOption::Tags(TagsColumnOption {
889901
with: false,
890902
tags: vec![
891-
Tag::new("C".into(), "TAG C".into()),
892-
Tag::new("D".into(), "TAG D".into()),
903+
Tag::new(
904+
ObjectName::from(vec![Ident::new("C")]),
905+
"TAG C".into()
906+
),
907+
Tag::new(
908+
ObjectName::from(vec![Ident::new("D")]),
909+
"TAG D".into()
910+
),
893911
]
894912
}),
895913
}
@@ -942,8 +960,8 @@ fn test_snowflake_create_iceberg_table_all_options() {
942960
with_aggregation_policy.map(|name| name.to_string())
943961
);
944962
assert_eq!(Some(vec![
945-
Tag::new("A".into(), "TAG A".into()),
946-
Tag::new("B".into(), "TAG B".into()),
963+
Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".into()),
964+
Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".into()),
947965
]), with_tags);
948966

949967
}
@@ -4172,3 +4190,17 @@ fn test_snowflake_create_view_with_multiple_column_options() {
41724190
r#"CREATE VIEW X (COL WITH TAG (pii='email') COMMENT 'foobar') AS SELECT * FROM Y"#;
41734191
snowflake().verified_stmt(create_view_with_tag);
41744192
}
4193+
4194+
#[test]
4195+
fn test_snowflake_create_view_with_composite_tag() {
4196+
let create_view_with_tag =
4197+
r#"CREATE VIEW X (COL WITH TAG (foo.bar.baz.pii='email')) AS SELECT * FROM Y"#;
4198+
snowflake().verified_stmt(create_view_with_tag);
4199+
}
4200+
4201+
#[test]
4202+
fn test_snowflake_create_view_with_composite_policy_name() {
4203+
let create_view_with_tag =
4204+
r#"CREATE VIEW X (COL WITH MASKING POLICY foo.bar.baz) AS SELECT * FROM Y"#;
4205+
snowflake().verified_stmt(create_view_with_tag);
4206+
}

0 commit comments

Comments
 (0)