mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
SupportSELECT AS VALUE
and SELECT AS STRUCT
for BigQuery (#1135)
This commit is contained in:
parent
6a9b6f547d
commit
1cf6585649
10 changed files with 89 additions and 10 deletions
|
@ -44,8 +44,8 @@ pub use self::query::{
|
|||
JsonTableColumnErrorHandling, LateralView, LockClause, LockType, NamedWindowDefinition,
|
||||
NonBlock, Offset, OffsetRows, OrderByExpr, Query, RenameSelectItem, ReplaceSelectElement,
|
||||
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Table,
|
||||
TableAlias, TableFactor, TableVersion, TableWithJoins, Top, TopQuantity, Values,
|
||||
WildcardAdditionalOptions, With,
|
||||
TableAlias, TableFactor, TableVersion, TableWithJoins, Top, TopQuantity, ValueTableMode,
|
||||
Values, WildcardAdditionalOptions, With,
|
||||
};
|
||||
pub use self::value::{
|
||||
escape_quoted_string, DateTimeField, DollarQuotedString, TrimWhereField, Value,
|
||||
|
|
|
@ -245,11 +245,18 @@ pub struct Select {
|
|||
pub named_window: Vec<NamedWindowDefinition>,
|
||||
/// QUALIFY (Snowflake)
|
||||
pub qualify: Option<Expr>,
|
||||
/// BigQuery syntax: `SELECT AS VALUE | SELECT AS STRUCT`
|
||||
pub value_table_mode: Option<ValueTableMode>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Select {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "SELECT")?;
|
||||
|
||||
if let Some(value_table_mode) = self.value_table_mode {
|
||||
write!(f, " {value_table_mode}")?;
|
||||
}
|
||||
|
||||
if let Some(ref distinct) = self.distinct {
|
||||
write!(f, " {distinct}")?;
|
||||
}
|
||||
|
@ -1574,3 +1581,24 @@ impl fmt::Display for JsonTableColumnErrorHandling {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// BigQuery supports ValueTables which have 2 modes:
|
||||
/// `SELECT AS STRUCT`
|
||||
/// `SELECT AS VALUE`
|
||||
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#value_tables>
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum ValueTableMode {
|
||||
AsStruct,
|
||||
AsValue,
|
||||
}
|
||||
|
||||
impl fmt::Display for ValueTableMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
|
||||
ValueTableMode::AsValue => write!(f, "AS VALUE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6826,6 +6826,19 @@ impl<'a> Parser<'a> {
|
|||
/// Parse a restricted `SELECT` statement (no CTEs / `UNION` / `ORDER BY`),
|
||||
/// assuming the initial `SELECT` was already consumed
|
||||
pub fn parse_select(&mut self) -> Result<Select, ParserError> {
|
||||
let value_table_mode =
|
||||
if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::AS) {
|
||||
if self.parse_keyword(Keyword::VALUE) {
|
||||
Some(ValueTableMode::AsValue)
|
||||
} else if self.parse_keyword(Keyword::STRUCT) {
|
||||
Some(ValueTableMode::AsStruct)
|
||||
} else {
|
||||
self.expected("VALUE or STRUCT", self.peek_token())?
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let distinct = self.parse_all_or_distinct()?;
|
||||
|
||||
let top = if self.parse_keyword(Keyword::TOP) {
|
||||
|
@ -6962,6 +6975,7 @@ impl<'a> Parser<'a> {
|
|||
having,
|
||||
named_window: named_windows,
|
||||
qualify,
|
||||
value_table_mode,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1352,3 +1352,19 @@ fn test_bigquery_trim() {
|
|||
bigquery().parse_sql_statements(error_sql).unwrap_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_as_struct() {
|
||||
bigquery().verified_only_select("SELECT * FROM (SELECT AS VALUE STRUCT(123 AS a, false AS b))");
|
||||
let select = bigquery().verified_only_select("SELECT AS STRUCT 1 AS a, 2 AS b");
|
||||
assert_eq!(Some(ValueTableMode::AsStruct), select.value_table_mode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_as_value() {
|
||||
bigquery().verified_only_select(
|
||||
"SELECT * FROM (SELECT AS VALUE STRUCT(5 AS star_rating, false AS up_down_rating))",
|
||||
);
|
||||
let select = bigquery().verified_only_select("SELECT AS VALUE STRUCT(1 AS a, 2 AS b) AS xyz");
|
||||
assert_eq!(Some(ValueTableMode::AsValue), select.value_table_mode);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ fn parse_map_access_expr() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
},
|
||||
select
|
||||
);
|
||||
|
|
|
@ -400,7 +400,8 @@ fn parse_update_set_from() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -4212,6 +4213,7 @@ fn test_parse_named_window() {
|
|||
),
|
||||
],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
};
|
||||
assert_eq!(actual_select_only, expected);
|
||||
}
|
||||
|
@ -4567,6 +4569,7 @@ fn parse_interval_and_or_xor() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -6550,6 +6553,7 @@ fn lateral_function() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
};
|
||||
assert_eq!(actual_select_only, expected);
|
||||
}
|
||||
|
@ -7193,6 +7197,7 @@ fn parse_merge() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
|
|
@ -177,6 +177,7 @@ fn test_select_union_by_name() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
right: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
||||
distinct: None,
|
||||
|
@ -211,6 +212,7 @@ fn test_select_union_by_name() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
});
|
||||
assert_eq!(ast.body, expected);
|
||||
|
|
|
@ -112,7 +112,8 @@ fn parse_create_procedure() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
})))
|
||||
}))],
|
||||
params: Some(vec![
|
||||
|
@ -595,7 +596,8 @@ fn parse_substring_in_select() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
|
|
@ -785,7 +785,8 @@ fn parse_escaped_quote_identifiers_with_escape() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -829,7 +830,8 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -870,7 +872,8 @@ fn parse_escaped_backticks_with_escape() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -911,7 +914,8 @@ fn parse_escaped_backticks_with_no_escape() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -1581,6 +1585,7 @@ fn parse_select_with_numeric_prefix_column_name() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
})))
|
||||
);
|
||||
}
|
||||
|
@ -1631,6 +1636,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
})))
|
||||
);
|
||||
}
|
||||
|
@ -1841,7 +1847,8 @@ fn parse_substring_in_select() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -2143,6 +2150,7 @@ fn parse_hex_string_introducer() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
into: None
|
||||
}))),
|
||||
order_by: vec![],
|
||||
|
|
|
@ -1082,6 +1082,7 @@ fn parse_copy_to() {
|
|||
distribute_by: vec![],
|
||||
sort_by: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
|
@ -2139,6 +2140,7 @@ fn parse_array_subquery_expr() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
right: Box::new(SetExpr::Select(Box::new(Select {
|
||||
distinct: None,
|
||||
|
@ -2155,6 +2157,7 @@ fn parse_array_subquery_expr() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
}),
|
||||
order_by: vec![],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue