diff --git a/src/executor/insert.rs b/src/executor/insert.rs
index 2b7168388..665fa5bee 100644
--- a/src/executor/insert.rs
+++ b/src/executor/insert.rs
@@ -1,6 +1,7 @@
use crate::{
- error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel,
- Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, SelectModel, SelectorRaw, TryFromU64, TryInsert,
+ error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, DbBackend, EntityTrait, Insert,
+ IntoActiveModel, Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, SelectModel, SelectorRaw,
+ TryFromU64, TryInsert,
};
use sea_query::{FromValueTuple, Iden, InsertStatement, Query, ValueTuple};
use std::{future::Future, marker::PhantomData};
@@ -245,6 +246,14 @@ where
return Err(DbErr::RecordNotInserted);
}
let last_insert_id = res.last_insert_id();
+ // For MySQL, the affected-rows number:
+ // - The affected-rows value per row is `1` if the row is inserted as a new row,
+ // - `2` if an existing row is updated,
+ // - and `0` if an existing row is set to its current values.
+ // Reference: https://dev.mysql.com/doc/refman/8.4/en/insert-on-duplicate.html
+ if db_backend == DbBackend::MySql && last_insert_id == 0 {
+ return Err(DbErr::RecordNotInserted);
+ }
ValueTypeOf::::try_from_u64(last_insert_id).map_err(|_| DbErr::UnpackInsertId)?
}
};
diff --git a/src/query/insert.rs b/src/query/insert.rs
index 3e26e0110..457d1d1e7 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -225,6 +225,21 @@ where
{
TryInsert::from_insert(self)
}
+
+ /// On conflict do nothing
+ pub fn on_conflict_do_nothing(mut self) -> TryInsert
+ where
+ A: ActiveModelTrait,
+ {
+ let primary_keys = ::PrimaryKey::iter();
+ self.query.on_conflict(
+ OnConflict::columns(primary_keys.clone())
+ .do_nothing_on(primary_keys)
+ .to_owned(),
+ );
+
+ TryInsert::from_insert(self)
+ }
}
impl QueryTrait for Insert
diff --git a/tests/empty_insert_tests.rs b/tests/empty_insert_tests.rs
index 46642fa2e..e902a4fac 100644
--- a/tests/empty_insert_tests.rs
+++ b/tests/empty_insert_tests.rs
@@ -34,12 +34,19 @@ pub async fn test(db: &DbConn) {
assert!(matches!(res, Ok(TryInsertResult::Inserted(_))));
- let _double_seaside_bakery = bakery::ActiveModel {
+ let double_seaside_bakery = bakery::ActiveModel {
name: Set("SeaSide Bakery".to_owned()),
profit_margin: Set(10.4),
id: Set(1),
};
+ let conflict_insert = Bakery::insert_many([double_seaside_bakery])
+ .on_conflict_do_nothing()
+ .exec(db)
+ .await;
+
+ assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted)));
+
let empty_insert = Bakery::insert_many(std::iter::empty::())
.on_empty_do_nothing()
.exec(db)
diff --git a/tests/upsert_tests.rs b/tests/upsert_tests.rs
index 4879e4788..84e8b88d3 100644
--- a/tests/upsert_tests.rs
+++ b/tests/upsert_tests.rs
@@ -9,7 +9,6 @@ use sea_orm::TryInsertResult;
use sea_orm::{sea_query::OnConflict, Set};
#[sea_orm_macros::test]
-#[cfg(feature = "sqlx-postgres")]
async fn main() -> Result<(), DbErr> {
let ctx = TestContext::new("upsert_tests").await;
create_tables(&ctx.db).await?;
@@ -22,7 +21,9 @@ async fn main() -> Result<(), DbErr> {
pub async fn create_insert_default(db: &DatabaseConnection) -> Result<(), DbErr> {
use insert_default::*;
- let on_conflict = OnConflict::column(Column::Id).do_nothing().to_owned();
+ let on_conflict = OnConflict::column(Column::Id)
+ .do_nothing_on([Column::Id])
+ .to_owned();
let res = Entity::insert_many([
ActiveModel { id: Set(1) },