Generalize conflict target (#762)

Postgres supports `ON CONFLICT ON CONSTRAINT <constraint_name>` to
explicitly name the constraint that fails. Support this.
This commit is contained in:
Audun Skaugen 2022-12-17 13:38:57 +01:00 committed by GitHub
parent 6d6eb4bc9b
commit 3d5cc54dcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 15 deletions

View file

@ -2728,11 +2728,17 @@ pub enum OnInsert {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OnConflict {
pub conflict_target: Vec<Ident>,
pub conflict_target: Option<ConflictTarget>,
pub action: OnConflictAction,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ConflictTarget {
Columns(Vec<Ident>),
OnConstraint(ObjectName),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OnConflictAction {
DoNothing,
DoUpdate(DoUpdate),
@ -2762,12 +2768,20 @@ impl fmt::Display for OnInsert {
impl fmt::Display for OnConflict {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, " ON CONFLICT")?;
if !self.conflict_target.is_empty() {
write!(f, "({})", display_comma_separated(&self.conflict_target))?;
if let Some(target) = &self.conflict_target {
write!(f, "{}", target)?;
}
write!(f, " {}", self.action)
}
}
impl fmt::Display for ConflictTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ConflictTarget::Columns(cols) => write!(f, "({})", display_comma_separated(cols)),
ConflictTarget::OnConstraint(name) => write!(f, " ON CONSTRAINT {}", name),
}
}
}
impl fmt::Display for OnConflictAction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {

View file

@ -5630,7 +5630,15 @@ impl<'a> Parser<'a> {
let on = if self.parse_keyword(Keyword::ON) {
if self.parse_keyword(Keyword::CONFLICT) {
let conflict_target =
self.parse_parenthesized_column_list(IsOptional::Optional)?;
if self.parse_keywords(&[Keyword::ON, Keyword::CONSTRAINT]) {
Some(ConflictTarget::OnConstraint(self.parse_object_name()?))
} else if self.peek_token() == Token::LParen {
Some(ConflictTarget::Columns(
self.parse_parenthesized_column_list(IsOptional::Mandatory)?,
))
} else {
None
};
self.expect_keyword(Keyword::DO)?;
let action = if self.parse_keyword(Keyword::NOTHING) {