mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
Fix Hive table comment should be after table column definitions (#1413)
This commit is contained in:
parent
a7b49b5072
commit
6ba6068944
4 changed files with 64 additions and 6 deletions
|
@ -226,6 +226,13 @@ impl Display for CreateTable {
|
||||||
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
|
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
|
||||||
write!(f, " ()")?;
|
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
|
// Only for SQLite
|
||||||
if self.without_rowid {
|
if self.without_rowid {
|
||||||
write!(f, " WITHOUT ROWID")?;
|
write!(f, " WITHOUT ROWID")?;
|
||||||
|
@ -336,6 +343,8 @@ impl Display for CreateTable {
|
||||||
CommentDef::WithoutEq(comment) => {
|
CommentDef::WithoutEq(comment) => {
|
||||||
write!(f, " COMMENT '{comment}'")?;
|
write!(f, " COMMENT '{comment}'")?;
|
||||||
}
|
}
|
||||||
|
// For CommentDef::AfterColumnDefsWithoutEq will be displayed after column definition
|
||||||
|
CommentDef::AfterColumnDefsWithoutEq(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6807,12 +6807,18 @@ pub enum CommentDef {
|
||||||
/// Does not include `=` when printing the comment, as `COMMENT 'comment'`
|
/// Does not include `=` when printing the comment, as `COMMENT 'comment'`
|
||||||
WithEq(String),
|
WithEq(String),
|
||||||
WithoutEq(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 {
|
impl Display for CommentDef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
CommentDef::WithEq(comment) | CommentDef::WithoutEq(comment) => write!(f, "{comment}"),
|
CommentDef::WithEq(comment)
|
||||||
|
| CommentDef::WithoutEq(comment)
|
||||||
|
| CommentDef::AfterColumnDefsWithoutEq(comment) => write!(f, "{comment}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5598,6 +5598,17 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// parse optional column list (schema)
|
// parse optional column list (schema)
|
||||||
let (columns, constraints) = self.parse_columns()?;
|
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`
|
// SQLite supports `WITHOUT ROWID` at the end of `CREATE TABLE`
|
||||||
let without_rowid = self.parse_keywords(&[Keyword::WITHOUT, Keyword::ROWID]);
|
let without_rowid = self.parse_keywords(&[Keyword::WITHOUT, Keyword::ROWID]);
|
||||||
|
@ -5708,15 +5719,14 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let strict = self.parse_keyword(Keyword::STRICT);
|
let strict = self.parse_keyword(Keyword::STRICT);
|
||||||
|
|
||||||
let comment = if self.parse_keyword(Keyword::COMMENT) {
|
// Excludes Hive dialect here since it has been handled after table column definitions.
|
||||||
|
if !dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::COMMENT) {
|
||||||
let _ = self.consume_token(&Token::Eq);
|
let _ = self.consume_token(&Token::Eq);
|
||||||
let next_token = self.next_token();
|
let next_token = self.next_token();
|
||||||
match next_token.token {
|
comment = match next_token.token {
|
||||||
Token::SingleQuotedString(str) => Some(CommentDef::WithoutEq(str)),
|
Token::SingleQuotedString(str) => Some(CommentDef::WithoutEq(str)),
|
||||||
_ => self.expected("comment", next_token)?,
|
_ => self.expected("comment", next_token)?,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse optional `AS ( query )`
|
// Parse optional `AS ( query )`
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
//! is also tested (on the inputs it can handle).
|
//! is also tested (on the inputs it can handle).
|
||||||
|
|
||||||
use sqlparser::ast::{
|
use sqlparser::ast::{
|
||||||
ClusteredBy, CreateFunctionBody, CreateFunctionUsing, CreateTable, Expr, Function,
|
ClusteredBy, CommentDef, CreateFunctionBody, CreateFunctionUsing, CreateTable, Expr, Function,
|
||||||
FunctionArgumentList, FunctionArguments, Ident, ObjectName, OneOrManyWithParens, OrderByExpr,
|
FunctionArgumentList, FunctionArguments, Ident, ObjectName, OneOrManyWithParens, OrderByExpr,
|
||||||
SelectItem, Statement, TableFactor, UnaryOperator, Use, Value,
|
SelectItem, Statement, TableFactor, UnaryOperator, Use, Value,
|
||||||
};
|
};
|
||||||
|
@ -115,6 +115,39 @@ fn create_table_like() {
|
||||||
hive().verified_stmt(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]
|
#[test]
|
||||||
fn create_table_with_clustered_by() {
|
fn create_table_with_clustered_by() {
|
||||||
let sql = concat!(
|
let sql = concat!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue