Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6e80e5c

Browse files
Add support for SEMANTIC_VIEW table factor (#2009)
1 parent e9eee00 commit 6e80e5c

File tree

7 files changed

+308
-3
lines changed

7 files changed

+308
-3
lines changed

‎src/ast/query.rs‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,31 @@ pub enum TableFactor {
14101410
/// The alias for the table.
14111411
alias: Option<TableAlias>,
14121412
},
1413+
/// Snowflake's SEMANTIC_VIEW function for semantic models.
1414+
///
1415+
/// <https://docs.snowflake.com/en/sql-reference/constructs/semantic_view>
1416+
///
1417+
/// ```sql
1418+
/// SELECT * FROM SEMANTIC_VIEW(
1419+
/// tpch_analysis
1420+
/// DIMENSIONS customer.customer_market_segment
1421+
/// METRICS orders.order_average_value
1422+
/// );
1423+
/// ```
1424+
SemanticView {
1425+
/// The name of the semantic model
1426+
name: ObjectName,
1427+
/// List of dimensions or expression referring to dimensions (e.g. DATE_PART('year', col))
1428+
dimensions: Vec<Expr>,
1429+
/// List of metrics (references to objects like orders.value, value, orders.*)
1430+
metrics: Vec<ObjectName>,
1431+
/// List of facts or expressions referring to facts or dimensions.
1432+
facts: Vec<Expr>,
1433+
/// WHERE clause for filtering
1434+
where_clause: Option<Expr>,
1435+
/// The alias for the table
1436+
alias: Option<TableAlias>,
1437+
},
14131438
}
14141439

14151440
/// The table sample modifier options
@@ -2112,6 +2137,40 @@ impl fmt::Display for TableFactor {
21122137
}
21132138
Ok(())
21142139
}
2140+
TableFactor::SemanticView {
2141+
name,
2142+
dimensions,
2143+
metrics,
2144+
facts,
2145+
where_clause,
2146+
alias,
2147+
} => {
2148+
write!(f, "SEMANTIC_VIEW({name}")?;
2149+
2150+
if !dimensions.is_empty() {
2151+
write!(f, " DIMENSIONS {}", display_comma_separated(dimensions))?;
2152+
}
2153+
2154+
if !metrics.is_empty() {
2155+
write!(f, " METRICS {}", display_comma_separated(metrics))?;
2156+
}
2157+
2158+
if !facts.is_empty() {
2159+
write!(f, " FACTS {}", display_comma_separated(facts))?;
2160+
}
2161+
2162+
if let Some(where_clause) = where_clause {
2163+
write!(f, " WHERE {where_clause}")?;
2164+
}
2165+
2166+
write!(f, ")")?;
2167+
2168+
if let Some(alias) = alias {
2169+
write!(f, " AS {alias}")?;
2170+
}
2171+
2172+
Ok(())
2173+
}
21152174
}
21162175
}
21172176
}

‎src/ast/spans.rs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,23 @@ impl Spanned for TableFactor {
20442044
.chain(symbols.iter().map(|i| i.span()))
20452045
.chain(alias.as_ref().map(|i| i.span())),
20462046
),
2047+
TableFactor::SemanticView {
2048+
name,
2049+
dimensions,
2050+
metrics,
2051+
facts,
2052+
where_clause,
2053+
alias,
2054+
} => union_spans(
2055+
name.0
2056+
.iter()
2057+
.map(|i| i.span())
2058+
.chain(dimensions.iter().map(|d| d.span()))
2059+
.chain(metrics.iter().map(|m| m.span()))
2060+
.chain(facts.iter().map(|f| f.span()))
2061+
.chain(where_clause.as_ref().map(|e| e.span()))
2062+
.chain(alias.as_ref().map(|a| a.span())),
2063+
),
20472064
TableFactor::OpenJsonTable { .. } => Span::empty(),
20482065
}
20492066
}

‎src/dialect/mod.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,20 @@ pub trait Dialect: Debug + Any {
11821182
fn supports_create_table_like_parenthesized(&self) -> bool {
11831183
false
11841184
}
1185+
1186+
/// Returns true if the dialect supports `SEMANTIC_VIEW()` table functions.
1187+
///
1188+
/// ```sql
1189+
/// SELECT * FROM SEMANTIC_VIEW(
1190+
/// model_name
1191+
/// DIMENSIONS customer.name, customer.region
1192+
/// METRICS orders.revenue, orders.count
1193+
/// WHERE customer.active = true
1194+
/// )
1195+
/// ```
1196+
fn supports_semantic_view_table_factor(&self) -> bool {
1197+
false
1198+
}
11851199
}
11861200

11871201
/// This represents the operators for which precedence must be defined

‎src/dialect/snowflake.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,10 @@ impl Dialect for SnowflakeDialect {
566566
fn supports_select_wildcard_exclude(&self) -> bool {
567567
true
568568
}
569+
570+
fn supports_semantic_view_table_factor(&self) -> bool {
571+
true
572+
}
569573
}
570574

571575
// Peeks ahead to identify tokens that are expected after

‎src/keywords.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ define_keywords!(
290290
DETACH,
291291
DETAIL,
292292
DETERMINISTIC,
293+
DIMENSIONS,
293294
DIRECTORY,
294295
DISABLE,
295296
DISCARD,
@@ -359,6 +360,7 @@ define_keywords!(
359360
EXTERNAL,
360361
EXTERNAL_VOLUME,
361362
EXTRACT,
363+
FACTS,
362364
FAIL,
363365
FAILOVER,
364366
FALSE,
@@ -566,6 +568,7 @@ define_keywords!(
566568
METADATA,
567569
METHOD,
568570
METRIC,
571+
METRICS,
569572
MICROSECOND,
570573
MICROSECONDS,
571574
MILLENIUM,
@@ -828,6 +831,7 @@ define_keywords!(
828831
SECURITY,
829832
SEED,
830833
SELECT,
834+
SEMANTIC_VIEW,
831835
SEMI,
832836
SENSITIVE,
833837
SEPARATOR,

‎src/parser/mod.rs‎

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4245,17 +4245,32 @@ impl<'a> Parser<'a> {
42454245
/// not be efficient as it does a loop on the tokens with `peek_nth_token`
42464246
/// each time.
42474247
pub fn parse_keyword_with_tokens(&mut self, expected: Keyword, tokens: &[Token]) -> bool {
4248+
self.keyword_with_tokens(expected, tokens, true)
4249+
}
4250+
4251+
/// Peeks to see if the current token is the `expected` keyword followed by specified tokens
4252+
/// without consuming them.
4253+
///
4254+
/// See [Self::parse_keyword_with_tokens] for details.
4255+
pub(crate) fn peek_keyword_with_tokens(&mut self, expected: Keyword, tokens: &[Token]) -> bool {
4256+
self.keyword_with_tokens(expected, tokens, false)
4257+
}
4258+
4259+
fn keyword_with_tokens(&mut self, expected: Keyword, tokens: &[Token], consume: bool) -> bool {
42484260
match &self.peek_token_ref().token {
42494261
Token::Word(w) if expected == w.keyword => {
42504262
for (idx, token) in tokens.iter().enumerate() {
42514263
if self.peek_nth_token_ref(idx + 1).token != *token {
42524264
return false;
42534265
}
42544266
}
4255-
// consume all tokens
4256-
for _ in 0..(tokens.len() + 1) {
4257-
self.advance_token();
4267+
4268+
if consume {
4269+
for _ in 0..(tokens.len() + 1) {
4270+
self.advance_token();
4271+
}
42584272
}
4273+
42594274
true
42604275
}
42614276
_ => false,
@@ -13397,6 +13412,7 @@ impl<'a> Parser<'a> {
1339713412
| TableFactor::Pivot { alias, .. }
1339813413
| TableFactor::Unpivot { alias, .. }
1339913414
| TableFactor::MatchRecognize { alias, .. }
13415+
| TableFactor::SemanticView { alias, .. }
1340013416
| TableFactor::NestedJoin { alias, .. } => {
1340113417
// but not `FROM (mytable AS alias1) AS alias2`.
1340213418
if let Some(inner_alias) = alias {
@@ -13511,6 +13527,10 @@ impl<'a> Parser<'a> {
1351113527
} else if self.parse_keyword_with_tokens(Keyword::XMLTABLE, &[Token::LParen]) {
1351213528
self.prev_token();
1351313529
self.parse_xml_table_factor()
13530+
} else if self.dialect.supports_semantic_view_table_factor()
13531+
&& self.peek_keyword_with_tokens(Keyword::SEMANTIC_VIEW, &[Token::LParen])
13532+
{
13533+
self.parse_semantic_view_table_factor()
1351413534
} else {
1351513535
let name = self.parse_object_name(true)?;
1351613536

@@ -13842,6 +13862,70 @@ impl<'a> Parser<'a> {
1384213862
Ok(XmlPassingClause { arguments })
1384313863
}
1384413864

13865+
/// Parse a [TableFactor::SemanticView]
13866+
fn parse_semantic_view_table_factor(&mut self) -> Result<TableFactor, ParserError> {
13867+
self.expect_keyword(Keyword::SEMANTIC_VIEW)?;
13868+
self.expect_token(&Token::LParen)?;
13869+
13870+
let name = self.parse_object_name(true)?;
13871+
13872+
// Parse DIMENSIONS, METRICS, FACTS and WHERE clauses in flexible order
13873+
let mut dimensions = Vec::new();
13874+
let mut metrics = Vec::new();
13875+
let mut facts = Vec::new();
13876+
let mut where_clause = None;
13877+
13878+
while self.peek_token().token != Token::RParen {
13879+
if self.parse_keyword(Keyword::DIMENSIONS) {
13880+
if !dimensions.is_empty() {
13881+
return Err(ParserError::ParserError(
13882+
"DIMENSIONS clause can only be specified once".to_string(),
13883+
));
13884+
}
13885+
dimensions = self.parse_comma_separated(Parser::parse_expr)?;
13886+
} else if self.parse_keyword(Keyword::METRICS) {
13887+
if !metrics.is_empty() {
13888+
return Err(ParserError::ParserError(
13889+
"METRICS clause can only be specified once".to_string(),
13890+
));
13891+
}
13892+
metrics = self.parse_comma_separated(|parser| parser.parse_object_name(true))?;
13893+
} else if self.parse_keyword(Keyword::FACTS) {
13894+
if !facts.is_empty() {
13895+
return Err(ParserError::ParserError(
13896+
"FACTS clause can only be specified once".to_string(),
13897+
));
13898+
}
13899+
facts = self.parse_comma_separated(Parser::parse_expr)?;
13900+
} else if self.parse_keyword(Keyword::WHERE) {
13901+
if where_clause.is_some() {
13902+
return Err(ParserError::ParserError(
13903+
"WHERE clause can only be specified once".to_string(),
13904+
));
13905+
}
13906+
where_clause = Some(self.parse_expr()?);
13907+
} else {
13908+
return parser_err!(
13909+
"Expected one of DIMENSIONS, METRICS, FACTS or WHERE",
13910+
self.peek_token().span.start
13911+
)?;
13912+
}
13913+
}
13914+
13915+
self.expect_token(&Token::RParen)?;
13916+
13917+
let alias = self.maybe_parse_table_alias()?;
13918+
13919+
Ok(TableFactor::SemanticView {
13920+
name,
13921+
dimensions,
13922+
metrics,
13923+
facts,
13924+
where_clause,
13925+
alias,
13926+
})
13927+
}
13928+
1384513929
fn parse_match_recognize(&mut self, table: TableFactor) -> Result<TableFactor, ParserError> {
1384613930
self.expect_token(&Token::LParen)?;
1384713931

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /