Snowflake: support of views column comment (#1441)

This commit is contained in:
Aleksei Piianin 2024-10-07 22:20:23 +02:00 committed by GitHub
parent 8ccb87a835
commit 84348d483e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 56 additions and 17 deletions

View file

@ -1040,6 +1040,7 @@ impl fmt::Display for ColumnDef {
/// ```sql
/// name
/// age OPTIONS(description = "age column", tag = "prod")
/// amount COMMENT 'The total amount for the order line'
/// created_at DateTime64
/// ```
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@ -1048,7 +1049,7 @@ impl fmt::Display for ColumnDef {
pub struct ViewColumnDef {
pub name: Ident,
pub data_type: Option<DataType>,
pub options: Option<Vec<SqlOption>>,
pub options: Option<Vec<ColumnOption>>,
}
impl fmt::Display for ViewColumnDef {
@ -1058,11 +1059,7 @@ impl fmt::Display for ViewColumnDef {
write!(f, " {}", data_type)?;
}
if let Some(options) = self.options.as_ref() {
write!(
f,
" OPTIONS({})",
display_comma_separated(options.as_slice())
)?;
write!(f, " {}", display_comma_separated(options.as_slice()))?;
}
Ok(())
}

View file

@ -3930,6 +3930,12 @@ impl fmt::Display for Statement {
.map(|to| format!(" TO {to}"))
.unwrap_or_default()
)?;
if !columns.is_empty() {
write!(f, " ({})", display_comma_separated(columns))?;
}
if matches!(options, CreateTableOptions::With(_)) {
write!(f, " {options}")?;
}
if let Some(comment) = comment {
write!(
f,
@ -3937,12 +3943,6 @@ impl fmt::Display for Statement {
value::escape_single_quote_string(comment)
)?;
}
if matches!(options, CreateTableOptions::With(_)) {
write!(f, " {options}")?;
}
if !columns.is_empty() {
write!(f, " ({})", display_comma_separated(columns))?;
}
if !cluster_by.is_empty() {
write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?;
}

View file

@ -8361,11 +8361,14 @@ impl<'a> Parser<'a> {
/// Parses a column definition within a view.
fn parse_view_column(&mut self) -> Result<ViewColumnDef, ParserError> {
let name = self.parse_identifier(false)?;
let options = if dialect_of!(self is BigQueryDialect | GenericDialect)
&& self.parse_keyword(Keyword::OPTIONS)
let options = if (dialect_of!(self is BigQueryDialect | GenericDialect)
&& self.parse_keyword(Keyword::OPTIONS))
|| (dialect_of!(self is SnowflakeDialect | GenericDialect)
&& self.parse_keyword(Keyword::COMMENT))
{
self.prev_token();
Some(self.parse_options(Keyword::OPTIONS)?)
self.parse_optional_column_option()?
.map(|option| vec![option])
} else {
None
};

View file

@ -272,10 +272,10 @@ fn parse_create_view_with_options() {
ViewColumnDef {
name: Ident::new("age"),
data_type: None,
options: Some(vec![SqlOption::KeyValue {
options: Some(vec![ColumnOption::Options(vec![SqlOption::KeyValue {
key: Ident::new("description"),
value: Expr::Value(Value::DoubleQuotedString("field age".to_string())),
}])
}])]),
},
],
columns

View file

@ -2405,3 +2405,42 @@ fn parse_use() {
);
}
}
#[test]
fn view_comment_option_should_be_after_column_list() {
for sql in [
"CREATE OR REPLACE VIEW v (a) COMMENT = 'Comment' AS SELECT a FROM t",
"CREATE OR REPLACE VIEW v (a COMMENT 'a comment', b, c COMMENT 'c comment') COMMENT = 'Comment' AS SELECT a FROM t",
"CREATE OR REPLACE VIEW v (a COMMENT 'a comment', b, c COMMENT 'c comment') WITH (foo = bar) COMMENT = 'Comment' AS SELECT a FROM t",
] {
snowflake_and_generic()
.verified_stmt(sql);
}
}
#[test]
fn parse_view_column_descriptions() {
let sql = "CREATE OR REPLACE VIEW v (a COMMENT 'Comment', b) AS SELECT a, b FROM table1";
match snowflake_and_generic().verified_stmt(sql) {
Statement::CreateView { name, columns, .. } => {
assert_eq!(name.to_string(), "v");
assert_eq!(
columns,
vec![
ViewColumnDef {
name: Ident::new("a"),
data_type: None,
options: Some(vec![ColumnOption::Comment("Comment".to_string())]),
},
ViewColumnDef {
name: Ident::new("b"),
data_type: None,
options: None,
}
]
);
}
_ => unreachable!(),
};
}