SupportSELECT AS VALUE and SELECT AS STRUCT for BigQuery (#1135)

This commit is contained in:
Lukasz Stefaniak 2024-02-29 13:14:00 +01:00 committed by GitHub
parent 6a9b6f547d
commit 1cf6585649
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 89 additions and 10 deletions

View file

@ -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,

View file

@ -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"),
}
}
}

View file

@ -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,
})
}