Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ require (
mvdan.cc/xurls/v2 v2.4.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.12
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75
xorm.io/xorm v1.3.3-0.20230701034009-d29fe4993351
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1923,5 +1923,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75 h1:ReBAlO50dCIXCWF8Gbi0ZRa62AGAwCJNCPaUNUa7JSg=
xorm.io/xorm v1.3.3-0.20230623150031-18f8e7a86c75/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
xorm.io/xorm v1.3.3-0.20230701034009-d29fe4993351 h1:zjbf38FKz2hcqIspgMXYhwhGfy4iXZ/7YBqyv9ZNz8I=
xorm.io/xorm v1.3.3-0.20230701034009-d29fe4993351/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
21 changes: 20 additions & 1 deletion models/git/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

"xorm.io/xorm/schemas"
)

// ErrBranchNotExist represents an error that branch with such name does not exist.
Expand Down Expand Up @@ -101,7 +104,7 @@ func (err ErrBranchesEqual) Unwrap() error {
type Branch struct {
ID int64
RepoID int64 `xorm:"UNIQUE(s)"`
Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
Name string `xorm:"UNIQUE(s) NOT NULL"`
CommitID string
CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line)
PusherID int64
Expand All @@ -115,6 +118,22 @@ type Branch struct {
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

// TableCollations git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
// so we need to set the collation to case-sensitive which is utf8mb4_bin for mysql and Latin1_General_CS_AS for mssql
// the function is supported by xorm
func (b *Branch) TableCollations() []*schemas.Collation {
if setting.Database.Type.IsMySQL() {
return []*schemas.Collation{
{Name: "utf8mb4_bin", Column: "name"},
}
} else if setting.Database.Type.IsMSSQL() {
return []*schemas.Collation{
{Name: "Latin1_General_CS_AS", Column: "name"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC SQLServer doesn't treat this collation as UTF-8 internally.

So it's better to add a test for it to make sure wide UTF-8 chars (eg: emoji) can be inserted and selected correctly.

}
}
return nil
}

func (b *Branch) LoadDeletedBy(ctx context.Context) (err error) {
if b.DeletedBy == nil {
b.DeletedBy, err = user_model.GetUserByID(ctx, b.DeletedByID)
Expand Down
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,8 @@ var migrations = []Migration{
NewMigration("Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable),
// v264 -> v265
NewMigration("Add branch table", v1_21.AddBranchTable),
// v265 -> v266
NewMigration("Change Branch name column collation to support case sensitive", v1_21.BranchColumnNameCollation),
}

// GetCurrentDBVersion returns the current db version
Expand Down
21 changes: 21 additions & 0 deletions models/migrations/v1_21/v265.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_21 //nolint

import (
"code.gitea.io/gitea/modules/setting"

"xorm.io/xorm"
)

func BranchColumnNameCollation(x *xorm.Engine) error {
if setting.Database.Type.IsMySQL() {
_, err := x.Exec("ALTER TABLE branch MODIFY COLUMN `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL")
return err
} else if setting.Database.Type.IsMSSQL() {
_, err := x.Exec("ALTER TABLE [branch] COLUMN [name] nvarchar(255) COLLATE Latin1_General_CS_AS NOT NULL;")
return err
}
return nil
}
29 changes: 29 additions & 0 deletions models/migrations/v1_21/v265_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_21 //nolint

import (
"testing"

"code.gitea.io/gitea/models/migrations/base"

"github.com/stretchr/testify/assert"
)

func Test_BranchColumnNameCollation(t *testing.T) {
type Branch struct {
ID int64
RepoID int64 `xorm:"Unique(s)"`
Name string `xorm:"Unique(s) NOT NULL"`
}

// Prepare and load the testing database
x, deferable := base.PrepareTestEnv(t, 0, new(Branch))
defer deferable()
if x == nil || t.Failed() {
return
}

assert.NoError(t, BranchColumnNameCollation(x))
}