Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-11-16 04:12:53 +01:00
Fixed foreign-key (mariadb) errors.
When using MariaDB v10.5+ Foreign-Key errors were popping up because of some changes in that version. To mitigate this on MariaDB and other MySQL forks those errors are now catched, and instead of a replace_into an update will happen. I have tested this as thorough as possible with MariaDB 10.5, 10.4, 10.3 and the default MySQL on Ubuntu Focal. And tested it again using sqlite, all seems to be ok on all tables. resolves #1081. resolves #1065, resolves #1050
Dieser Commit ist enthalten in:
Ursprung
2f3e18caa9
Commit
978be0b4a9
8 geänderte Dateien mit 170 neuen und 45 gelöschten Zeilen
|
@ -63,11 +63,22 @@ impl Attachment {
|
||||||
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(attachments::table)
|
match diesel::replace_into(attachments::table)
|
||||||
.values(AttachmentDb::to_db(self))
|
.values(AttachmentDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(attachments::table)
|
||||||
|
.filter(attachments::id.eq(&self.id))
|
||||||
|
.set(AttachmentDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving attachment")
|
.map_res("Error saving attachment")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving attachment")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = AttachmentDb::to_db(self);
|
let value = AttachmentDb::to_db(self);
|
||||||
diesel::insert_into(attachments::table)
|
diesel::insert_into(attachments::table)
|
||||||
|
|
|
@ -197,11 +197,22 @@ impl Cipher {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(ciphers::table)
|
match diesel::replace_into(ciphers::table)
|
||||||
.values(CipherDb::to_db(self))
|
.values(CipherDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(ciphers::table)
|
||||||
|
.filter(ciphers::uuid.eq(&self.uuid))
|
||||||
|
.set(CipherDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving cipher")
|
.map_res("Error saving cipher")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving cipher")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = CipherDb::to_db(self);
|
let value = CipherDb::to_db(self);
|
||||||
diesel::insert_into(ciphers::table)
|
diesel::insert_into(ciphers::table)
|
||||||
|
|
|
@ -69,11 +69,22 @@ impl Collection {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(collections::table)
|
match diesel::replace_into(collections::table)
|
||||||
.values(CollectionDb::to_db(self))
|
.values(CollectionDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(collections::table)
|
||||||
|
.filter(collections::uuid.eq(&self.uuid))
|
||||||
|
.set(CollectionDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving collection")
|
.map_res("Error saving collection")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving collection")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = CollectionDb::to_db(self);
|
let value = CollectionDb::to_db(self);
|
||||||
diesel::insert_into(collections::table)
|
diesel::insert_into(collections::table)
|
||||||
|
@ -247,7 +258,7 @@ impl CollectionUser {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(users_collections::table)
|
match diesel::replace_into(users_collections::table)
|
||||||
.values((
|
.values((
|
||||||
users_collections::user_uuid.eq(user_uuid),
|
users_collections::user_uuid.eq(user_uuid),
|
||||||
users_collections::collection_uuid.eq(collection_uuid),
|
users_collections::collection_uuid.eq(collection_uuid),
|
||||||
|
@ -255,8 +266,25 @@ impl CollectionUser {
|
||||||
users_collections::hide_passwords.eq(hide_passwords),
|
users_collections::hide_passwords.eq(hide_passwords),
|
||||||
))
|
))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(users_collections::table)
|
||||||
|
.filter(users_collections::user_uuid.eq(user_uuid))
|
||||||
|
.filter(users_collections::collection_uuid.eq(collection_uuid))
|
||||||
|
.set((
|
||||||
|
users_collections::user_uuid.eq(user_uuid),
|
||||||
|
users_collections::collection_uuid.eq(collection_uuid),
|
||||||
|
users_collections::read_only.eq(read_only),
|
||||||
|
users_collections::hide_passwords.eq(hide_passwords),
|
||||||
|
))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error adding user to collection")
|
.map_res("Error adding user to collection")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error adding user to collection")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
diesel::insert_into(users_collections::table)
|
diesel::insert_into(users_collections::table)
|
||||||
.values((
|
.values((
|
||||||
|
@ -346,6 +374,9 @@ impl CollectionCipher {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
|
// Not checking for ForeignKey Constraints here.
|
||||||
|
// Table ciphers_collections does not have ForeignKey Constraints which would cause conflicts.
|
||||||
|
// This table has no constraints pointing to itself, but only to others.
|
||||||
diesel::replace_into(ciphers_collections::table)
|
diesel::replace_into(ciphers_collections::table)
|
||||||
.values((
|
.values((
|
||||||
ciphers_collections::cipher_uuid.eq(cipher_uuid),
|
ciphers_collections::cipher_uuid.eq(cipher_uuid),
|
||||||
|
|
|
@ -76,11 +76,22 @@ impl Folder {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(folders::table)
|
match diesel::replace_into(folders::table)
|
||||||
.values(FolderDb::to_db(self))
|
.values(FolderDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(folders::table)
|
||||||
|
.filter(folders::uuid.eq(&self.uuid))
|
||||||
|
.set(FolderDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving folder")
|
.map_res("Error saving folder")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving folder")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = FolderDb::to_db(self);
|
let value = FolderDb::to_db(self);
|
||||||
diesel::insert_into(folders::table)
|
diesel::insert_into(folders::table)
|
||||||
|
@ -138,6 +149,9 @@ impl FolderCipher {
|
||||||
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
|
// Not checking for ForeignKey Constraints here.
|
||||||
|
// Table folders_ciphers does not have ForeignKey Constraints which would cause conflicts.
|
||||||
|
// This table has no constraints pointing to itself, but only to others.
|
||||||
diesel::replace_into(folders_ciphers::table)
|
diesel::replace_into(folders_ciphers::table)
|
||||||
.values(FolderCipherDb::to_db(self))
|
.values(FolderCipherDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
|
|
@ -58,11 +58,22 @@ impl OrgPolicy {
|
||||||
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(org_policies::table)
|
match diesel::replace_into(org_policies::table)
|
||||||
.values(OrgPolicyDb::to_db(self))
|
.values(OrgPolicyDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(org_policies::table)
|
||||||
|
.filter(org_policies::uuid.eq(&self.uuid))
|
||||||
|
.set(OrgPolicyDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving org_policy")
|
.map_res("Error saving org_policy")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving org_policy")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = OrgPolicyDb::to_db(self);
|
let value = OrgPolicyDb::to_db(self);
|
||||||
// We need to make sure we're not going to violate the unique constraint on org_uuid and atype.
|
// We need to make sure we're not going to violate the unique constraint on org_uuid and atype.
|
||||||
|
|
|
@ -206,11 +206,23 @@ impl Organization {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(organizations::table)
|
match diesel::replace_into(organizations::table)
|
||||||
.values(OrganizationDb::to_db(self))
|
.values(OrganizationDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(organizations::table)
|
||||||
|
.filter(organizations::uuid.eq(&self.uuid))
|
||||||
|
.set(OrganizationDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving organization")
|
.map_res("Error saving organization")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving organization")
|
||||||
|
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = OrganizationDb::to_db(self);
|
let value = OrganizationDb::to_db(self);
|
||||||
diesel::insert_into(organizations::table)
|
diesel::insert_into(organizations::table)
|
||||||
|
@ -345,11 +357,22 @@ impl UserOrganization {
|
||||||
|
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(users_organizations::table)
|
match diesel::replace_into(users_organizations::table)
|
||||||
.values(UserOrganizationDb::to_db(self))
|
.values(UserOrganizationDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(users_organizations::table)
|
||||||
|
.filter(users_organizations::uuid.eq(&self.uuid))
|
||||||
|
.set(UserOrganizationDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error adding user to organization")
|
.map_res("Error adding user to organization")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error adding user to organization")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = UserOrganizationDb::to_db(self);
|
let value = UserOrganizationDb::to_db(self);
|
||||||
diesel::insert_into(users_organizations::table)
|
diesel::insert_into(users_organizations::table)
|
||||||
|
|
|
@ -73,11 +73,22 @@ impl TwoFactor {
|
||||||
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
pub fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(twofactor::table)
|
match diesel::replace_into(twofactor::table)
|
||||||
.values(TwoFactorDb::to_db(self))
|
.values(TwoFactorDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(twofactor::table)
|
||||||
|
.filter(twofactor::uuid.eq(&self.uuid))
|
||||||
|
.set(TwoFactorDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
.map_res("Error saving twofactor")
|
.map_res("Error saving twofactor")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving twofactor")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = TwoFactorDb::to_db(self);
|
let value = TwoFactorDb::to_db(self);
|
||||||
// We need to make sure we're not going to violate the unique constraint on user_uuid and atype.
|
// We need to make sure we're not going to violate the unique constraint on user_uuid and atype.
|
||||||
|
|
|
@ -175,11 +175,22 @@ impl User {
|
||||||
|
|
||||||
db_run! {conn:
|
db_run! {conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
diesel::replace_into(users::table) // Insert or update
|
match diesel::replace_into(users::table)
|
||||||
.values(&UserDb::to_db(self))
|
.values(UserDb::to_db(self))
|
||||||
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||||
|
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||||
|
diesel::update(users::table)
|
||||||
|
.filter(users::uuid.eq(&self.uuid))
|
||||||
|
.set(UserDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.map_res("Error saving user")
|
.map_res("Error saving user")
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}.map_res("Error saving user")
|
||||||
|
}
|
||||||
postgresql {
|
postgresql {
|
||||||
let value = UserDb::to_db(self);
|
let value = UserDb::to_db(self);
|
||||||
diesel::insert_into(users::table) // Insert or update
|
diesel::insert_into(users::table) // Insert or update
|
||||||
|
@ -290,6 +301,8 @@ impl Invitation {
|
||||||
|
|
||||||
db_run! {conn:
|
db_run! {conn:
|
||||||
sqlite, mysql {
|
sqlite, mysql {
|
||||||
|
// Not checking for ForeignKey Constraints here
|
||||||
|
// Table invitations does not have any ForeignKey Constraints.
|
||||||
diesel::replace_into(invitations::table)
|
diesel::replace_into(invitations::table)
|
||||||
.values(InvitationDb::to_db(self))
|
.values(InvitationDb::to_db(self))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
|
Laden …
In neuem Issue referenzieren