Skip to content

Commit d8589e6

Browse files
committed
Fix: Long column identifiers in deeply nested joins cause fields to be omitted #7513
1 parent 751a6dd commit d8589e6

File tree

4 files changed

+43
-2
lines changed

4 files changed

+43
-2
lines changed

callbacks/query.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func BuildQuerySQL(db *gorm.DB) {
4040
}
4141
}
4242

43+
if db.Statement.TruncatedFields == nil {
44+
db.Statement.TruncatedFields = make(map[string]string)
45+
}
4346
if db.Statement.SQL.Len() == 0 {
4447
db.Statement.SQL.Grow(100)
4548
clauseSelect := clause.Select{Distinct: db.Statement.Distinct}
@@ -158,11 +161,17 @@ func BuildQuerySQL(db *gorm.DB) {
158161
selectColumns, restricted := columnStmt.SelectAndOmitColumns(false, false)
159162
for _, s := range relation.FieldSchema.DBNames {
160163
if v, ok := selectColumns[s]; (ok && v) || (!ok && !restricted) {
164+
aliasName := db.NamingStrategy.JoinNestedRelationNames([]string{tableAliasName, s})
161165
clauseSelect.Columns = append(clauseSelect.Columns, clause.Column{
162166
Table: tableAliasName,
163167
Name: s,
164-
Alias: utils.NestedRelationName(tableAliasName, s),
168+
Alias: aliasName,
165169
})
170+
origTableAliasName := tableAliasName
171+
if alias, ok := db.Statement.TruncatedFields[tableAliasName]; ok {
172+
origTableAliasName = alias
173+
}
174+
db.Statement.TruncatedFields[aliasName] = utils.NestedRelationName(origTableAliasName, s)
166175
}
167176
}
168177

@@ -236,7 +245,9 @@ func BuildQuerySQL(db *gorm.DB) {
236245
// joins table alias like "Manager, Company, Manager__Company"
237246
curAliasName := rel.Name
238247
if parentTableName != clause.CurrentTable {
239-
curAliasName = utils.NestedRelationName(parentTableName, curAliasName)
248+
aliasName := db.NamingStrategy.JoinNestedRelationNames([]string{parentTableName, curAliasName})
249+
db.Statement.TruncatedFields[aliasName] = utils.NestedRelationName(parentTableName, curAliasName)
250+
curAliasName = aliasName
240251
}
241252

242253
if _, ok := specifiedRelationsName[curAliasName]; !ok {

scan.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ func Scan(rows Rows, db *DB, mode ScanMode) {
227227
if sch != nil {
228228
matchedFieldCount := make(map[string]int, len(columns))
229229
for idx, column := range columns {
230+
if origName, ok := db.Statement.TruncatedFields[column]; ok {
231+
column = origName
232+
}
230233
if field := sch.LookUpField(column); field != nil && field.Readable {
231234
fields[idx] = field
232235
if count, ok := matchedFieldCount[column]; ok {

schema/naming.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"strings"
88
"unicode/utf8"
99

10+
"gorm.io/gorm/utils"
11+
1012
"github.com/jinzhu/inflection"
1113
"golang.org/x/text/cases"
1214
"golang.org/x/text/language"
@@ -22,6 +24,7 @@ type Namer interface {
2224
CheckerName(table, column string) string
2325
IndexName(table, column string) string
2426
UniqueName(table, column string) string
27+
JoinNestedRelationNames(relationNames []string) string
2528
}
2629

2730
// Replacer replacer interface like strings.Replacer
@@ -95,6 +98,29 @@ func (ns NamingStrategy) UniqueName(table, column string) string {
9598
return ns.formatName("uni", table, ns.toDBName(column))
9699
}
97100

101+
// JoinNestedRelationNames nested relationships like `Manager__Company` with enforcing IdentifierMaxLength
102+
func (ns NamingStrategy) JoinNestedRelationNames(relationNames []string) string {
103+
tableAlias := utils.JoinNestedRelationNames(relationNames)
104+
return ns.truncateName(tableAlias)
105+
}
106+
107+
// TruncatedName generate truncated name
108+
func (ns NamingStrategy) truncateName(ident string) string {
109+
formattedName := ident
110+
if ns.IdentifierMaxLength == 0 {
111+
ns.IdentifierMaxLength = 64
112+
}
113+
114+
if utf8.RuneCountInString(formattedName) > ns.IdentifierMaxLength {
115+
h := sha1.New()
116+
h.Write([]byte(formattedName))
117+
bs := h.Sum(nil)
118+
119+
formattedName = formattedName[0:ns.IdentifierMaxLength-8] + hex.EncodeToString(bs)[:8]
120+
}
121+
return formattedName
122+
}
123+
98124
func (ns NamingStrategy) formatName(prefix, table, name string) string {
99125
formattedName := strings.ReplaceAll(strings.Join([]string{
100126
prefix, table, name,

statement.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Statement struct {
4747
attrs []interface{}
4848
assigns []interface{}
4949
scopes []func(*DB) *DB
50+
TruncatedFields map[string]string
5051
Result *result
5152
}
5253

0 commit comments

Comments
 (0)