|
5 | 5 | package models
|
6 | 6 |
|
7 | 7 | import (
|
| 8 | + "errors" |
8 | 9 | "fmt"
|
9 | 10 | "path"
|
10 | 11 | "regexp"
|
|
73 | 74 |
|
74 | 75 | const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)`
|
75 | 76 | const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)`
|
76 |
| -const issueMaxDupIndexAttempts = 3 |
77 | 77 |
|
78 | 78 | func init() {
|
79 | 79 | issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
|
@@ -1053,9 +1053,36 @@ type NewIssueOptions struct {
|
1053 | 1053 | IsPull bool
|
1054 | 1054 | }
|
1055 | 1055 |
|
| 1056 | +// GetMaxIndexOfIssue returns the max index on issue |
| 1057 | +func GetMaxIndexOfIssue(repoID int64) (int64, error) { |
| 1058 | + return getMaxIndexOfIssue(x, repoID) |
| 1059 | +} |
| 1060 | + |
| 1061 | +func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) { |
| 1062 | + var ( |
| 1063 | + maxIndex int64 |
| 1064 | + has bool |
| 1065 | + err error |
| 1066 | + ) |
| 1067 | + |
| 1068 | + has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex) |
| 1069 | + if err != nil { |
| 1070 | + return 0, err |
| 1071 | + } else if !has { |
| 1072 | + return 0, errors.New("Retrieve Max index from issue failed") |
| 1073 | + } |
| 1074 | + return maxIndex, nil |
| 1075 | +} |
| 1076 | + |
1056 | 1077 | func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
|
1057 | 1078 | opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
|
1058 | 1079 |
|
| 1080 | + maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID) |
| 1081 | + if err != nil { |
| 1082 | + return err |
| 1083 | + } |
| 1084 | + opts.Issue.Index = maxIndex + 1 |
| 1085 | + |
1059 | 1086 | if opts.Issue.MilestoneID > 0 {
|
1060 | 1087 | milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID)
|
1061 | 1088 | if err != nil && !IsErrMilestoneNotExist(err) {
|
@@ -1104,31 +1131,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
|
1104 | 1131 | }
|
1105 | 1132 |
|
1106 | 1133 | // Milestone and assignee validation should happen before insert actual object.
|
1107 |
| - |
1108 |
| - // There's no good way to identify a duplicate key error in database/sql; brute force some retries |
1109 |
| - dupIndexAttempts := issueMaxDupIndexAttempts |
1110 |
| - for { |
1111 |
| - _, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). |
1112 |
| - Where("repo_id=?", opts.Issue.RepoID). |
1113 |
| - Insert(opts.Issue) |
1114 |
| - if err == nil { |
1115 |
| - break |
1116 |
| - } |
1117 |
| - |
1118 |
| - dupIndexAttempts-- |
1119 |
| - if dupIndexAttempts <= 0 { |
1120 |
| - return err |
1121 |
| - } |
1122 |
| - } |
1123 |
| - |
1124 |
| - inserted, err := getIssueByID(e, opts.Issue.ID) |
1125 |
| - if err != nil { |
| 1134 | + if _, err = e.Insert(opts.Issue); err != nil { |
1126 | 1135 | return err
|
1127 | 1136 | }
|
1128 | 1137 |
|
1129 |
| - // Patch Index with the value calculated by the database |
1130 |
| - opts.Issue.Index = inserted.Index |
1131 |
| - |
1132 | 1138 | if opts.Issue.MilestoneID > 0 {
|
1133 | 1139 | if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil {
|
1134 | 1140 | return err
|
|
0 commit comments