diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3ace38c02..98637e697 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -471,6 +471,7 @@ pub enum Statement { columns: Vec, constraints: Vec, with_options: Vec, + if_not_exists: bool, external: bool, file_format: Option, location: Option, @@ -623,14 +624,16 @@ impl fmt::Display for Statement { columns, constraints, with_options, + if_not_exists, external, file_format, location, } => { write!( f, - "CREATE {}TABLE {} ({}", + "CREATE {}TABLE {}{} ({}", if *external { "EXTERNAL " } else { "" }, + if *if_not_exists { "IF NOT EXISTS " } else { "" }, name, display_comma_separated(columns) )?; diff --git a/src/parser.rs b/src/parser.rs index 3b61ad112..0939b7e39 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -880,6 +880,7 @@ impl Parser { columns, constraints, with_options: vec![], + if_not_exists: false, external: true, file_format: Some(file_format), location: Some(location), @@ -932,6 +933,7 @@ impl Parser { } pub fn parse_create_table(&mut self) -> Result { + let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]); let table_name = self.parse_object_name()?; // parse optional column list (schema) let (columns, constraints) = self.parse_columns()?; @@ -942,6 +944,7 @@ impl Parser { columns, constraints, with_options, + if_not_exists, external: false, file_format: None, location: None, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index fe4013fac..c62fc86d7 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -909,6 +909,7 @@ fn parse_create_table() { columns, constraints, with_options, + if_not_exists: false, external: false, file_format: None, location: None, @@ -1045,6 +1046,7 @@ fn parse_create_external_table() { columns, constraints, with_options, + if_not_exists, external, file_format, location, @@ -1086,6 +1088,7 @@ fn parse_create_external_table() { assert_eq!("/tmp/example.csv", location.unwrap()); assert_eq!(with_options, vec![]); + assert!(!if_not_exists); } _ => unreachable!(), } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index a903ced64..bd467dc74 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -39,6 +39,7 @@ fn parse_create_table_with_defaults() { columns, constraints, with_options, + if_not_exists: false, external: false, file_format: None, location: None, @@ -225,6 +226,57 @@ fn parse_create_table_with_inherit() { 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] fn parse_copy_example() { let sql = r#"COPY public.actor (actor_id, first_name, last_name, last_update, value) FROM stdin;