Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/ast/dml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ impl Display for CreateTable {
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
write!(f, " ()")?;
}

// Hive table comment should be after column definitions, please refer to:
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
if let Some(CommentDef::AfterColumnDefsWithoutEq(comment)) = &self.comment {
write!(f, " COMMENT '{comment}'")?;
}

// Only for SQLite
if self.without_rowid {
write!(f, " WITHOUT ROWID")?;
Expand Down Expand Up @@ -336,6 +343,8 @@ impl Display for CreateTable {
CommentDef::WithoutEq(comment) => {
write!(f, " COMMENT '{comment}'")?;
}
// For CommentDef::AfterColumnDefsWithoutEq will be displayed after column definition
CommentDef::AfterColumnDefsWithoutEq(_) => (),
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6807,12 +6807,18 @@ pub enum CommentDef {
/// Does not include `=` when printing the comment, as `COMMENT 'comment'`
WithEq(String),
WithoutEq(String),
// For Hive dialect, the table comment is after the column definitions without `=`,
// so we need to add an extra variant to allow to identify this case when displaying.
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
AfterColumnDefsWithoutEq(String),
}

impl Display for CommentDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CommentDef::WithEq(comment) | CommentDef::WithoutEq(comment) => write!(f, "{comment}"),
CommentDef::WithEq(comment)
| CommentDef::WithoutEq(comment)
| CommentDef::AfterColumnDefsWithoutEq(comment) => write!(f, "{comment}"),
}
}
}
Expand Down
34 changes: 24 additions & 10 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5613,6 +5613,17 @@ impl<'a> Parser<'a> {

// parse optional column list (schema)
let (columns, constraints) = self.parse_columns()?;
let mut comment = if dialect_of!(self is HiveDialect)
&& self.parse_keyword(Keyword::COMMENT)
{
let next_token = self.next_token();
match next_token.token {
Token::SingleQuotedString(str) => Some(CommentDef::AfterColumnDefsWithoutEq(str)),
_ => self.expected("comment", next_token)?,
}
} else {
None
};

// SQLite supports `WITHOUT ROWID` at the end of `CREATE TABLE`
let without_rowid = self.parse_keywords(&[Keyword::WITHOUT, Keyword::ROWID]);
Expand Down Expand Up @@ -5723,16 +5734,19 @@ impl<'a> Parser<'a> {

let strict = self.parse_keyword(Keyword::STRICT);

let comment = if self.parse_keyword(Keyword::COMMENT) {
let _ = self.consume_token(&Token::Eq);
let next_token = self.next_token();
match next_token.token {
Token::SingleQuotedString(str) => Some(CommentDef::WithoutEq(str)),
_ => self.expected("comment", next_token)?,
}
} else {
None
};
// Excludes Hive dialect here since it has been handled after table column definitions.
if !dialect_of!(self is HiveDialect) {
comment = if self.parse_keyword(Keyword::COMMENT) {
let _ = self.consume_token(&Token::Eq);
let next_token = self.next_token();
match next_token.token {
Token::SingleQuotedString(str) => Some(CommentDef::WithoutEq(str)),
_ => self.expected("comment", next_token)?,
}
} else {
None
};
}

// Parse optional `AS ( query )`
let query = if self.parse_keyword(Keyword::AS) {
Expand Down
35 changes: 34 additions & 1 deletion tests/sqlparser_hive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! is also tested (on the inputs it can handle).
use sqlparser::ast::{
ClusteredBy, CreateFunctionBody, CreateFunctionUsing, CreateTable, Expr, Function,
ClusteredBy, CommentDef, CreateFunctionBody, CreateFunctionUsing, CreateTable, Expr, Function,
FunctionArgumentList, FunctionArguments, Ident, ObjectName, OneOrManyWithParens, OrderByExpr,
SelectItem, Statement, TableFactor, UnaryOperator, Use, Value,
};
Expand Down Expand Up @@ -115,6 +115,39 @@ fn create_table_like() {
hive().verified_stmt(like);
}

#[test]
fn create_table_with_comment() {
let sql = concat!(
"CREATE TABLE db.table_name (a INT, b STRING)",
" COMMENT 'table comment'",
" PARTITIONED BY (a INT, b STRING)",
" CLUSTERED BY (a, b) SORTED BY (a ASC, b DESC)",
" INTO 4 BUCKETS"
);
match hive().verified_stmt(sql) {
Statement::CreateTable(CreateTable { comment, .. }) => {
assert_eq!(
comment,
Some(CommentDef::AfterColumnDefsWithoutEq(
"table comment".to_string()
))
)
}
_ => unreachable!(),
}

// negative test case
let invalid_sql = concat!(
"CREATE TABLE db.table_name (a INT, b STRING)",
" PARTITIONED BY (a INT, b STRING)",
" COMMENT 'table comment'",
);
assert_eq!(
hive().parse_sql_statements(invalid_sql).unwrap_err(),
ParserError::ParserError("Expected: end of statement, found: COMMENT".to_string())
);
}

#[test]
fn create_table_with_clustered_by() {
let sql = concat!(
Expand Down
Loading