Skip to content

Commit c6e897d

Browse files
Postgresql: Add REPLICA IDENTITY operation for ALTER TABLE (#1844)
1 parent 74a95fd commit c6e897d

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

src/ast/ddl.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ use crate::ast::{
3939
use crate::keywords::Keyword;
4040
use crate::tokenizer::Token;
4141

42+
/// ALTER TABLE operation REPLICA IDENTITY values
43+
/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
44+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
45+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
47+
pub enum ReplicaIdentity {
48+
None,
49+
Full,
50+
Default,
51+
Index(Ident),
52+
}
53+
54+
impl fmt::Display for ReplicaIdentity {
55+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56+
match self {
57+
ReplicaIdentity::None => f.write_str("NONE"),
58+
ReplicaIdentity::Full => f.write_str("FULL"),
59+
ReplicaIdentity::Default => f.write_str("DEFAULT"),
60+
ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {}", idx),
61+
}
62+
}
63+
}
64+
4265
/// An `ALTER TABLE` (`Statement::AlterTable`) operation
4366
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4467
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -208,6 +231,13 @@ pub enum AlterTableOperation {
208231
old_partitions: Vec<Expr>,
209232
new_partitions: Vec<Expr>,
210233
},
234+
/// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
235+
///
236+
/// Note: this is a PostgreSQL-specific operation.
237+
/// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
238+
ReplicaIdentity {
239+
identity: ReplicaIdentity,
240+
},
211241
/// Add Partitions
212242
AddPartitions {
213243
if_not_exists: bool,
@@ -729,6 +759,9 @@ impl fmt::Display for AlterTableOperation {
729759
AlterTableOperation::Lock { equals, lock } => {
730760
write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
731761
}
762+
AlterTableOperation::ReplicaIdentity { identity } => {
763+
write!(f, "REPLICA IDENTITY {identity}")
764+
}
732765
}
733766
}
734767
}

src/ast/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub use self::ddl::{
6565
DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
6666
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
6767
IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
68-
ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
68+
ProcedureParam, ReferentialAction, ReplicaIdentity, TableConstraint, TagsColumnOption,
6969
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
7070
};
7171
pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,7 @@ impl Spanned for AlterTableOperation {
11751175
AlterTableOperation::Algorithm { .. } => Span::empty(),
11761176
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
11771177
AlterTableOperation::Lock { .. } => Span::empty(),
1178+
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
11781179
}
11791180
}
11801181
}

src/parser/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8774,6 +8774,23 @@ impl<'a> Parser<'a> {
87748774
let equals = self.consume_token(&Token::Eq);
87758775
let value = self.parse_number_value()?;
87768776
AlterTableOperation::AutoIncrement { equals, value }
8777+
} else if self.parse_keywords(&[Keyword::REPLICA, Keyword::IDENTITY]) {
8778+
let identity = if self.parse_keyword(Keyword::NONE) {
8779+
ReplicaIdentity::None
8780+
} else if self.parse_keyword(Keyword::FULL) {
8781+
ReplicaIdentity::Full
8782+
} else if self.parse_keyword(Keyword::DEFAULT) {
8783+
ReplicaIdentity::Default
8784+
} else if self.parse_keywords(&[Keyword::USING, Keyword::INDEX]) {
8785+
ReplicaIdentity::Index(self.parse_identifier()?)
8786+
} else {
8787+
return self.expected(
8788+
"NONE, FULL, DEFAULT, or USING INDEX index_name after REPLICA IDENTITY",
8789+
self.peek_token(),
8790+
);
8791+
};
8792+
8793+
AlterTableOperation::ReplicaIdentity { identity }
87778794
} else {
87788795
let options: Vec<SqlOption> =
87798796
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;
@@ -8783,7 +8800,7 @@ impl<'a> Parser<'a> {
87838800
}
87848801
} else {
87858802
return self.expected(
8786-
"ADD, RENAME, PARTITION, SWAP, DROP, or SET TBLPROPERTIES after ALTER TABLE",
8803+
"ADD, RENAME, PARTITION, SWAP, DROP, REPLICA IDENTITY, or SET TBLPROPERTIES after ALTER TABLE",
87878804
self.peek_token(),
87888805
);
87898806
}

tests/sqlparser_postgres.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5959,3 +5959,30 @@ fn parse_varbit_datatype() {
59595959
_ => unreachable!(),
59605960
}
59615961
}
5962+
5963+
#[test]
5964+
fn parse_alter_table_replica_identity() {
5965+
match pg_and_generic().verified_stmt("ALTER TABLE foo REPLICA IDENTITY FULL") {
5966+
Statement::AlterTable { operations, .. } => {
5967+
assert_eq!(
5968+
operations,
5969+
vec![AlterTableOperation::ReplicaIdentity {
5970+
identity: ReplicaIdentity::Full
5971+
}]
5972+
);
5973+
}
5974+
_ => unreachable!(),
5975+
}
5976+
5977+
match pg_and_generic().verified_stmt("ALTER TABLE foo REPLICA IDENTITY USING INDEX foo_idx") {
5978+
Statement::AlterTable { operations, .. } => {
5979+
assert_eq!(
5980+
operations,
5981+
vec![AlterTableOperation::ReplicaIdentity {
5982+
identity: ReplicaIdentity::Index("foo_idx".into())
5983+
}]
5984+
);
5985+
}
5986+
_ => unreachable!(),
5987+
}
5988+
}

0 commit comments

Comments
 (0)