mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-08 01:15:00 +00:00
Support Databricks struct literal (#1542)
This commit is contained in:
parent
4ab3ab9147
commit
bd750dfada
7 changed files with 71 additions and 9 deletions
|
@ -931,12 +931,14 @@ pub enum Expr {
|
||||||
Rollup(Vec<Vec<Expr>>),
|
Rollup(Vec<Vec<Expr>>),
|
||||||
/// ROW / TUPLE a single value, such as `SELECT (1, 2)`
|
/// ROW / TUPLE a single value, such as `SELECT (1, 2)`
|
||||||
Tuple(Vec<Expr>),
|
Tuple(Vec<Expr>),
|
||||||
/// `BigQuery` specific `Struct` literal expression [1]
|
/// `Struct` literal expression
|
||||||
/// Syntax:
|
/// Syntax:
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// STRUCT<[field_name] field_type, ...>( expr1 [, ... ])
|
/// STRUCT<[field_name] field_type, ...>( expr1 [, ... ])
|
||||||
|
///
|
||||||
|
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type)
|
||||||
|
/// [Databricks](https://docs.databricks.com/en/sql/language-manual/functions/struct.html)
|
||||||
/// ```
|
/// ```
|
||||||
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
|
|
||||||
Struct {
|
Struct {
|
||||||
/// Struct values.
|
/// Struct values.
|
||||||
values: Vec<Expr>,
|
values: Vec<Expr>,
|
||||||
|
|
|
@ -72,4 +72,9 @@ impl Dialect for BigQueryDialect {
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
fn require_interval_qualifier(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#constructing_a_struct
|
||||||
|
fn supports_struct_literal(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,4 +59,9 @@ impl Dialect for DatabricksDialect {
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
fn require_interval_qualifier(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See https://docs.databricks.com/en/sql/language-manual/functions/struct.html
|
||||||
|
fn supports_struct_literal(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,4 +123,8 @@ impl Dialect for GenericDialect {
|
||||||
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
|
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_struct_literal(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,6 +375,16 @@ pub trait Dialect: Debug + Any {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if the dialect supports the STRUCT literal
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```sql
|
||||||
|
/// SELECT STRUCT(1 as one, 'foo' as foo, false)
|
||||||
|
/// ```
|
||||||
|
fn supports_struct_literal(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Dialect-specific infix parser override
|
/// Dialect-specific infix parser override
|
||||||
///
|
///
|
||||||
/// This method is called to parse the next infix expression.
|
/// This method is called to parse the next infix expression.
|
||||||
|
|
|
@ -1123,9 +1123,8 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::MATCH if dialect_of!(self is MySqlDialect | GenericDialect) => {
|
Keyword::MATCH if dialect_of!(self is MySqlDialect | GenericDialect) => {
|
||||||
Ok(Some(self.parse_match_against()?))
|
Ok(Some(self.parse_match_against()?))
|
||||||
}
|
}
|
||||||
Keyword::STRUCT if dialect_of!(self is BigQueryDialect | GenericDialect) => {
|
Keyword::STRUCT if self.dialect.supports_struct_literal() => {
|
||||||
self.prev_token();
|
Ok(Some(self.parse_struct_literal()?))
|
||||||
Ok(Some(self.parse_bigquery_struct_literal()?))
|
|
||||||
}
|
}
|
||||||
Keyword::PRIOR if matches!(self.state, ParserState::ConnectBy) => {
|
Keyword::PRIOR if matches!(self.state, ParserState::ConnectBy) => {
|
||||||
let expr = self.parse_subexpr(self.dialect.prec_value(Precedence::PlusMinus))?;
|
let expr = self.parse_subexpr(self.dialect.prec_value(Precedence::PlusMinus))?;
|
||||||
|
@ -2383,7 +2382,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bigquery specific: Parse a struct literal
|
|
||||||
/// Syntax
|
/// Syntax
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// -- typed
|
/// -- typed
|
||||||
|
@ -2391,7 +2389,9 @@ impl<'a> Parser<'a> {
|
||||||
/// -- typeless
|
/// -- typeless
|
||||||
/// STRUCT( expr1 [AS field_name] [, ... ])
|
/// STRUCT( expr1 [AS field_name] [, ... ])
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_bigquery_struct_literal(&mut self) -> Result<Expr, ParserError> {
|
fn parse_struct_literal(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
// Parse the fields definition if exist `<[field_name] field_type, ...>`
|
||||||
|
self.prev_token();
|
||||||
let (fields, trailing_bracket) =
|
let (fields, trailing_bracket) =
|
||||||
self.parse_struct_type_def(Self::parse_struct_field_def)?;
|
self.parse_struct_type_def(Self::parse_struct_field_def)?;
|
||||||
if trailing_bracket.0 {
|
if trailing_bracket.0 {
|
||||||
|
@ -2401,6 +2401,7 @@ impl<'a> Parser<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the struct values `(expr1 [, ... ])`
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let values = self
|
let values = self
|
||||||
.parse_comma_separated(|parser| parser.parse_struct_field_expr(!fields.is_empty()))?;
|
.parse_comma_separated(|parser| parser.parse_struct_field_expr(!fields.is_empty()))?;
|
||||||
|
@ -2409,13 +2410,13 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Expr::Struct { values, fields })
|
Ok(Expr::Struct { values, fields })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an expression value for a bigquery struct [1]
|
/// Parse an expression value for a struct literal
|
||||||
/// Syntax
|
/// Syntax
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// expr [AS name]
|
/// expr [AS name]
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Parameter typed_syntax is set to true if the expression
|
/// For biquery [1], Parameter typed_syntax is set to true if the expression
|
||||||
/// is to be parsed as a field expression declared using typed
|
/// is to be parsed as a field expression declared using typed
|
||||||
/// struct syntax [2], and false if using typeless struct syntax [3].
|
/// struct syntax [2], and false if using typeless struct syntax [3].
|
||||||
///
|
///
|
||||||
|
|
|
@ -278,3 +278,38 @@ fn parse_use() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_databricks_struct_function() {
|
||||||
|
assert_eq!(
|
||||||
|
databricks_and_generic()
|
||||||
|
.verified_only_select("SELECT STRUCT(1, 'foo')")
|
||||||
|
.projection[0],
|
||||||
|
SelectItem::UnnamedExpr(Expr::Struct {
|
||||||
|
values: vec![
|
||||||
|
Expr::Value(number("1")),
|
||||||
|
Expr::Value(Value::SingleQuotedString("foo".to_string()))
|
||||||
|
],
|
||||||
|
fields: vec![]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
databricks_and_generic()
|
||||||
|
.verified_only_select("SELECT STRUCT(1 AS one, 'foo' AS foo, false)")
|
||||||
|
.projection[0],
|
||||||
|
SelectItem::UnnamedExpr(Expr::Struct {
|
||||||
|
values: vec![
|
||||||
|
Expr::Named {
|
||||||
|
expr: Expr::Value(number("1")).into(),
|
||||||
|
name: Ident::new("one")
|
||||||
|
},
|
||||||
|
Expr::Named {
|
||||||
|
expr: Expr::Value(Value::SingleQuotedString("foo".to_string())).into(),
|
||||||
|
name: Ident::new("foo")
|
||||||
|
},
|
||||||
|
Expr::Value(Value::Boolean(false))
|
||||||
|
],
|
||||||
|
fields: vec![]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue