From 7e13b03bd4e57a554d3daa2774d3f58102ac30d9 Mon Sep 17 00:00:00 2001 From: Cr <631807682@qq.com> Date: Sat, 28 May 2022 22:18:07 +0800 Subject: [PATCH] fix: duplicate column scan (#5369) * fix: duplicate column scan * fix: dup filed in inconsistent schema and database * chore[ci skip]: gofumpt style * chore[ci skip]: fix typo --- scan.go | 17 ++++++++++++----- tests/scan_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/scan.go b/scan.go index ad3734d89..a611a9ce8 100644 --- a/scan.go +++ b/scan.go @@ -193,14 +193,21 @@ func Scan(rows Rows, db *DB, mode ScanMode) { // Not Pluck if sch != nil { + schFieldsCount := len(sch.Fields) for idx, column := range columns { if field := sch.LookUpField(column); field != nil && field.Readable { if curIndex, ok := selectedColumnsMap[column]; ok { - for fieldIndex, selectField := range sch.Fields[curIndex+1:] { - if selectField.DBName == column && selectField.Readable { - selectedColumnsMap[column] = curIndex + fieldIndex + 1 - fields[idx] = selectField - break + fields[idx] = field // handle duplicate fields + offset := curIndex + 1 + // handle sch inconsistent with database + // like Raw(`...`).Scan + if schFieldsCount > offset { + for fieldIndex, selectField := range sch.Fields[offset:] { + if selectField.DBName == column && selectField.Readable { + selectedColumnsMap[column] = curIndex + fieldIndex + 1 + fields[idx] = selectField + break + } } } } else { diff --git a/tests/scan_test.go b/tests/scan_test.go index 425c0a299..6f2e9f54d 100644 --- a/tests/scan_test.go +++ b/tests/scan_test.go @@ -214,4 +214,29 @@ func TestScanToEmbedded(t *testing.T) { if !addressMatched { t.Errorf("Failed, no address matched") } + + personDupField := Person{ID: person1.ID} + if err := DB.Select("people.id, people.*"). + First(&personDupField).Error; err != nil { + t.Errorf("Failed to run join query, got error: %v", err) + } + AssertEqual(t, person1, personDupField) + + user := User{ + Name: "TestScanToEmbedded_1", + Manager: &User{ + Name: "TestScanToEmbedded_1_m1", + Manager: &User{Name: "TestScanToEmbedded_1_m1_m1"}, + }, + } + DB.Create(&user) + + type UserScan struct { + ID uint + Name string + ManagerID *uint + } + var user2 UserScan + err := DB.Raw("SELECT * FROM users INNER JOIN users Manager ON users.manager_id = Manager.id WHERE users.id = ?", user.ID).Scan(&user2).Error + AssertEqual(t, err, nil) }