From 27307128fd08cd226a33e1c513bd8bb833575027 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sat, 9 Mar 2024 13:30:15 -0800 Subject: [PATCH 1/3] sigma element table factor --- src/ast/query.rs | 12 ++++++++++++ src/keywords.rs | 1 + src/parser/mod.rs | 13 +++++++++++++ tests/sqlparser_sigma.rs | 30 ++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 tests/sqlparser_sigma.rs diff --git a/src/ast/query.rs b/src/ast/query.rs index d7037ce4c..04309d9b7 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -761,6 +761,11 @@ pub enum TableFactor { /// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL. partitions: Vec, }, + /// A reference to an element in a Sigma workbook. + SigmaElement { + element: Ident, + alias: Option, + }, Derived { lateral: bool, subquery: Box, @@ -887,6 +892,13 @@ impl fmt::Display for TableFactor { } Ok(()) } + TableFactor::SigmaElement { element, alias } => { + write!(f, "@sigma.{element}")?; + if let Some(alias) = alias { + write!(f, " AS {alias}")?; + } + Ok(()) + } TableFactor::Derived { lateral, subquery, diff --git a/src/keywords.rs b/src/keywords.rs index 3621961bc..b3208ffeb 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -612,6 +612,7 @@ define_keywords!( SETS, SHARE, SHOW, + SIGMA, SIMILAR, SKIP, SLOW, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f9ca62f8d..14205ab87 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7985,6 +7985,7 @@ impl<'a> Parser<'a> { match &mut table_and_joins.relation { TableFactor::Derived { alias, .. } | TableFactor::Table { alias, .. } + | TableFactor::SigmaElement { alias, .. } | TableFactor::Function { alias, .. } | TableFactor::UNNEST { alias, .. } | TableFactor::JsonTable { alias, .. } @@ -8062,6 +8063,18 @@ impl<'a> Parser<'a> { columns, alias, }) + } else if self + .maybe_parse(|p| { + p.expect_token(&Token::AtSign)?; + p.expect_keyword(Keyword::SIGMA)?; + Ok(()) + }) + .is_some() + { + self.expect_token(&Token::Period)?; + let element = self.parse_identifier(true)?; + let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; + Ok(TableFactor::SigmaElement { element, alias }) } else { let name = self.parse_object_name(true)?; diff --git a/tests/sqlparser_sigma.rs b/tests/sqlparser_sigma.rs new file mode 100644 index 000000000..38dd7060d --- /dev/null +++ b/tests/sqlparser_sigma.rs @@ -0,0 +1,30 @@ +#![warn(clippy::all)] + +use sqlparser::ast::*; +use sqlparser::dialect::SnowflakeDialect; +use test_utils::*; + +#[macro_use] +mod test_utils; + +fn snowflake() -> TestedDialects { + TestedDialects { + dialects: vec![Box::new(SnowflakeDialect {})], + options: None, + } +} +#[test] +fn parse_sigma() { + let sql = "SELECT my_column FROM @sigma.my_element"; + let select = snowflake().verified_only_select(sql); + assert_eq!( + select.from, + vec![TableWithJoins { + relation: TableFactor::SigmaElement { + element: Ident::new("my_element"), + alias: None + }, + joins: vec![] + }] + ) +} From 1a85f68cc44c23bfcbf145cad99d82563842d292 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Mar 2024 14:36:00 -0700 Subject: [PATCH 2/3] support for parameter references --- src/ast/mod.rs | 3 +++ src/parser/mod.rs | 4 ++++ tests/sqlparser_sigma.rs | 10 +++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 28125768c..acc294c09 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -374,6 +374,8 @@ pub enum Expr { Identifier(Ident), /// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col` CompoundIdentifier(Vec), + /// A reference to a Sigma scalar value, e.g. `@sigma.my_parameter`. + SigmaParameter(Ident), /// JSON access (postgres) eg: data->'tags' JsonAccess { left: Box, @@ -752,6 +754,7 @@ impl fmt::Display for Expr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Expr::Identifier(s) => write!(f, "{s}"), + Expr::SigmaParameter(s) => write!(f, "@sigma.{s}"), Expr::MapAccess { column, keys } => { write!(f, "{column}")?; for k in keys { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 14205ab87..b015013d2 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1050,6 +1050,10 @@ impl<'a> Parser<'a> { }, // End of Token::Word // array `[1, 2, 3]` Token::LBracket => self.parse_array_expr(false), + Token::AtSign if self.parse_keyword(Keyword::SIGMA) => { + self.expect_token(&Token::Period)?; + Ok(Expr::SigmaParameter(self.parse_identifier(false)?)) + } tok @ Token::Minus | tok @ Token::Plus => { let op = if tok == Token::Plus { UnaryOperator::Plus diff --git a/tests/sqlparser_sigma.rs b/tests/sqlparser_sigma.rs index 38dd7060d..0a28b331a 100644 --- a/tests/sqlparser_sigma.rs +++ b/tests/sqlparser_sigma.rs @@ -15,7 +15,7 @@ fn snowflake() -> TestedDialects { } #[test] fn parse_sigma() { - let sql = "SELECT my_column FROM @sigma.my_element"; + let sql = "SELECT my_column FROM @sigma.my_element WHERE my_column <> @sigma.param_filter"; let select = snowflake().verified_only_select(sql); assert_eq!( select.from, @@ -26,5 +26,13 @@ fn parse_sigma() { }, joins: vec![] }] + ); + assert_eq!( + select.selection, + Some(Expr::BinaryOp { + left: Box::new(Expr::Identifier(Ident::new("my_column"))), + op: BinaryOperator::NotEq, + right: Box::new(Expr::SigmaParameter(Ident::new("param_filter"))), + }) ) } From 0037d8b6b4638993aff458deb0de6feb1c294652 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Mon, 18 Mar 2024 08:32:38 -0700 Subject: [PATCH 3/3] clippy --- src/parser/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b015013d2..def6637d7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8067,14 +8067,7 @@ impl<'a> Parser<'a> { columns, alias, }) - } else if self - .maybe_parse(|p| { - p.expect_token(&Token::AtSign)?; - p.expect_keyword(Keyword::SIGMA)?; - Ok(()) - }) - .is_some() - { + } else if self.parse_sigma_directive() { self.expect_token(&Token::Period)?; let element = self.parse_identifier(true)?; let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; @@ -8135,6 +8128,15 @@ impl<'a> Parser<'a> { } } + pub fn parse_sigma_directive(&mut self) -> bool { + self.maybe_parse(|p| { + p.expect_token(&Token::AtSign)?; + p.expect_keyword(Keyword::SIGMA)?; + Ok(()) + }) + .is_some() + } + /// Parse a given table version specifier. /// /// For now it only supports timestamp versioning for BigQuery and MSSQL dialects.