diff options
author | guillep2k <18600385+guillep2k@users.noreply.github.com> | 2019-08-26 23:17:23 -0300 |
---|---|---|
committer | techknowlogick <techknowlogick@gitea.io> | 2019-08-26 22:17:23 -0400 |
commit | 5fe2ec264febd6a4112c5f8c72c170f016bdf0c8 (patch) | |
tree | bc1261858b8278189d7b30c51faaa9b442245d0d /models/issue.go | |
parent | 541fab196f216771a51419a8b8d353694afa6c45 (diff) | |
download | gitea-5fe2ec264febd6a4112c5f8c72c170f016bdf0c8.tar.gz gitea-5fe2ec264febd6a4112c5f8c72c170f016bdf0c8.zip |
Retry create issue to cope with duplicate keys (#7898)
* Retry create issue to cope with duplicate keys
* Use .SetExpr().Where().Insert()
Diffstat (limited to 'models/issue.go')
-rw-r--r-- | models/issue.go | 52 |
1 files changed, 23 insertions, 29 deletions
diff --git a/models/issue.go b/models/issue.go index fc74c73162..b849f97bd4 100644 --- a/models/issue.go +++ b/models/issue.go @@ -5,7 +5,6 @@ package models import ( - "errors" "fmt" "path" "regexp" @@ -74,6 +73,7 @@ var ( const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)` const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)` +const issueMaxDupIndexAttempts = 3 func init() { issueTasksPat = regexp.MustCompile(issueTasksRegexpStr) @@ -1031,36 +1031,9 @@ type NewIssueOptions struct { IsPull bool } -// GetMaxIndexOfIssue returns the max index on issue -func GetMaxIndexOfIssue(repoID int64) (int64, error) { - return getMaxIndexOfIssue(x, repoID) -} - -func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) { - var ( - maxIndex int64 - has bool - err error - ) - - has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex) - if err != nil { - return 0, err - } else if !has { - return 0, errors.New("Retrieve Max index from issue failed") - } - return maxIndex, nil -} - func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) - maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID) - if err != nil { - return err - } - opts.Issue.Index = maxIndex + 1 - if opts.Issue.MilestoneID > 0 { milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID) if err != nil && !IsErrMilestoneNotExist(err) { @@ -1109,10 +1082,31 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { } // Milestone and assignee validation should happen before insert actual object. - if _, err = e.Insert(opts.Issue); err != nil { + + // There's no good way to identify a duplicate key error in database/sql; brute force some retries + dupIndexAttempts := issueMaxDupIndexAttempts + for { + _, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). + Where("repo_id=?", opts.Issue.RepoID). + Insert(opts.Issue) + if err == nil { + break + } + + dupIndexAttempts-- + if dupIndexAttempts <= 0 { + return err + } + } + + inserted, err := getIssueByID(e, opts.Issue.ID) + if err != nil { return err } + // Patch Index with the value calculated by the database + opts.Issue.Index = inserted.Index + if opts.Issue.MilestoneID > 0 { if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil { return err |