Skip to content

Commit 71ca306

Browse files
wolfogrezeripath
andauthored
Check primary keys for all tables and drop ForeignReference (#21721)
Some dbs require that all tables have primary keys, see - #16802 - #21086 We can add a test to keep it from being broken again. Edit: ~Added missing primary key for `ForeignReference`~ Dropped the `ForeignReference` table to satisfy the check, so it closes #21086. More context can be found in comments. Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: zeripath <[email protected]>
1 parent 41f0668 commit 71ca306

File tree

11 files changed

+55
-203
lines changed

11 files changed

+55
-203
lines changed

Diff for: models/db/engine_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"code.gitea.io/gitea/models/unittest"
1313
"code.gitea.io/gitea/modules/setting"
1414

15+
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
16+
1517
"github.com/stretchr/testify/assert"
1618
)
1719

@@ -51,3 +53,34 @@ func TestDeleteOrphanedObjects(t *testing.T) {
5153
assert.NoError(t, err)
5254
assert.EqualValues(t, countBefore, countAfter)
5355
}
56+
57+
func TestPrimaryKeys(t *testing.T) {
58+
// Some dbs require that all tables have primary keys, see
59+
// https://github.com/go-gitea/gitea/issues/21086
60+
// https://github.com/go-gitea/gitea/issues/16802
61+
// To avoid creating tables without primary key again, this test will check them.
62+
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
63+
64+
beans, err := db.NamesToBean()
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
69+
whitelist := map[string]string{
70+
"the_table_name_to_skip_checking": "Write a note here to explain why",
71+
}
72+
73+
for _, bean := range beans {
74+
table, err := db.TableInfo(bean)
75+
if err != nil {
76+
t.Fatal(err)
77+
}
78+
if why, ok := whitelist[table.Name]; ok {
79+
t.Logf("ignore %q because %q", table.Name, why)
80+
continue
81+
}
82+
if len(table.PrimaryKeys) == 0 {
83+
t.Errorf("table %q has no primary key", table.Name)
84+
}
85+
}
86+
}

Diff for: models/fixtures/foreign_reference.yml

-1
This file was deleted.

Diff for: models/foreignreference/error.go

-52
This file was deleted.

Diff for: models/foreignreference/foreignreference.go

-31
This file was deleted.

Diff for: models/issues/issue.go

+5-55
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import (
99
"fmt"
1010
"regexp"
1111
"sort"
12-
"strconv"
1312
"strings"
1413

1514
"code.gitea.io/gitea/models/db"
16-
"code.gitea.io/gitea/models/foreignreference"
1715
"code.gitea.io/gitea/models/organization"
1816
"code.gitea.io/gitea/models/perm"
1917
access_model "code.gitea.io/gitea/models/perm/access"
@@ -136,12 +134,11 @@ type Issue struct {
136134
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
137135
ClosedUnix timeutil.TimeStamp `xorm:"INDEX"`
138136

139-
Attachments []*repo_model.Attachment `xorm:"-"`
140-
Comments []*Comment `xorm:"-"`
141-
Reactions ReactionList `xorm:"-"`
142-
TotalTrackedTime int64 `xorm:"-"`
143-
Assignees []*user_model.User `xorm:"-"`
144-
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
137+
Attachments []*repo_model.Attachment `xorm:"-"`
138+
Comments []*Comment `xorm:"-"`
139+
Reactions ReactionList `xorm:"-"`
140+
TotalTrackedTime int64 `xorm:"-"`
141+
Assignees []*user_model.User `xorm:"-"`
145142

146143
// IsLocked limits commenting abilities to users on an issue
147144
// with write access
@@ -321,29 +318,6 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
321318
return nil
322319
}
323320

324-
func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
325-
if issue.ForeignReference != nil {
326-
return nil
327-
}
328-
reference := &foreignreference.ForeignReference{
329-
RepoID: issue.RepoID,
330-
LocalIndex: issue.Index,
331-
Type: foreignreference.TypeIssue,
332-
}
333-
has, err := db.GetEngine(ctx).Get(reference)
334-
if err != nil {
335-
return err
336-
} else if !has {
337-
return foreignreference.ErrForeignIndexNotExist{
338-
RepoID: issue.RepoID,
339-
LocalIndex: issue.Index,
340-
Type: foreignreference.TypeIssue,
341-
}
342-
}
343-
issue.ForeignReference = reference
344-
return nil
345-
}
346-
347321
// LoadMilestone load milestone of this issue.
348322
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
349323
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
@@ -406,10 +380,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
406380
}
407381
}
408382

409-
if err = issue.loadForeignReference(ctx); err != nil && !foreignreference.IsErrForeignIndexNotExist(err) {
410-
return err
411-
}
412-
413383
return issue.loadReactions(ctx)
414384
}
415385

@@ -1097,26 +1067,6 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
10971067
return issue, nil
10981068
}
10991069

1100-
// GetIssueByForeignIndex returns raw issue by foreign ID
1101-
func GetIssueByForeignIndex(ctx context.Context, repoID, foreignIndex int64) (*Issue, error) {
1102-
reference := &foreignreference.ForeignReference{
1103-
RepoID: repoID,
1104-
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
1105-
Type: foreignreference.TypeIssue,
1106-
}
1107-
has, err := db.GetEngine(ctx).Get(reference)
1108-
if err != nil {
1109-
return nil, err
1110-
} else if !has {
1111-
return nil, foreignreference.ErrLocalIndexNotExist{
1112-
RepoID: repoID,
1113-
ForeignIndex: foreignIndex,
1114-
Type: foreignreference.TypeIssue,
1115-
}
1116-
}
1117-
return GetIssueByIndex(repoID, reference.LocalIndex)
1118-
}
1119-
11201070
// GetIssueWithAttrsByIndex returns issue by index in a repository.
11211071
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
11221072
issue, err := GetIssueByIndex(repoID, index)

Diff for: models/issues/issue_test.go

-34
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ import (
77
"context"
88
"fmt"
99
"sort"
10-
"strconv"
1110
"sync"
1211
"testing"
1312
"time"
1413

1514
"code.gitea.io/gitea/models/db"
16-
"code.gitea.io/gitea/models/foreignreference"
1715
issues_model "code.gitea.io/gitea/models/issues"
1816
"code.gitea.io/gitea/models/organization"
1917
repo_model "code.gitea.io/gitea/models/repo"
@@ -501,38 +499,6 @@ func TestCorrectIssueStats(t *testing.T) {
501499
assert.EqualValues(t, issueStats.OpenCount, issueAmount)
502500
}
503501

504-
func TestIssueForeignReference(t *testing.T) {
505-
assert.NoError(t, unittest.PrepareTestDatabase())
506-
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4})
507-
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
508-
509-
// it is fine for an issue to not have a foreign reference
510-
err := issue.LoadAttributes(db.DefaultContext)
511-
assert.NoError(t, err)
512-
assert.Nil(t, issue.ForeignReference)
513-
514-
var foreignIndex int64 = 12345
515-
_, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
516-
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
517-
518-
err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{
519-
LocalIndex: issue.Index,
520-
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
521-
RepoID: issue.RepoID,
522-
Type: foreignreference.TypeIssue,
523-
})
524-
assert.NoError(t, err)
525-
526-
err = issue.LoadAttributes(db.DefaultContext)
527-
assert.NoError(t, err)
528-
529-
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
530-
531-
found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
532-
assert.NoError(t, err)
533-
assert.EqualValues(t, found.Index, issue.Index)
534-
}
535-
536502
func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
537503
assert.NoError(t, unittest.PrepareTestDatabase())
538504
miles := issues_model.MilestoneList{

Diff for: models/migrate.go

-7
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,6 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
8383
}
8484
}
8585

86-
if issue.ForeignReference != nil {
87-
issue.ForeignReference.LocalIndex = issue.Index
88-
if _, err := sess.Insert(issue.ForeignReference); err != nil {
89-
return err
90-
}
91-
}
92-
9386
return nil
9487
}
9588

Diff for: models/migrate_test.go

-12
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
package models
55

66
import (
7-
"strconv"
87
"testing"
98

109
"code.gitea.io/gitea/models/db"
11-
"code.gitea.io/gitea/models/foreignreference"
1210
issues_model "code.gitea.io/gitea/models/issues"
1311
repo_model "code.gitea.io/gitea/models/repo"
1412
"code.gitea.io/gitea/models/unittest"
@@ -48,7 +46,6 @@ func assertCreateIssues(t *testing.T, isPull bool) {
4846
UserID: owner.ID,
4947
}
5048

51-
foreignIndex := int64(12345)
5249
title := "issuetitle1"
5350
is := &issues_model.Issue{
5451
RepoID: repo.ID,
@@ -62,20 +59,11 @@ func assertCreateIssues(t *testing.T, isPull bool) {
6259
IsClosed: true,
6360
Labels: []*issues_model.Label{label},
6461
Reactions: []*issues_model.Reaction{reaction},
65-
ForeignReference: &foreignreference.ForeignReference{
66-
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
67-
RepoID: repo.ID,
68-
Type: foreignreference.TypeIssue,
69-
},
7062
}
7163
err := InsertIssues(is)
7264
assert.NoError(t, err)
7365

7466
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title})
75-
assert.Nil(t, i.ForeignReference)
76-
err = i.LoadAttributes(db.DefaultContext)
77-
assert.NoError(t, err)
78-
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
7967
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
8068
}
8169

Diff for: models/migrations/migrations.go

+2
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,8 @@ var migrations = []Migration{
444444
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
445445
// v236 -> v237
446446
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
447+
// v237 -> v238
448+
NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable),
447449
}
448450

449451
// GetCurrentDBVersion returns the current db version

Diff for: models/migrations/v1_19/v237.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_19 //nolint
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func DropForeignReferenceTable(x *xorm.Engine) error {
11+
// Drop the table introduced in `v211`, it's considered badly designed and doesn't look like to be used.
12+
// See: https://github.com/go-gitea/gitea/issues/21086#issuecomment-1318217453
13+
type ForeignReference struct{}
14+
return x.DropTables(new(ForeignReference))
15+
}

Diff for: services/migrations/gitea_uploader.go

-11
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717

1818
"code.gitea.io/gitea/models"
1919
"code.gitea.io/gitea/models/db"
20-
"code.gitea.io/gitea/models/foreignreference"
2120
issues_model "code.gitea.io/gitea/models/issues"
2221
repo_model "code.gitea.io/gitea/models/repo"
2322
user_model "code.gitea.io/gitea/models/user"
@@ -403,16 +402,6 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
403402
Labels: labels,
404403
CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()),
405404
UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()),
406-
ForeignReference: &foreignreference.ForeignReference{
407-
LocalIndex: issue.GetLocalIndex(),
408-
ForeignIndex: strconv.FormatInt(issue.GetForeignIndex(), 10),
409-
RepoID: g.repo.ID,
410-
Type: foreignreference.TypeIssue,
411-
},
412-
}
413-
414-
if is.ForeignReference.ForeignIndex == "0" {
415-
is.ForeignReference.ForeignIndex = strconv.FormatInt(is.Index, 10)
416405
}
417406

418407
if err := g.remapUser(issue, &is); err != nil {

0 commit comments

Comments
 (0)