Snowflake: support for object constants (#1223)

This commit is contained in:
Joey Hain 2024-04-26 11:01:33 -07:00 committed by GitHub
parent 2490034948
commit deaa6d8151
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 81 additions and 1 deletions

View file

@ -37,4 +37,11 @@ impl Dialect for DuckDbDialect {
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
true
}
// DuckDB uses this syntax for `STRUCT`s.
//
// https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
fn supports_dictionary_syntax(&self) -> bool {
true
}
}

View file

@ -46,4 +46,8 @@ impl Dialect for GenericDialect {
fn supports_start_transaction_modifier(&self) -> bool {
true
}
fn supports_dictionary_syntax(&self) -> bool {
true
}
}

View file

@ -170,6 +170,11 @@ pub trait Dialect: Debug + Any {
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
false
}
/// Returns true if the dialect supports defining structs or objects using a
/// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
fn supports_dictionary_syntax(&self) -> bool {
false
}
/// Returns true if the dialect has a CONVERT function which accepts a type first
/// and an expression second, e.g. `CONVERT(varchar, 1)`
fn convert_type_before_value(&self) -> bool {

View file

@ -59,6 +59,14 @@ impl Dialect for SnowflakeDialect {
true
}
// Snowflake uses this syntax for "object constants" (the values of which
// are not actually required to be constants).
//
// https://docs.snowflake.com/en/sql-reference/data-types-semistructured#label-object-constant
fn supports_dictionary_syntax(&self) -> bool {
true
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::CREATE) {
// possibly CREATE STAGE

View file

@ -1192,7 +1192,7 @@ impl<'a> Parser<'a> {
self.prev_token();
Ok(Expr::Value(self.parse_value()?))
}
Token::LBrace if dialect_of!(self is DuckDbDialect | GenericDialect) => {
Token::LBrace if self.dialect.supports_dictionary_syntax() => {
self.prev_token();
self.parse_duckdb_struct_literal()
}

View file

@ -9408,3 +9408,59 @@ fn insert_into_with_parentheses() {
};
dialects.verified_stmt("INSERT INTO t1 (id, name) (SELECT t2.id, t2.name FROM t2)");
}
#[test]
fn test_dictionary_syntax() {
fn check(sql: &str, expect: Expr) {
assert_eq!(
all_dialects_where(|d| d.supports_dictionary_syntax()).verified_expr(sql),
expect
);
}
check(
"{'Alberta': 'Edmonton', 'Manitoba': 'Winnipeg'}",
Expr::Dictionary(vec![
DictionaryField {
key: Ident::with_quote('\'', "Alberta"),
value: Box::new(Expr::Value(Value::SingleQuotedString(
"Edmonton".to_owned(),
))),
},
DictionaryField {
key: Ident::with_quote('\'', "Manitoba"),
value: Box::new(Expr::Value(Value::SingleQuotedString(
"Winnipeg".to_owned(),
))),
},
]),
);
check(
"{'start': CAST('2023-04-01' AS TIMESTAMP), 'end': CAST('2023-04-05' AS TIMESTAMP)}",
Expr::Dictionary(vec![
DictionaryField {
key: Ident::with_quote('\'', "start"),
value: Box::new(Expr::Cast {
kind: CastKind::Cast,
expr: Box::new(Expr::Value(Value::SingleQuotedString(
"2023-04-01".to_owned(),
))),
data_type: DataType::Timestamp(None, TimezoneInfo::None),
format: None,
}),
},
DictionaryField {
key: Ident::with_quote('\'', "end"),
value: Box::new(Expr::Cast {
kind: CastKind::Cast,
expr: Box::new(Expr::Value(Value::SingleQuotedString(
"2023-04-05".to_owned(),
))),
data_type: DataType::Timestamp(None, TimezoneInfo::None),
format: None,
}),
},
]),
)
}