Implement CREATE TABLE IF NOT EXISTS (#163)

A non-standard feature supported at least by Postgres

https://www.postgresql.org/docs/12/sql-createtable.html
This commit is contained in:
Alex Dukhno 2020-04-21 16:28:02 +03:00 committed by GitHub
parent 06865113d7
commit 5ad578e3e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 1 deletions

View file

@ -471,6 +471,7 @@ pub enum Statement {
columns: Vec<ColumnDef>, columns: Vec<ColumnDef>,
constraints: Vec<TableConstraint>, constraints: Vec<TableConstraint>,
with_options: Vec<SqlOption>, with_options: Vec<SqlOption>,
if_not_exists: bool,
external: bool, external: bool,
file_format: Option<FileFormat>, file_format: Option<FileFormat>,
location: Option<String>, location: Option<String>,
@ -623,14 +624,16 @@ impl fmt::Display for Statement {
columns, columns,
constraints, constraints,
with_options, with_options,
if_not_exists,
external, external,
file_format, file_format,
location, location,
} => { } => {
write!( write!(
f, f,
"CREATE {}TABLE {} ({}", "CREATE {}TABLE {}{} ({}",
if *external { "EXTERNAL " } else { "" }, if *external { "EXTERNAL " } else { "" },
if *if_not_exists { "IF NOT EXISTS " } else { "" },
name, name,
display_comma_separated(columns) display_comma_separated(columns)
)?; )?;

View file

@ -880,6 +880,7 @@ impl Parser {
columns, columns,
constraints, constraints,
with_options: vec![], with_options: vec![],
if_not_exists: false,
external: true, external: true,
file_format: Some(file_format), file_format: Some(file_format),
location: Some(location), location: Some(location),
@ -932,6 +933,7 @@ impl Parser {
} }
pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> { pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> {
let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]);
let table_name = self.parse_object_name()?; let table_name = self.parse_object_name()?;
// parse optional column list (schema) // parse optional column list (schema)
let (columns, constraints) = self.parse_columns()?; let (columns, constraints) = self.parse_columns()?;
@ -942,6 +944,7 @@ impl Parser {
columns, columns,
constraints, constraints,
with_options, with_options,
if_not_exists,
external: false, external: false,
file_format: None, file_format: None,
location: None, location: None,

View file

@ -909,6 +909,7 @@ fn parse_create_table() {
columns, columns,
constraints, constraints,
with_options, with_options,
if_not_exists: false,
external: false, external: false,
file_format: None, file_format: None,
location: None, location: None,
@ -1045,6 +1046,7 @@ fn parse_create_external_table() {
columns, columns,
constraints, constraints,
with_options, with_options,
if_not_exists,
external, external,
file_format, file_format,
location, location,
@ -1086,6 +1088,7 @@ fn parse_create_external_table() {
assert_eq!("/tmp/example.csv", location.unwrap()); assert_eq!("/tmp/example.csv", location.unwrap());
assert_eq!(with_options, vec![]); assert_eq!(with_options, vec![]);
assert!(!if_not_exists);
} }
_ => unreachable!(), _ => unreachable!(),
} }

View file

@ -39,6 +39,7 @@ fn parse_create_table_with_defaults() {
columns, columns,
constraints, constraints,
with_options, with_options,
if_not_exists: false,
external: false, external: false,
file_format: None, file_format: None,
location: None, location: None,
@ -225,6 +226,57 @@ fn parse_create_table_with_inherit() {
pg().verified_stmt(sql); pg().verified_stmt(sql);
} }
#[test]
fn parse_create_table_if_not_exists() {
let sql = "CREATE TABLE IF NOT EXISTS uk_cities ()";
let ast =
pg_and_generic().one_statement_parses_to(sql, "CREATE TABLE IF NOT EXISTS uk_cities ()");
match ast {
Statement::CreateTable {
name,
columns: _columns,
constraints,
with_options,
if_not_exists: true,
external: false,
file_format: None,
location: None,
} => {
assert_eq!("uk_cities", name.to_string());
assert!(constraints.is_empty());
assert_eq!(with_options, vec![]);
}
_ => unreachable!(),
}
}
#[test]
fn parse_bad_if_not_exists() {
let res = pg().parse_sql_statements("CREATE TABLE NOT EXISTS uk_cities ()");
assert_eq!(
ParserError::ParserError("Expected end of statement, found: EXISTS".to_string()),
res.unwrap_err()
);
let res = pg().parse_sql_statements("CREATE TABLE IF EXISTS uk_cities ()");
assert_eq!(
ParserError::ParserError("Expected end of statement, found: EXISTS".to_string()),
res.unwrap_err()
);
let res = pg().parse_sql_statements("CREATE TABLE IF uk_cities ()");
assert_eq!(
ParserError::ParserError("Expected end of statement, found: uk_cities".to_string()),
res.unwrap_err()
);
let res = pg().parse_sql_statements("CREATE TABLE IF NOT uk_cities ()");
assert_eq!(
ParserError::ParserError("Expected end of statement, found: NOT".to_string()),
res.unwrap_err()
);
}
#[test] #[test]
fn parse_copy_example() { fn parse_copy_example() {
let sql = r#"COPY public.actor (actor_id, first_name, last_name, last_update, value) FROM stdin; let sql = r#"COPY public.actor (actor_id, first_name, last_name, last_update, value) FROM stdin;