mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-30 18:57:21 +00:00
Support for IF NOT EXISTS
in ALTER TABLE ADD COLUMN (#707)
This commit is contained in:
parent
bae682255d
commit
886875f3bf
3 changed files with 110 additions and 11 deletions
|
@ -30,8 +30,15 @@ use crate::tokenizer::Token;
|
||||||
pub enum AlterTableOperation {
|
pub enum AlterTableOperation {
|
||||||
/// `ADD <table_constraint>`
|
/// `ADD <table_constraint>`
|
||||||
AddConstraint(TableConstraint),
|
AddConstraint(TableConstraint),
|
||||||
/// `ADD [ COLUMN ] <column_def>`
|
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
|
||||||
AddColumn { column_def: ColumnDef },
|
AddColumn {
|
||||||
|
/// `[COLUMN]`.
|
||||||
|
column_keyword: bool,
|
||||||
|
/// `[IF NOT EXISTS]`
|
||||||
|
if_not_exists: bool,
|
||||||
|
/// <column_def>.
|
||||||
|
column_def: ColumnDef,
|
||||||
|
},
|
||||||
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
|
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
|
||||||
DropConstraint {
|
DropConstraint {
|
||||||
if_exists: bool,
|
if_exists: bool,
|
||||||
|
@ -100,8 +107,21 @@ impl fmt::Display for AlterTableOperation {
|
||||||
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
|
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
|
||||||
),
|
),
|
||||||
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
|
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
|
||||||
AlterTableOperation::AddColumn { column_def } => {
|
AlterTableOperation::AddColumn {
|
||||||
write!(f, "ADD COLUMN {}", column_def)
|
column_keyword,
|
||||||
|
if_not_exists,
|
||||||
|
column_def,
|
||||||
|
} => {
|
||||||
|
write!(f, "ADD")?;
|
||||||
|
if *column_keyword {
|
||||||
|
write!(f, " COLUMN")?;
|
||||||
|
}
|
||||||
|
if *if_not_exists {
|
||||||
|
write!(f, " IF NOT EXISTS")?;
|
||||||
|
}
|
||||||
|
write!(f, " {column_def}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
AlterTableOperation::AlterColumn { column_name, op } => {
|
AlterTableOperation::AlterColumn { column_name, op } => {
|
||||||
write!(f, "ALTER COLUMN {} {}", column_name, op)
|
write!(f, "ALTER COLUMN {} {}", column_name, op)
|
||||||
|
@ -416,8 +436,8 @@ impl fmt::Display for KeyOrIndexDisplay {
|
||||||
|
|
||||||
/// Indexing method used by that index.
|
/// Indexing method used by that index.
|
||||||
///
|
///
|
||||||
/// This structure isn't present on ANSI, but is found at least in [MySQL CREATE TABLE][1],
|
/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
|
||||||
/// [MySQL CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
|
/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
|
||||||
///
|
///
|
||||||
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
|
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
|
||||||
/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
|
/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
|
||||||
|
@ -466,7 +486,7 @@ impl fmt::Display for ColumnDef {
|
||||||
/// they are allowed to be named. The specification distinguishes between
|
/// they are allowed to be named. The specification distinguishes between
|
||||||
/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
|
/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
|
||||||
/// and can appear in any order, and other options (DEFAULT, GENERATED), which
|
/// and can appear in any order, and other options (DEFAULT, GENERATED), which
|
||||||
/// cannot be named and must appear in a fixed order. PostgreSQL, however,
|
/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
|
||||||
/// allows preceding any option with `CONSTRAINT <name>`, even those that are
|
/// allows preceding any option with `CONSTRAINT <name>`, even those that are
|
||||||
/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
|
/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
|
||||||
/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
|
/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
|
||||||
|
|
|
@ -3205,9 +3205,22 @@ impl<'a> Parser<'a> {
|
||||||
new_partitions: partitions,
|
new_partitions: partitions,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let _ = self.parse_keyword(Keyword::COLUMN);
|
let column_keyword = self.parse_keyword(Keyword::COLUMN);
|
||||||
|
|
||||||
|
let if_not_exists = if dialect_of!(self is PostgreSqlDialect | BigQueryDialect | GenericDialect)
|
||||||
|
{
|
||||||
|
self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS])
|
||||||
|
|| if_not_exists
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
let column_def = self.parse_column_def()?;
|
let column_def = self.parse_column_def()?;
|
||||||
AlterTableOperation::AddColumn { column_def }
|
AlterTableOperation::AddColumn {
|
||||||
|
column_keyword,
|
||||||
|
if_not_exists,
|
||||||
|
column_def,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if self.parse_keyword(Keyword::RENAME) {
|
} else if self.parse_keyword(Keyword::RENAME) {
|
||||||
|
@ -5858,7 +5871,6 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_parse_data_type {
|
mod test_parse_data_type {
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, ObjectName, TimezoneInfo,
|
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, ObjectName, TimezoneInfo,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2528,8 +2528,15 @@ fn parse_alter_table() {
|
||||||
match one_statement_parses_to(add_column, "ALTER TABLE tab ADD COLUMN foo TEXT") {
|
match one_statement_parses_to(add_column, "ALTER TABLE tab ADD COLUMN foo TEXT") {
|
||||||
Statement::AlterTable {
|
Statement::AlterTable {
|
||||||
name,
|
name,
|
||||||
operation: AlterTableOperation::AddColumn { column_def },
|
operation:
|
||||||
|
AlterTableOperation::AddColumn {
|
||||||
|
column_keyword,
|
||||||
|
if_not_exists,
|
||||||
|
column_def,
|
||||||
|
},
|
||||||
} => {
|
} => {
|
||||||
|
assert!(column_keyword);
|
||||||
|
assert!(!if_not_exists);
|
||||||
assert_eq!("tab", name.to_string());
|
assert_eq!("tab", name.to_string());
|
||||||
assert_eq!("foo", column_def.name.to_string());
|
assert_eq!("foo", column_def.name.to_string());
|
||||||
assert_eq!("TEXT", column_def.data_type.to_string());
|
assert_eq!("TEXT", column_def.data_type.to_string());
|
||||||
|
@ -2567,6 +2574,66 @@ fn parse_alter_table() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_add_column() {
|
||||||
|
match verified_stmt("ALTER TABLE tab ADD foo TEXT") {
|
||||||
|
Statement::AlterTable {
|
||||||
|
operation: AlterTableOperation::AddColumn { column_keyword, .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert!(!column_keyword);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match verified_stmt("ALTER TABLE tab ADD COLUMN foo TEXT") {
|
||||||
|
Statement::AlterTable {
|
||||||
|
operation: AlterTableOperation::AddColumn { column_keyword, .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert!(column_keyword);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_add_column_if_not_exists() {
|
||||||
|
let dialects = TestedDialects {
|
||||||
|
dialects: vec![
|
||||||
|
Box::new(PostgreSqlDialect {}),
|
||||||
|
Box::new(BigQueryDialect {}),
|
||||||
|
Box::new(GenericDialect {}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
match dialects.verified_stmt("ALTER TABLE tab ADD IF NOT EXISTS foo TEXT") {
|
||||||
|
Statement::AlterTable {
|
||||||
|
operation: AlterTableOperation::AddColumn { if_not_exists, .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert!(if_not_exists);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match dialects.verified_stmt("ALTER TABLE tab ADD COLUMN IF NOT EXISTS foo TEXT") {
|
||||||
|
Statement::AlterTable {
|
||||||
|
operation:
|
||||||
|
AlterTableOperation::AddColumn {
|
||||||
|
column_keyword,
|
||||||
|
if_not_exists,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert!(column_keyword);
|
||||||
|
assert!(if_not_exists);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_alter_table_constraints() {
|
fn parse_alter_table_constraints() {
|
||||||
check_one("CONSTRAINT address_pkey PRIMARY KEY (address_id)");
|
check_one("CONSTRAINT address_pkey PRIMARY KEY (address_id)");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue