mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Add support for ENABLE and DISABLE on ALTER TABLE for pg (#1077)
Signed-off-by: Toby Hede <toby@cipherstash.com>
This commit is contained in:
parent
593c090b21
commit
a75778c8c7
7 changed files with 143 additions and 7 deletions
|
@ -1 +1 @@
|
||||||
rust 1.73.0
|
rust 1.75.0
|
|
@ -45,6 +45,18 @@ pub enum AlterTableOperation {
|
||||||
/// <column_def>.
|
/// <column_def>.
|
||||||
column_def: ColumnDef,
|
column_def: ColumnDef,
|
||||||
},
|
},
|
||||||
|
/// `DISABLE ROW LEVEL SECURITY`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
DisableRowLevelSecurity,
|
||||||
|
/// `DISABLE RULE rewrite_rule_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
DisableRule { name: Ident },
|
||||||
|
/// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
DisableTrigger { name: Ident },
|
||||||
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
|
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
|
||||||
DropConstraint {
|
DropConstraint {
|
||||||
if_exists: bool,
|
if_exists: bool,
|
||||||
|
@ -61,6 +73,34 @@ pub enum AlterTableOperation {
|
||||||
///
|
///
|
||||||
/// Note: this is a MySQL-specific operation.
|
/// Note: this is a MySQL-specific operation.
|
||||||
DropPrimaryKey,
|
DropPrimaryKey,
|
||||||
|
/// `ENABLE ALWAYS RULE rewrite_rule_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableAlwaysRule { name: Ident },
|
||||||
|
/// `ENABLE ALWAYS TRIGGER trigger_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableAlwaysTrigger { name: Ident },
|
||||||
|
/// `ENABLE REPLICA RULE rewrite_rule_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableReplicaRule { name: Ident },
|
||||||
|
/// `ENABLE REPLICA TRIGGER trigger_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableReplicaTrigger { name: Ident },
|
||||||
|
/// `ENABLE ROW LEVEL SECURITY`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableRowLevelSecurity,
|
||||||
|
/// `ENABLE RULE rewrite_rule_name`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableRule { name: Ident },
|
||||||
|
/// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
|
||||||
|
///
|
||||||
|
/// Note: this is a PostgreSQL-specific operation.
|
||||||
|
EnableTrigger { name: Ident },
|
||||||
/// `RENAME TO PARTITION (partition=val)`
|
/// `RENAME TO PARTITION (partition=val)`
|
||||||
RenamePartitions {
|
RenamePartitions {
|
||||||
old_partitions: Vec<Expr>,
|
old_partitions: Vec<Expr>,
|
||||||
|
@ -143,6 +183,15 @@ impl fmt::Display for AlterTableOperation {
|
||||||
AlterTableOperation::AlterColumn { column_name, op } => {
|
AlterTableOperation::AlterColumn { column_name, op } => {
|
||||||
write!(f, "ALTER COLUMN {column_name} {op}")
|
write!(f, "ALTER COLUMN {column_name} {op}")
|
||||||
}
|
}
|
||||||
|
AlterTableOperation::DisableRowLevelSecurity => {
|
||||||
|
write!(f, "DISABLE ROW LEVEL SECURITY")
|
||||||
|
}
|
||||||
|
AlterTableOperation::DisableRule { name } => {
|
||||||
|
write!(f, "DISABLE RULE {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::DisableTrigger { name } => {
|
||||||
|
write!(f, "DISABLE TRIGGER {name}")
|
||||||
|
}
|
||||||
AlterTableOperation::DropPartitions {
|
AlterTableOperation::DropPartitions {
|
||||||
partitions,
|
partitions,
|
||||||
if_exists,
|
if_exists,
|
||||||
|
@ -177,6 +226,27 @@ impl fmt::Display for AlterTableOperation {
|
||||||
column_name,
|
column_name,
|
||||||
if *cascade { " CASCADE" } else { "" }
|
if *cascade { " CASCADE" } else { "" }
|
||||||
),
|
),
|
||||||
|
AlterTableOperation::EnableAlwaysRule { name } => {
|
||||||
|
write!(f, "ENABLE ALWAYS RULE {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableAlwaysTrigger { name } => {
|
||||||
|
write!(f, "ENABLE ALWAYS TRIGGER {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableReplicaRule { name } => {
|
||||||
|
write!(f, "ENABLE REPLICA RULE {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableReplicaTrigger { name } => {
|
||||||
|
write!(f, "ENABLE REPLICA TRIGGER {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableRowLevelSecurity => {
|
||||||
|
write!(f, "ENABLE ROW LEVEL SECURITY")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableRule { name } => {
|
||||||
|
write!(f, "ENABLE RULE {name}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::EnableTrigger { name } => {
|
||||||
|
write!(f, "ENABLE TRIGGER {name}")
|
||||||
|
}
|
||||||
AlterTableOperation::RenamePartitions {
|
AlterTableOperation::RenamePartitions {
|
||||||
old_partitions,
|
old_partitions,
|
||||||
new_partitions,
|
new_partitions,
|
||||||
|
|
|
@ -349,6 +349,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_raw_string_hashes)]
|
||||||
let statement = r#"SELECT 'Wayne\'s World'"#;
|
let statement = r#"SELECT 'Wayne\'s World'"#;
|
||||||
let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
|
let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
|
||||||
let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
|
let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
|
||||||
|
|
|
@ -223,6 +223,7 @@ define_keywords!(
|
||||||
DETAIL,
|
DETAIL,
|
||||||
DETERMINISTIC,
|
DETERMINISTIC,
|
||||||
DIRECTORY,
|
DIRECTORY,
|
||||||
|
DISABLE,
|
||||||
DISCARD,
|
DISCARD,
|
||||||
DISCONNECT,
|
DISCONNECT,
|
||||||
DISTINCT,
|
DISTINCT,
|
||||||
|
@ -241,6 +242,7 @@ define_keywords!(
|
||||||
ELEMENTS,
|
ELEMENTS,
|
||||||
ELSE,
|
ELSE,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
|
ENABLE,
|
||||||
ENCODING,
|
ENCODING,
|
||||||
ENCRYPTION,
|
ENCRYPTION,
|
||||||
END,
|
END,
|
||||||
|
@ -546,6 +548,7 @@ define_keywords!(
|
||||||
REPAIR,
|
REPAIR,
|
||||||
REPEATABLE,
|
REPEATABLE,
|
||||||
REPLACE,
|
REPLACE,
|
||||||
|
REPLICA,
|
||||||
REPLICATION,
|
REPLICATION,
|
||||||
RESET,
|
RESET,
|
||||||
RESPECT,
|
RESPECT,
|
||||||
|
@ -566,6 +569,7 @@ define_keywords!(
|
||||||
ROWID,
|
ROWID,
|
||||||
ROWS,
|
ROWS,
|
||||||
ROW_NUMBER,
|
ROW_NUMBER,
|
||||||
|
RULE,
|
||||||
RUN,
|
RUN,
|
||||||
SAFE_CAST,
|
SAFE_CAST,
|
||||||
SAVEPOINT,
|
SAVEPOINT,
|
||||||
|
@ -574,6 +578,7 @@ define_keywords!(
|
||||||
SCROLL,
|
SCROLL,
|
||||||
SEARCH,
|
SEARCH,
|
||||||
SECOND,
|
SECOND,
|
||||||
|
SECURITY,
|
||||||
SELECT,
|
SELECT,
|
||||||
SEMI,
|
SEMI,
|
||||||
SENSITIVE,
|
SENSITIVE,
|
||||||
|
|
|
@ -4724,6 +4724,48 @@ impl<'a> Parser<'a> {
|
||||||
new_column_name,
|
new_column_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if self.parse_keyword(Keyword::DISABLE) {
|
||||||
|
if self.parse_keywords(&[Keyword::ROW, Keyword::LEVEL, Keyword::SECURITY]) {
|
||||||
|
AlterTableOperation::DisableRowLevelSecurity {}
|
||||||
|
} else if self.parse_keyword(Keyword::RULE) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::DisableRule { name }
|
||||||
|
} else if self.parse_keyword(Keyword::TRIGGER) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::DisableTrigger { name }
|
||||||
|
} else {
|
||||||
|
return self.expected(
|
||||||
|
"ROW LEVEL SECURITY, RULE, or TRIGGER after DISABLE",
|
||||||
|
self.peek_token(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if self.parse_keyword(Keyword::ENABLE) {
|
||||||
|
if self.parse_keywords(&[Keyword::ALWAYS, Keyword::RULE]) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableAlwaysRule { name }
|
||||||
|
} else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::TRIGGER]) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableAlwaysTrigger { name }
|
||||||
|
} else if self.parse_keywords(&[Keyword::ROW, Keyword::LEVEL, Keyword::SECURITY]) {
|
||||||
|
AlterTableOperation::EnableRowLevelSecurity {}
|
||||||
|
} else if self.parse_keywords(&[Keyword::REPLICA, Keyword::RULE]) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableReplicaRule { name }
|
||||||
|
} else if self.parse_keywords(&[Keyword::REPLICA, Keyword::TRIGGER]) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableReplicaTrigger { name }
|
||||||
|
} else if self.parse_keyword(Keyword::RULE) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableRule { name }
|
||||||
|
} else if self.parse_keyword(Keyword::TRIGGER) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::EnableTrigger { name }
|
||||||
|
} else {
|
||||||
|
return self.expected(
|
||||||
|
"ALWAYS, REPLICA, ROW LEVEL SECURITY, RULE, or TRIGGER after ENABLE",
|
||||||
|
self.peek_token(),
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if self.parse_keyword(Keyword::DROP) {
|
} else if self.parse_keyword(Keyword::DROP) {
|
||||||
if self.parse_keywords(&[Keyword::IF, Keyword::EXISTS, Keyword::PARTITION]) {
|
if self.parse_keywords(&[Keyword::IF, Keyword::EXISTS, Keyword::PARTITION]) {
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
|
|
|
@ -727,10 +727,7 @@ impl<'a> Tokenizer<'a> {
|
||||||
// match binary literal that starts with 0x
|
// match binary literal that starts with 0x
|
||||||
if s == "0" && chars.peek() == Some(&'x') {
|
if s == "0" && chars.peek() == Some(&'x') {
|
||||||
chars.next();
|
chars.next();
|
||||||
let s2 = peeking_take_while(
|
let s2 = peeking_take_while(chars, |ch| ch.is_ascii_hexdigit());
|
||||||
chars,
|
|
||||||
|ch| matches!(ch, '0'..='9' | 'A'..='F' | 'a'..='f'),
|
|
||||||
);
|
|
||||||
return Ok(Some(Token::HexStringLiteral(s2)));
|
return Ok(Some(Token::HexStringLiteral(s2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1077,7 +1074,7 @@ impl<'a> Tokenizer<'a> {
|
||||||
match chars.peek() {
|
match chars.peek() {
|
||||||
Some('$') => {
|
Some('$') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
for (_, c) in value.chars().enumerate() {
|
for c in value.chars() {
|
||||||
let next_char = chars.next();
|
let next_char = chars.next();
|
||||||
if Some(c) != next_char {
|
if Some(c) != next_char {
|
||||||
return self.tokenizer_error(
|
return self.tokenizer_error(
|
||||||
|
|
|
@ -563,6 +563,27 @@ fn parse_alter_table_constraints_rename() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_disable() {
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE ROW LEVEL SECURITY");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE RULE rule_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER ALL");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER USER");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER trigger_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_enable() {
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ALWAYS RULE rule_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ALWAYS TRIGGER trigger_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE REPLICA TRIGGER trigger_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE REPLICA RULE rule_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ROW LEVEL SECURITY");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE RULE rule_name");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER ALL");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER USER");
|
||||||
|
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER trigger_name");
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_alter_table_alter_column() {
|
fn parse_alter_table_alter_column() {
|
||||||
pg().one_statement_parses_to(
|
pg().one_statement_parses_to(
|
||||||
|
@ -3256,7 +3277,7 @@ fn parse_dollar_quoted_string() {
|
||||||
|
|
||||||
let stmt = pg().parse_sql_statements(sql).unwrap();
|
let stmt = pg().parse_sql_statements(sql).unwrap();
|
||||||
|
|
||||||
let projection = match stmt.get(0).unwrap() {
|
let projection = match stmt.first().unwrap() {
|
||||||
Statement::Query(query) => match &*query.body {
|
Statement::Query(query) => match &*query.body {
|
||||||
SetExpr::Select(select) => &select.projection,
|
SetExpr::Select(select) => &select.projection,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue