Skip to content

Commit a75778c

Browse files
authoredDec 31, 2023
Add support for ENABLE and DISABLE on ALTER TABLE for pg (#1077)
Signed-off-by: Toby Hede <[email protected]>
1 parent 593c090 commit a75778c

File tree

7 files changed

+143
-7
lines changed

7 files changed

+143
-7
lines changed
 

‎.tool-versions

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
rust 1.73.0
1+
rust 1.75.0

‎src/ast/ddl.rs

+70
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ pub enum AlterTableOperation {
4545
/// <column_def>.
4646
column_def: ColumnDef,
4747
},
48+
/// `DISABLE ROW LEVEL SECURITY`
49+
///
50+
/// Note: this is a PostgreSQL-specific operation.
51+
DisableRowLevelSecurity,
52+
/// `DISABLE RULE rewrite_rule_name`
53+
///
54+
/// Note: this is a PostgreSQL-specific operation.
55+
DisableRule { name: Ident },
56+
/// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
57+
///
58+
/// Note: this is a PostgreSQL-specific operation.
59+
DisableTrigger { name: Ident },
4860
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
4961
DropConstraint {
5062
if_exists: bool,
@@ -61,6 +73,34 @@ pub enum AlterTableOperation {
6173
///
6274
/// Note: this is a MySQL-specific operation.
6375
DropPrimaryKey,
76+
/// `ENABLE ALWAYS RULE rewrite_rule_name`
77+
///
78+
/// Note: this is a PostgreSQL-specific operation.
79+
EnableAlwaysRule { name: Ident },
80+
/// `ENABLE ALWAYS TRIGGER trigger_name`
81+
///
82+
/// Note: this is a PostgreSQL-specific operation.
83+
EnableAlwaysTrigger { name: Ident },
84+
/// `ENABLE REPLICA RULE rewrite_rule_name`
85+
///
86+
/// Note: this is a PostgreSQL-specific operation.
87+
EnableReplicaRule { name: Ident },
88+
/// `ENABLE REPLICA TRIGGER trigger_name`
89+
///
90+
/// Note: this is a PostgreSQL-specific operation.
91+
EnableReplicaTrigger { name: Ident },
92+
/// `ENABLE ROW LEVEL SECURITY`
93+
///
94+
/// Note: this is a PostgreSQL-specific operation.
95+
EnableRowLevelSecurity,
96+
/// `ENABLE RULE rewrite_rule_name`
97+
///
98+
/// Note: this is a PostgreSQL-specific operation.
99+
EnableRule { name: Ident },
100+
/// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
101+
///
102+
/// Note: this is a PostgreSQL-specific operation.
103+
EnableTrigger { name: Ident },
64104
/// `RENAME TO PARTITION (partition=val)`
65105
RenamePartitions {
66106
old_partitions: Vec<Expr>,
@@ -143,6 +183,15 @@ impl fmt::Display for AlterTableOperation {
143183
AlterTableOperation::AlterColumn { column_name, op } => {
144184
write!(f, "ALTER COLUMN {column_name} {op}")
145185
}
186+
AlterTableOperation::DisableRowLevelSecurity => {
187+
write!(f, "DISABLE ROW LEVEL SECURITY")
188+
}
189+
AlterTableOperation::DisableRule { name } => {
190+
write!(f, "DISABLE RULE {name}")
191+
}
192+
AlterTableOperation::DisableTrigger { name } => {
193+
write!(f, "DISABLE TRIGGER {name}")
194+
}
146195
AlterTableOperation::DropPartitions {
147196
partitions,
148197
if_exists,
@@ -177,6 +226,27 @@ impl fmt::Display for AlterTableOperation {
177226
column_name,
178227
if *cascade { " CASCADE" } else { "" }
179228
),
229+
AlterTableOperation::EnableAlwaysRule { name } => {
230+
write!(f, "ENABLE ALWAYS RULE {name}")
231+
}
232+
AlterTableOperation::EnableAlwaysTrigger { name } => {
233+
write!(f, "ENABLE ALWAYS TRIGGER {name}")
234+
}
235+
AlterTableOperation::EnableReplicaRule { name } => {
236+
write!(f, "ENABLE REPLICA RULE {name}")
237+
}
238+
AlterTableOperation::EnableReplicaTrigger { name } => {
239+
write!(f, "ENABLE REPLICA TRIGGER {name}")
240+
}
241+
AlterTableOperation::EnableRowLevelSecurity => {
242+
write!(f, "ENABLE ROW LEVEL SECURITY")
243+
}
244+
AlterTableOperation::EnableRule { name } => {
245+
write!(f, "ENABLE RULE {name}")
246+
}
247+
AlterTableOperation::EnableTrigger { name } => {
248+
write!(f, "ENABLE TRIGGER {name}")
249+
}
180250
AlterTableOperation::RenamePartitions {
181251
old_partitions,
182252
new_partitions,

‎src/dialect/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ mod tests {
349349
}
350350
}
351351

352+
#[allow(clippy::needless_raw_string_hashes)]
352353
let statement = r#"SELECT 'Wayne\'s World'"#;
353354
let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
354355
let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);

‎src/keywords.rs

+5
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ define_keywords!(
223223
DETAIL,
224224
DETERMINISTIC,
225225
DIRECTORY,
226+
DISABLE,
226227
DISCARD,
227228
DISCONNECT,
228229
DISTINCT,
@@ -241,6 +242,7 @@ define_keywords!(
241242
ELEMENTS,
242243
ELSE,
243244
EMPTY,
245+
ENABLE,
244246
ENCODING,
245247
ENCRYPTION,
246248
END,
@@ -546,6 +548,7 @@ define_keywords!(
546548
REPAIR,
547549
REPEATABLE,
548550
REPLACE,
551+
REPLICA,
549552
REPLICATION,
550553
RESET,
551554
RESPECT,
@@ -566,6 +569,7 @@ define_keywords!(
566569
ROWID,
567570
ROWS,
568571
ROW_NUMBER,
572+
RULE,
569573
RUN,
570574
SAFE_CAST,
571575
SAVEPOINT,
@@ -574,6 +578,7 @@ define_keywords!(
574578
SCROLL,
575579
SEARCH,
576580
SECOND,
581+
SECURITY,
577582
SELECT,
578583
SEMI,
579584
SENSITIVE,

‎src/parser/mod.rs

+42
Original file line numberDiff line numberDiff line change
@@ -4724,6 +4724,48 @@ impl<'a> Parser<'a> {
47244724
new_column_name,
47254725
}
47264726
}
4727+
} else if self.parse_keyword(Keyword::DISABLE) {
4728+
if self.parse_keywords(&[Keyword::ROW, Keyword::LEVEL, Keyword::SECURITY]) {
4729+
AlterTableOperation::DisableRowLevelSecurity {}
4730+
} else if self.parse_keyword(Keyword::RULE) {
4731+
let name = self.parse_identifier()?;
4732+
AlterTableOperation::DisableRule { name }
4733+
} else if self.parse_keyword(Keyword::TRIGGER) {
4734+
let name = self.parse_identifier()?;
4735+
AlterTableOperation::DisableTrigger { name }
4736+
} else {
4737+
return self.expected(
4738+
"ROW LEVEL SECURITY, RULE, or TRIGGER after DISABLE",
4739+
self.peek_token(),
4740+
);
4741+
}
4742+
} else if self.parse_keyword(Keyword::ENABLE) {
4743+
if self.parse_keywords(&[Keyword::ALWAYS, Keyword::RULE]) {
4744+
let name = self.parse_identifier()?;
4745+
AlterTableOperation::EnableAlwaysRule { name }
4746+
} else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::TRIGGER]) {
4747+
let name = self.parse_identifier()?;
4748+
AlterTableOperation::EnableAlwaysTrigger { name }
4749+
} else if self.parse_keywords(&[Keyword::ROW, Keyword::LEVEL, Keyword::SECURITY]) {
4750+
AlterTableOperation::EnableRowLevelSecurity {}
4751+
} else if self.parse_keywords(&[Keyword::REPLICA, Keyword::RULE]) {
4752+
let name = self.parse_identifier()?;
4753+
AlterTableOperation::EnableReplicaRule { name }
4754+
} else if self.parse_keywords(&[Keyword::REPLICA, Keyword::TRIGGER]) {
4755+
let name = self.parse_identifier()?;
4756+
AlterTableOperation::EnableReplicaTrigger { name }
4757+
} else if self.parse_keyword(Keyword::RULE) {
4758+
let name = self.parse_identifier()?;
4759+
AlterTableOperation::EnableRule { name }
4760+
} else if self.parse_keyword(Keyword::TRIGGER) {
4761+
let name = self.parse_identifier()?;
4762+
AlterTableOperation::EnableTrigger { name }
4763+
} else {
4764+
return self.expected(
4765+
"ALWAYS, REPLICA, ROW LEVEL SECURITY, RULE, or TRIGGER after ENABLE",
4766+
self.peek_token(),
4767+
);
4768+
}
47274769
} else if self.parse_keyword(Keyword::DROP) {
47284770
if self.parse_keywords(&[Keyword::IF, Keyword::EXISTS, Keyword::PARTITION]) {
47294771
self.expect_token(&Token::LParen)?;

‎src/tokenizer.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -727,10 +727,7 @@ impl<'a> Tokenizer<'a> {
727727
// match binary literal that starts with 0x
728728
if s == "0" && chars.peek() == Some(&'x') {
729729
chars.next();
730-
let s2 = peeking_take_while(
731-
chars,
732-
|ch| matches!(ch, '0'..='9' | 'A'..='F' | 'a'..='f'),
733-
);
730+
let s2 = peeking_take_while(chars, |ch| ch.is_ascii_hexdigit());
734731
return Ok(Some(Token::HexStringLiteral(s2)));
735732
}
736733

@@ -1077,7 +1074,7 @@ impl<'a> Tokenizer<'a> {
10771074
match chars.peek() {
10781075
Some('$') => {
10791076
chars.next();
1080-
for (_, c) in value.chars().enumerate() {
1077+
for c in value.chars() {
10811078
let next_char = chars.next();
10821079
if Some(c) != next_char {
10831080
return self.tokenizer_error(

‎tests/sqlparser_postgres.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,27 @@ fn parse_alter_table_constraints_rename() {
563563
}
564564
}
565565

566+
#[test]
567+
fn parse_alter_table_disable() {
568+
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE ROW LEVEL SECURITY");
569+
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE RULE rule_name");
570+
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER ALL");
571+
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER USER");
572+
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER trigger_name");
573+
}
574+
575+
#[test]
576+
fn parse_alter_table_enable() {
577+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ALWAYS RULE rule_name");
578+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ALWAYS TRIGGER trigger_name");
579+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE REPLICA TRIGGER trigger_name");
580+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE REPLICA RULE rule_name");
581+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE ROW LEVEL SECURITY");
582+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE RULE rule_name");
583+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER ALL");
584+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER USER");
585+
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER trigger_name");
586+
}
566587
#[test]
567588
fn parse_alter_table_alter_column() {
568589
pg().one_statement_parses_to(
@@ -3256,7 +3277,7 @@ fn parse_dollar_quoted_string() {
32563277

32573278
let stmt = pg().parse_sql_statements(sql).unwrap();
32583279

3259-
let projection = match stmt.get(0).unwrap() {
3280+
let projection = match stmt.first().unwrap() {
32603281
Statement::Query(query) => match &*query.body {
32613282
SetExpr::Select(select) => &select.projection,
32623283
_ => unreachable!(),

0 commit comments

Comments
 (0)
Please sign in to comment.