diff --git a/models/attachment.go b/models/attachment.go index 330e965bb11c9..96048db00a880 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -272,3 +272,16 @@ func IterateAttachment(f func(attach *Attachment) error) error { } } } + +// CountOrphanedAttachments returns the number of bad attachments +func CountOrphanedAttachments() (int64, error) { + return x.Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). + Count(new(Attachment)) +} + +// DeleteOrphanedAttachments delete all bad attachments +func DeleteOrphanedAttachments() error { + _, err := x.Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). + Delete(new(Attachment)) + return err +} diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index 23e8331e774a3..0d84c63976b8e 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -74,6 +74,24 @@ func checkDBConsistency(logger log.Logger, autofix bool) error { } } + // find releases without existing repository + count, err = models.CountOrphanedObjects("release", "repository", "release.repo_id=repository.id") + if err != nil { + logger.Critical("Error: %v whilst counting orphaned objects", err) + return err + } + if count > 0 { + if autofix { + if err = models.DeleteOrphanedObjects("release", "repository", "release.repo_id=repository.id"); err != nil { + logger.Critical("Error: %v whilst deleting orphaned objects", err) + return err + } + logger.Info("%d releases without existing repository deleted", count) + } else { + logger.Warn("%d releases without existing repository", count) + } + } + // find pulls without existing issues count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") if err != nil { @@ -110,6 +128,24 @@ func checkDBConsistency(logger log.Logger, autofix bool) error { } } + // find attachments without existing issues or releases + count, err = models.CountOrphanedAttachments() + if err != nil { + logger.Critical("Error: %v whilst counting orphaned objects", err) + return err + } + if count > 0 { + if autofix { + if err = models.DeleteOrphanedAttachments(); err != nil { + logger.Critical("Error: %v whilst deleting orphaned objects", err) + return err + } + logger.Info("%d attachments without existing issue or release deleted", count) + } else { + logger.Warn("%d attachments without existing issue or release", count) + } + } + // find null archived repositories count, err = models.CountNullArchivedRepository() if err != nil {