Skip to content

Commit 5ad578e

Browse files
authored
Implement CREATE TABLE IF NOT EXISTS (apache#163)
A non-standard feature supported at least by Postgres https://www.postgresql.org/docs/12/sql-createtable.html
1 parent 0686511 commit 5ad578e

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

src/ast/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ pub enum Statement {
471471
columns: Vec<ColumnDef>,
472472
constraints: Vec<TableConstraint>,
473473
with_options: Vec<SqlOption>,
474+
if_not_exists: bool,
474475
external: bool,
475476
file_format: Option<FileFormat>,
476477
location: Option<String>,
@@ -623,14 +624,16 @@ impl fmt::Display for Statement {
623624
columns,
624625
constraints,
625626
with_options,
627+
if_not_exists,
626628
external,
627629
file_format,
628630
location,
629631
} => {
630632
write!(
631633
f,
632-
"CREATE {}TABLE {} ({}",
634+
"CREATE {}TABLE {}{} ({}",
633635
if *external { "EXTERNAL " } else { "" },
636+
if *if_not_exists { "IF NOT EXISTS " } else { "" },
634637
name,
635638
display_comma_separated(columns)
636639
)?;

src/parser.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ impl Parser {
880880
columns,
881881
constraints,
882882
with_options: vec![],
883+
if_not_exists: false,
883884
external: true,
884885
file_format: Some(file_format),
885886
location: Some(location),
@@ -932,6 +933,7 @@ impl Parser {
932933
}
933934

934935
pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> {
936+
let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]);
935937
let table_name = self.parse_object_name()?;
936938
// parse optional column list (schema)
937939
let (columns, constraints) = self.parse_columns()?;
@@ -942,6 +944,7 @@ impl Parser {
942944
columns,
943945
constraints,
944946
with_options,
947+
if_not_exists,
945948
external: false,
946949
file_format: None,
947950
location: None,

tests/sqlparser_common.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ fn parse_create_table() {
909909
columns,
910910
constraints,
911911
with_options,
912+
if_not_exists: false,
912913
external: false,
913914
file_format: None,
914915
location: None,
@@ -1045,6 +1046,7 @@ fn parse_create_external_table() {
10451046
columns,
10461047
constraints,
10471048
with_options,
1049+
if_not_exists,
10481050
external,
10491051
file_format,
10501052
location,
@@ -1086,6 +1088,7 @@ fn parse_create_external_table() {
10861088
assert_eq!("/tmp/example.csv", location.unwrap());
10871089

10881090
assert_eq!(with_options, vec![]);
1091+
assert!(!if_not_exists);
10891092
}
10901093
_ => unreachable!(),
10911094
}

tests/sqlparser_postgres.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn parse_create_table_with_defaults() {
3939
columns,
4040
constraints,
4141
with_options,
42+
if_not_exists: false,
4243
external: false,
4344
file_format: None,
4445
location: None,
@@ -225,6 +226,57 @@ fn parse_create_table_with_inherit() {
225226
pg().verified_stmt(sql);
226227
}
227228

229+
#[test]
230+
fn parse_create_table_if_not_exists() {
231+
let sql = "CREATE TABLE IF NOT EXISTS uk_cities ()";
232+
let ast =
233+
pg_and_generic().one_statement_parses_to(sql, "CREATE TABLE IF NOT EXISTS uk_cities ()");
234+
match ast {
235+
Statement::CreateTable {
236+
name,
237+
columns: _columns,
238+
constraints,
239+
with_options,
240+
if_not_exists: true,
241+
external: false,
242+
file_format: None,
243+
location: None,
244+
} => {
245+
assert_eq!("uk_cities", name.to_string());
246+
assert!(constraints.is_empty());
247+
assert_eq!(with_options, vec![]);
248+
}
249+
_ => unreachable!(),
250+
}
251+
}
252+
253+
#[test]
254+
fn parse_bad_if_not_exists() {
255+
let res = pg().parse_sql_statements("CREATE TABLE NOT EXISTS uk_cities ()");
256+
assert_eq!(
257+
ParserError::ParserError("Expected end of statement, found: EXISTS".to_string()),
258+
res.unwrap_err()
259+
);
260+
261+
let res = pg().parse_sql_statements("CREATE TABLE IF EXISTS uk_cities ()");
262+
assert_eq!(
263+
ParserError::ParserError("Expected end of statement, found: EXISTS".to_string()),
264+
res.unwrap_err()
265+
);
266+
267+
let res = pg().parse_sql_statements("CREATE TABLE IF uk_cities ()");
268+
assert_eq!(
269+
ParserError::ParserError("Expected end of statement, found: uk_cities".to_string()),
270+
res.unwrap_err()
271+
);
272+
273+
let res = pg().parse_sql_statements("CREATE TABLE IF NOT uk_cities ()");
274+
assert_eq!(
275+
ParserError::ParserError("Expected end of statement, found: NOT".to_string()),
276+
res.unwrap_err()
277+
);
278+
}
279+
228280
#[test]
229281
fn parse_copy_example() {
230282
let sql = r#"COPY public.actor (actor_id, first_name, last_name, last_update, value) FROM stdin;

0 commit comments

Comments
 (0)