update on conflict method (#735)

This commit is contained in:
zidaye 2022-12-01 02:33:33 +08:00 committed by GitHub
parent a422116b89
commit 042effdf14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 94 additions and 18 deletions

View file

@ -2702,7 +2702,16 @@ pub struct OnConflict {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OnConflictAction {
DoNothing,
DoUpdate(Vec<Assignment>),
DoUpdate(DoUpdate),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DoUpdate {
/// Column assignments
pub assignments: Vec<Assignment>,
/// WHERE
pub selection: Option<Expr>,
}
impl fmt::Display for OnInsert {
@ -2730,7 +2739,20 @@ impl fmt::Display for OnConflictAction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::DoNothing => write!(f, "DO NOTHING"),
Self::DoUpdate(a) => write!(f, "DO UPDATE SET {}", display_comma_separated(a)),
Self::DoUpdate(do_update) => {
write!(f, "DO UPDATE")?;
if !do_update.assignments.is_empty() {
write!(
f,
" SET {}",
display_comma_separated(&do_update.assignments)
)?;
}
if let Some(selection) = &do_update.selection {
write!(f, " WHERE {}", selection)?;
}
Ok(())
}
}
}
}

View file

@ -5351,8 +5351,16 @@ impl<'a> Parser<'a> {
} else {
self.expect_keyword(Keyword::UPDATE)?;
self.expect_keyword(Keyword::SET)?;
let l = self.parse_comma_separated(Parser::parse_assignment)?;
OnConflictAction::DoUpdate(l)
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
let selection = if self.parse_keyword(Keyword::WHERE) {
Some(self.parse_expr()?)
} else {
None
};
OnConflictAction::DoUpdate(DoUpdate {
assignments,
selection,
})
};
Some(OnInsert::OnConflict(OnConflict {

View file

@ -1117,10 +1117,13 @@ fn parse_pg_on_conflict() {
} => {
assert_eq!(vec![Ident::from("did")], conflict_target);
assert_eq!(
OnConflictAction::DoUpdate(vec![Assignment {
OnConflictAction::DoUpdate(DoUpdate {
assignments: vec![Assignment {
id: vec!["dname".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "dname".into()])
},]),
},],
selection: None
}),
action
);
}
@ -1147,16 +1150,22 @@ fn parse_pg_on_conflict() {
conflict_target
);
assert_eq!(
OnConflictAction::DoUpdate(vec![
OnConflictAction::DoUpdate(DoUpdate {
assignments: vec![
Assignment {
id: vec!["dname".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "dname".into()])
value: Expr::CompoundIdentifier(vec![
"EXCLUDED".into(),
"dname".into()
])
},
Assignment {
id: vec!["area".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "area".into()])
},
]),
],
selection: None
}),
action
);
}
@ -1182,6 +1191,43 @@ fn parse_pg_on_conflict() {
}
_ => unreachable!(),
};
let stmt = pg_and_generic().verified_stmt(
"INSERT INTO distributors (did, dname, dsize) \
VALUES (5, 'Gizmo Transglobal', 1000), (6, 'Associated Computing, Inc', 1010) \
ON CONFLICT(did) \
DO UPDATE SET dname = $1 WHERE dsize > $2",
);
match stmt {
Statement::Insert {
on:
Some(OnInsert::OnConflict(OnConflict {
conflict_target,
action,
})),
..
} => {
assert_eq!(vec![Ident::from("did")], conflict_target);
assert_eq!(
OnConflictAction::DoUpdate(DoUpdate {
assignments: vec![Assignment {
id: vec!["dname".into()],
value: Expr::Value(Value::Placeholder("$1".to_string()))
},],
selection: Some(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident {
value: "dsize".to_string(),
quote_style: None
})),
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(Value::Placeholder("$2".to_string())))
})
}),
action
);
}
_ => unreachable!(),
};
}
#[test]