Skip to content

Commit eb59356

Browse files
committed
create if not exists for all dialect
1 parent 172ba42 commit eb59356

File tree

4 files changed

+137
-1
lines changed

4 files changed

+137
-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: 33 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,37 @@ impl Parser {
932933
}
933934

934935
pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> {
936+
let if_keyword = self.parse_keyword("IF");
937+
let not_keyword = self.parse_keyword("NOT");
938+
let exists_keyword = self.parse_keyword("EXISTS");
939+
940+
if !if_keyword && not_keyword {
941+
return Err(
942+
ParserError::ParserError("Expected a table name found: keyword NOT".to_string())
943+
)
944+
}
945+
946+
if if_keyword && !not_keyword && !exists_keyword {
947+
return Err(
948+
ParserError::ParserError("Expected keyword NOT found: table name".to_string())
949+
)
950+
}
951+
952+
if if_keyword && !not_keyword {
953+
return Err(
954+
ParserError::ParserError("Expected keyword NOT found: keyword EXISTS".to_string())
955+
)
956+
}
957+
958+
if if_keyword && not_keyword && !exists_keyword {
959+
return Err(
960+
ParserError::ParserError("Expected keyword EXISTS found: table name".to_string())
961+
)
962+
}
963+
964+
let if_not_exists = if_keyword
965+
&& not_keyword
966+
&& exists_keyword;
935967
let table_name = self.parse_object_name()?;
936968
// parse optional column list (schema)
937969
let (columns, constraints) = self.parse_columns()?;
@@ -942,6 +974,7 @@ impl Parser {
942974
columns,
943975
constraints,
944976
with_options,
977+
if_not_exists,
945978
external: false,
946979
file_format: None,
947980
location: None,

tests/sqlparser_common.rs

Lines changed: 99 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,
@@ -995,6 +996,102 @@ fn parse_create_table() {
995996
.contains("Expected column option, found: GARBAGE"));
996997
}
997998

999+
#[test]
1000+
fn parse_create_table_if_not_exists() {
1001+
let sql = "CREATE TABLE IF NOT EXISTS uk_cities (\
1002+
name VARCHAR(100) NOT NULL,\
1003+
lat DOUBLE NULL,\
1004+
lng DOUBLE)";
1005+
let ast = one_statement_parses_to(
1006+
sql,
1007+
"CREATE TABLE IF NOT EXISTS uk_cities (\
1008+
name character varying(100) NOT NULL, \
1009+
lat double NULL, \
1010+
lng double)",
1011+
);
1012+
match ast {
1013+
Statement::CreateTable {
1014+
name,
1015+
columns,
1016+
constraints,
1017+
with_options,
1018+
if_not_exists: true,
1019+
external: false,
1020+
file_format: None,
1021+
location: None,
1022+
} => {
1023+
assert_eq!("uk_cities", name.to_string());
1024+
assert_eq!(
1025+
columns,
1026+
vec![
1027+
ColumnDef {
1028+
name: "name".into(),
1029+
data_type: DataType::Varchar(Some(100)),
1030+
collation: None,
1031+
options: vec![ColumnOptionDef {
1032+
name: None,
1033+
option: ColumnOption::NotNull
1034+
}],
1035+
},
1036+
ColumnDef {
1037+
name: "lat".into(),
1038+
data_type: DataType::Double,
1039+
collation: None,
1040+
options: vec![ColumnOptionDef {
1041+
name: None,
1042+
option: ColumnOption::Null
1043+
}],
1044+
},
1045+
ColumnDef {
1046+
name: "lng".into(),
1047+
data_type: DataType::Double,
1048+
collation: None,
1049+
options: vec![],
1050+
}
1051+
]
1052+
);
1053+
assert!(constraints.is_empty());
1054+
assert_eq!(with_options, vec![]);
1055+
}
1056+
_ => unreachable!(),
1057+
}
1058+
}
1059+
1060+
#[test]
1061+
fn parse_bad_if_not_exists() {
1062+
let res = parse_sql_statements("CREATE TABLE NOT EXISTS uk_cities ()");
1063+
assert_eq!(
1064+
ParserError::ParserError(
1065+
"Expected a table name found: keyword NOT".to_string()
1066+
),
1067+
res.unwrap_err()
1068+
);
1069+
1070+
let res = parse_sql_statements("CREATE TABLE IF EXISTS uk_cities ()");
1071+
assert_eq!(
1072+
ParserError::ParserError(
1073+
"Expected keyword NOT found: keyword EXISTS".to_string()
1074+
),
1075+
res.unwrap_err()
1076+
);
1077+
1078+
let res = parse_sql_statements("CREATE TABLE IF uk_cities ()");
1079+
assert_eq!(
1080+
ParserError::ParserError(
1081+
"Expected keyword NOT found: table name".to_string()
1082+
),
1083+
res.unwrap_err()
1084+
);
1085+
1086+
let res = parse_sql_statements("CREATE TABLE IF NOT uk_cities ()");
1087+
assert_eq!(
1088+
ParserError::ParserError(
1089+
"Expected keyword EXISTS found: table name".to_string()
1090+
),
1091+
res.unwrap_err()
1092+
);
1093+
}
1094+
9981095
#[test]
9991096
fn parse_create_table_with_options() {
10001097
let sql = "CREATE TABLE t (c int) WITH (foo = 'bar', a = 123)";
@@ -1045,6 +1142,7 @@ fn parse_create_external_table() {
10451142
columns,
10461143
constraints,
10471144
with_options,
1145+
if_not_exists,
10481146
external,
10491147
file_format,
10501148
location,
@@ -1086,6 +1184,7 @@ fn parse_create_external_table() {
10861184
assert_eq!("/tmp/example.csv", location.unwrap());
10871185

10881186
assert_eq!(with_options, vec![]);
1187+
assert!(!if_not_exists);
10891188
}
10901189
_ => unreachable!(),
10911190
}

tests/sqlparser_postgres.rs

Lines changed: 1 addition & 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,

0 commit comments

Comments
 (0)