Support global,local, on commit for create temporary table (#456)

* feat: add global,local / on commit for create temp tables

* chore: minor refactor

* chore: clippy fix
This commit is contained in:
George Andronchik 2022-04-22 19:58:39 +08:00 committed by GitHub
parent 278345d21a
commit 0924870d11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 2 deletions

View file

@ -831,6 +831,7 @@ pub enum Statement {
or_replace: bool,
temporary: bool,
external: bool,
global: Option<bool>,
if_not_exists: bool,
/// Table name
name: ObjectName,
@ -849,6 +850,7 @@ pub enum Statement {
engine: Option<String>,
default_charset: Option<String>,
collation: Option<String>,
on_commit: Option<OnCommit>,
},
/// SQLite's `CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`
CreateVirtualTable {
@ -1313,6 +1315,7 @@ impl fmt::Display for Statement {
hive_distribution,
hive_formats,
external,
global,
temporary,
file_format,
location,
@ -1322,6 +1325,7 @@ impl fmt::Display for Statement {
default_charset,
engine,
collation,
on_commit,
} => {
// We want to allow the following options
// Empty column list, allowed by PostgreSQL:
@ -1332,9 +1336,18 @@ impl fmt::Display for Statement {
// `CREATE TABLE t (a INT) AS SELECT a from t2`
write!(
f,
"CREATE {or_replace}{external}{temporary}TABLE {if_not_exists}{name}",
"CREATE {or_replace}{external}{global}{temporary}TABLE {if_not_exists}{name}",
or_replace = if *or_replace { "OR REPLACE " } else { "" },
external = if *external { "EXTERNAL " } else { "" },
global = global
.map(|global| {
if global {
"GLOBAL "
} else {
"LOCAL "
}
})
.unwrap_or(""),
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
temporary = if *temporary { "TEMPORARY " } else { "" },
name = name,
@ -1456,6 +1469,17 @@ impl fmt::Display for Statement {
if let Some(collation) = collation {
write!(f, " COLLATE={}", collation)?;
}
if on_commit.is_some() {
let on_commit = match on_commit {
Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
Some(OnCommit::Drop) => "ON COMMIT DROP",
None => "",
};
write!(f, " {}", on_commit)?;
}
Ok(())
}
Statement::CreateVirtualTable {
@ -2276,6 +2300,14 @@ impl fmt::Display for CopyTarget {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OnCommit {
DeleteRows,
PreserveRows,
Drop,
}
/// An option in `COPY` statement.
///
/// <https://www.postgresql.org/docs/14/sql-copy.html>

View file

@ -376,6 +376,7 @@ define_keywords!(
PRECEDING,
PRECISION,
PREPARE,
PRESERVE,
PRIMARY,
PRIVILEGES,
PROCEDURE,

View file

@ -1519,11 +1519,20 @@ impl<'a> Parser<'a> {
/// Parse a SQL CREATE statement
pub fn parse_create(&mut self) -> Result<Statement, ParserError> {
let or_replace = self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
let local = self.parse_one_of_keywords(&[Keyword::LOCAL]).is_some();
let global = self.parse_one_of_keywords(&[Keyword::GLOBAL]).is_some();
let global: Option<bool> = if global {
Some(true)
} else if local {
Some(false)
} else {
None
};
let temporary = self
.parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY])
.is_some();
if self.parse_keyword(Keyword::TABLE) {
self.parse_create_table(or_replace, temporary)
self.parse_create_table(or_replace, temporary, global)
} else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) {
self.prev_token();
self.parse_create_view(or_replace)
@ -1633,6 +1642,7 @@ impl<'a> Parser<'a> {
or_replace,
if_not_exists,
external: true,
global: None,
temporary: false,
file_format,
location,
@ -1642,6 +1652,7 @@ impl<'a> Parser<'a> {
default_charset: None,
engine: None,
collation: None,
on_commit: None,
})
}
@ -1790,6 +1801,7 @@ impl<'a> Parser<'a> {
&mut self,
or_replace: bool,
temporary: bool,
global: Option<bool>,
) -> Result<Statement, ParserError> {
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
let table_name = self.parse_object_name()?;
@ -1846,6 +1858,23 @@ impl<'a> Parser<'a> {
None
};
let on_commit: Option<OnCommit> =
if self.parse_keywords(&[Keyword::ON, Keyword::COMMIT, Keyword::DELETE, Keyword::ROWS])
{
Some(OnCommit::DeleteRows)
} else if self.parse_keywords(&[
Keyword::ON,
Keyword::COMMIT,
Keyword::PRESERVE,
Keyword::ROWS,
]) {
Some(OnCommit::PreserveRows)
} else if self.parse_keywords(&[Keyword::ON, Keyword::COMMIT, Keyword::DROP]) {
Some(OnCommit::Drop)
} else {
None
};
Ok(Statement::CreateTable {
name: table_name,
temporary,
@ -1858,6 +1887,7 @@ impl<'a> Parser<'a> {
hive_distribution,
hive_formats: Some(hive_formats),
external: false,
global,
file_format: None,
location: None,
query,
@ -1866,6 +1896,7 @@ impl<'a> Parser<'a> {
engine,
default_charset,
collation,
on_commit,
})
}

View file

@ -1347,6 +1347,21 @@ fn parse_quoted_identifier() {
pg_and_generic().verified_stmt(r#"SELECT "quoted "" ident""#);
}
#[test]
fn parse_local_and_global() {
pg_and_generic().verified_stmt("CREATE LOCAL TEMPORARY TABLE table (COL INT)");
}
#[test]
fn parse_on_commit() {
pg_and_generic()
.verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT PRESERVE ROWS");
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DELETE ROWS");
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DROP");
}
fn pg() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(PostgreSqlDialect {})],