Fix #22109 --------- Co-authored-by: silverwind <me@silverwind.io>tags/v1.21.0-rc0
@@ -89,6 +89,33 @@ func mysqlGetNextResourceIndex(ctx context.Context, tableName string, groupID in | |||
return idx, nil | |||
} | |||
func mssqlGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { | |||
if _, err := GetEngine(ctx).Exec(fmt.Sprintf(` | |||
MERGE INTO %s WITH (HOLDLOCK) AS target | |||
USING (SELECT %d AS group_id) AS source | |||
(group_id) | |||
ON target.group_id = source.group_id | |||
WHEN MATCHED | |||
THEN UPDATE | |||
SET max_index = max_index + 1 | |||
WHEN NOT MATCHED | |||
THEN INSERT (group_id, max_index) | |||
VALUES (%d, 1); | |||
`, tableName, groupID, groupID)); err != nil { | |||
return 0, err | |||
} | |||
var idx int64 | |||
_, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&idx) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if idx == 0 { | |||
return 0, errors.New("cannot get the correct index") | |||
} | |||
return idx, nil | |||
} | |||
// GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created | |||
func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { | |||
switch { | |||
@@ -96,6 +123,8 @@ func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) | |||
return postgresGetNextResourceIndex(ctx, tableName, groupID) | |||
case setting.Database.Type.IsMySQL(): | |||
return mysqlGetNextResourceIndex(ctx, tableName, groupID) | |||
case setting.Database.Type.IsMSSQL(): | |||
return mssqlGetNextResourceIndex(ctx, tableName, groupID) | |||
} | |||
e := GetEngine(ctx) |
@@ -83,13 +83,47 @@ func mysqlGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (i | |||
return idx, nil | |||
} | |||
func mssqlGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { | |||
if _, err := db.GetEngine(ctx).Exec(` | |||
MERGE INTO commit_status_index WITH (HOLDLOCK) AS target | |||
USING (SELECT ? AS repo_id, ? AS sha) AS source | |||
(repo_id, sha) | |||
ON target.repo_id = source.repo_id AND target.sha = source.sha | |||
WHEN MATCHED | |||
THEN UPDATE | |||
SET max_index = max_index + 1 | |||
WHEN NOT MATCHED | |||
THEN INSERT (repo_id, sha, max_index) | |||
VALUES (?, ?, 1); | |||
`, repoID, sha, repoID, sha); err != nil { | |||
return 0, err | |||
} | |||
var idx int64 | |||
_, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", | |||
repoID, sha).Get(&idx) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if idx == 0 { | |||
return 0, errors.New("cannot get the correct index") | |||
} | |||
return idx, nil | |||
} | |||
// GetNextCommitStatusIndex retried 3 times to generate a resource index | |||
func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { | |||
if !git.IsValidSHAPattern(sha) { | |||
return 0, git.ErrInvalidSHA{SHA: sha} | |||
} | |||
switch { | |||
case setting.Database.Type.IsPostgreSQL(): | |||
return postgresGetCommitStatusIndex(ctx, repoID, sha) | |||
case setting.Database.Type.IsMySQL(): | |||
return mysqlGetCommitStatusIndex(ctx, repoID, sha) | |||
case setting.Database.Type.IsMSSQL(): | |||
return mssqlGetCommitStatusIndex(ctx, repoID, sha) | |||
} | |||
e := db.GetEngine(ctx) |
@@ -28,6 +28,14 @@ func IsValidSHAPattern(sha string) bool { | |||
return shaPattern.MatchString(sha) | |||
} | |||
type ErrInvalidSHA struct { | |||
SHA string | |||
} | |||
func (err ErrInvalidSHA) Error() string { | |||
return fmt.Sprintf("invalid sha: %s", err.SHA) | |||
} | |||
// MustID always creates a new SHA1 from a [20]byte array with no validation of input. | |||
func MustID(b []byte) SHA1 { | |||
var id SHA1 |