Skip to content

Commit 069304c

Browse files
bombsimonsolontsev
authored andcommitted
Support DISTINCT AS { STRUCT | VALUE } for BigQuery (apache#1880)
1 parent 4775335 commit 069304c

File tree

3 files changed

+69
-18
lines changed

3 files changed

+69
-18
lines changed

src/ast/query.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3338,22 +3338,28 @@ impl fmt::Display for OpenJsonTableColumn {
33383338
}
33393339

33403340
/// BigQuery supports ValueTables which have 2 modes:
3341-
/// `SELECT AS STRUCT`
3342-
/// `SELECT AS VALUE`
3341+
/// `SELECT [ALL | DISTINCT] AS STRUCT`
3342+
/// `SELECT [ALL | DISTINCT] AS VALUE`
3343+
///
33433344
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#value_tables>
3345+
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_list>
33443346
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
33453347
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33463348
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
33473349
pub enum ValueTableMode {
33483350
AsStruct,
33493351
AsValue,
3352+
DistinctAsStruct,
3353+
DistinctAsValue,
33503354
}
33513355

33523356
impl fmt::Display for ValueTableMode {
33533357
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33543358
match self {
33553359
ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
33563360
ValueTableMode::AsValue => write!(f, "AS VALUE"),
3361+
ValueTableMode::DistinctAsStruct => write!(f, "DISTINCT AS STRUCT"),
3362+
ValueTableMode::DistinctAsValue => write!(f, "DISTINCT AS VALUE"),
33573363
}
33583364
}
33593365
}

src/parser/mod.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11514,18 +11514,7 @@ impl<'a> Parser<'a> {
1151411514
}
1151511515

1151611516
let select_token = self.expect_keyword(Keyword::SELECT)?;
11517-
let value_table_mode =
11518-
if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::AS) {
11519-
if self.parse_keyword(Keyword::VALUE) {
11520-
Some(ValueTableMode::AsValue)
11521-
} else if self.parse_keyword(Keyword::STRUCT) {
11522-
Some(ValueTableMode::AsStruct)
11523-
} else {
11524-
self.expected("VALUE or STRUCT", self.peek_token())?
11525-
}
11526-
} else {
11527-
None
11528-
};
11517+
let value_table_mode = self.parse_value_table_mode()?;
1152911518

1153011519
let mut top_before_distinct = false;
1153111520
let mut top = None;
@@ -11701,6 +11690,32 @@ impl<'a> Parser<'a> {
1170111690
})
1170211691
}
1170311692

11693+
fn parse_value_table_mode(&mut self) -> Result<Option<ValueTableMode>, ParserError> {
11694+
if !dialect_of!(self is BigQueryDialect) {
11695+
return Ok(None);
11696+
}
11697+
11698+
let mode = if self.parse_keywords(&[Keyword::DISTINCT, Keyword::AS, Keyword::VALUE]) {
11699+
Some(ValueTableMode::DistinctAsValue)
11700+
} else if self.parse_keywords(&[Keyword::DISTINCT, Keyword::AS, Keyword::STRUCT]) {
11701+
Some(ValueTableMode::DistinctAsStruct)
11702+
} else if self.parse_keywords(&[Keyword::AS, Keyword::VALUE])
11703+
|| self.parse_keywords(&[Keyword::ALL, Keyword::AS, Keyword::VALUE])
11704+
{
11705+
Some(ValueTableMode::AsValue)
11706+
} else if self.parse_keywords(&[Keyword::AS, Keyword::STRUCT])
11707+
|| self.parse_keywords(&[Keyword::ALL, Keyword::AS, Keyword::STRUCT])
11708+
{
11709+
Some(ValueTableMode::AsStruct)
11710+
} else if self.parse_keyword(Keyword::AS) {
11711+
self.expected("VALUE or STRUCT", self.peek_token())?
11712+
} else {
11713+
None
11714+
};
11715+
11716+
Ok(mode)
11717+
}
11718+
1170411719
/// Invoke `f` after first setting the parser's `ParserState` to `state`.
1170511720
///
1170611721
/// Upon return, restores the parser's state to what it started at.

tests/sqlparser_bigquery.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,16 +2313,46 @@ fn bigquery_select_expr_star() {
23132313

23142314
#[test]
23152315
fn test_select_as_struct() {
2316-
bigquery().verified_only_select("SELECT * FROM (SELECT AS VALUE STRUCT(123 AS a, false AS b))");
2316+
for (sql, parse_to) in [
2317+
(
2318+
"SELECT * FROM (SELECT AS STRUCT STRUCT(123 AS a, false AS b))",
2319+
"SELECT * FROM (SELECT AS STRUCT STRUCT(123 AS a, false AS b))",
2320+
),
2321+
(
2322+
"SELECT * FROM (SELECT DISTINCT AS STRUCT STRUCT(123 AS a, false AS b))",
2323+
"SELECT * FROM (SELECT DISTINCT AS STRUCT STRUCT(123 AS a, false AS b))",
2324+
),
2325+
(
2326+
"SELECT * FROM (SELECT ALL AS STRUCT STRUCT(123 AS a, false AS b))",
2327+
"SELECT * FROM (SELECT AS STRUCT STRUCT(123 AS a, false AS b))",
2328+
),
2329+
] {
2330+
bigquery().one_statement_parses_to(sql, parse_to);
2331+
}
2332+
23172333
let select = bigquery().verified_only_select("SELECT AS STRUCT 1 AS a, 2 AS b");
23182334
assert_eq!(Some(ValueTableMode::AsStruct), select.value_table_mode);
23192335
}
23202336

23212337
#[test]
23222338
fn test_select_as_value() {
2323-
bigquery().verified_only_select(
2324-
"SELECT * FROM (SELECT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2325-
);
2339+
for (sql, parse_to) in [
2340+
(
2341+
"SELECT * FROM (SELECT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2342+
"SELECT * FROM (SELECT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2343+
),
2344+
(
2345+
"SELECT * FROM (SELECT DISTINCT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2346+
"SELECT * FROM (SELECT DISTINCT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2347+
),
2348+
(
2349+
"SELECT * FROM (SELECT ALL AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2350+
"SELECT * FROM (SELECT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
2351+
),
2352+
] {
2353+
bigquery().one_statement_parses_to(sql, parse_to);
2354+
}
2355+
23262356
let select = bigquery().verified_only_select("SELECT AS VALUE STRUCT(1 AS a, 2 AS b) AS xyz");
23272357
assert_eq!(Some(ValueTableMode::AsValue), select.value_table_mode);
23282358
}

0 commit comments

Comments
 (0)