Skip to content

Commit f78d8d3

Browse files
committed
Add support for MYSQL's CREATE TABLE SELECT expr
1 parent 334a5bf commit f78d8d3

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

src/dialect/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ pub trait Dialect: Debug + Any {
606606
fn supports_top_before_distinct(&self) -> bool {
607607
false
608608
}
609+
610+
/// Returns true if the dialect supports the `CREATE TABLE SELECT` statement
611+
fn supports_create_table_select(&self) -> bool {
612+
false
613+
}
609614
}
610615

611616
/// This represents the operators for which precedence must be defined

src/dialect/mysql.rs

+5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ impl Dialect for MySqlDialect {
9797
fn supports_limit_comma(&self) -> bool {
9898
true
9999
}
100+
101+
/// see <https://dev.mysql.com/doc/refman/8.4/en/create-table-select.html>
102+
fn supports_create_table_select(&self) -> bool {
103+
true
104+
}
100105
}
101106

102107
/// `LOCK TABLES`

src/parser/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -5911,6 +5911,11 @@ impl<'a> Parser<'a> {
59115911
// Parse optional `AS ( query )`
59125912
let query = if self.parse_keyword(Keyword::AS) {
59135913
Some(self.parse_query()?)
5914+
} else if self.dialect.supports_create_table_select() && self.parse_keyword(Keyword::SELECT)
5915+
{
5916+
// rewind the SELECT keyword
5917+
self.prev_token();
5918+
Some(self.parse_query()?)
59145919
} else {
59155920
None
59165921
};

tests/sqlparser_common.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -6539,7 +6539,17 @@ fn parse_multiple_statements() {
65396539
);
65406540
test_with("DELETE FROM foo", "SELECT", " bar");
65416541
test_with("INSERT INTO foo VALUES (1)", "SELECT", " bar");
6542-
test_with("CREATE TABLE foo (baz INT)", "SELECT", " bar");
6542+
// Since MySQL supports the `CREATE TABLE SELECT` syntax, this needs to be handled separately
6543+
let res = parse_sql_statements("CREATE TABLE foo (baz INT); SELECT bar");
6544+
assert_eq!(
6545+
vec![
6546+
one_statement_parses_to("CREATE TABLE foo (baz INT)", ""),
6547+
one_statement_parses_to("SELECT bar", ""),
6548+
],
6549+
res.unwrap()
6550+
);
6551+
// Check that extra semicolon at the end is stripped by normalization:
6552+
one_statement_parses_to("CREATE TABLE foo (baz INT);", "CREATE TABLE foo (baz INT)");
65436553
// Make sure that empty statements do not cause an error:
65446554
let res = parse_sql_statements(";;");
65456555
assert_eq!(0, res.unwrap().len());
@@ -11532,3 +11542,24 @@ fn test_select_top() {
1153211542
dialects.verified_stmt("SELECT TOP 3 DISTINCT * FROM tbl");
1153311543
dialects.verified_stmt("SELECT TOP 3 DISTINCT a, b, c FROM tbl");
1153411544
}
11545+
11546+
#[test]
11547+
fn parse_create_table_select() {
11548+
let dialects = all_dialects_where(|d| d.supports_create_table_select());
11549+
let sql_1 = r#"CREATE TABLE foo (baz INT) SELECT bar"#;
11550+
let expected = r#"CREATE TABLE foo (baz INT) AS SELECT bar"#;
11551+
let _ = dialects.one_statement_parses_to(sql_1, expected);
11552+
11553+
let sql_2 = r#"CREATE TABLE foo (baz INT, name STRING) SELECT bar, oth_name FROM test.table_a"#;
11554+
let expected =
11555+
r#"CREATE TABLE foo (baz INT, name STRING) AS SELECT bar, oth_name FROM test.table_a"#;
11556+
let _ = dialects.one_statement_parses_to(sql_2, expected);
11557+
11558+
let dialects = all_dialects_where(|d| !d.supports_create_table_select());
11559+
for sql in [sql_1, sql_2] {
11560+
assert_eq!(
11561+
dialects.parse_sql_statements(&sql).unwrap_err(),
11562+
ParserError::ParserError("Expected: end of statement, found: SELECT".to_string())
11563+
);
11564+
}
11565+
}

0 commit comments

Comments
 (0)