Fix scanning identical column names occurring >2 times (#2080)

Fix the indexing logic used in selectedColumnsMap to skip fields
that have already been seen. The values of selectedColumns map
must be indexed relative to fields, not relative to selectFields.
This commit is contained in:
Xy Ziemba 2018-09-09 15:12:58 -07:00 committed by Jinzhu
parent dc3b2476c4
commit 71b7f19aad
2 changed files with 58 additions and 2 deletions

View File

@ -581,6 +581,60 @@ func TestJoins(t *testing.T) {
}
}
type JoinedIds struct {
UserID int64 `gorm:"column:id"`
BillingAddressID int64 `gorm:"column:id"`
EmailID int64 `gorm:"column:id"`
}
func TestScanIdenticalColumnNames(t *testing.T) {
var user = User{
Name: "joinsIds",
Email: "joinIds@example.com",
BillingAddress: Address{
Address1: "One Park Place",
},
Emails: []Email{{Email: "join1@example.com"}, {Email: "join2@example.com"}},
}
DB.Save(&user)
var users []JoinedIds
DB.Select("users.id, addresses.id, emails.id").Table("users").
Joins("left join addresses on users.billing_address_id = addresses.id").
Joins("left join emails on emails.user_id = users.id").
Where("name = ?", "joinsIds").Scan(&users)
if len(users) != 2 {
t.Fatal("should find two rows using left join")
}
if user.Id != users[0].UserID {
t.Errorf("Expected result row to contain UserID %d, but got %d", user.Id, users[0].UserID)
}
if user.Id != users[1].UserID {
t.Errorf("Expected result row to contain UserID %d, but got %d", user.Id, users[1].UserID)
}
if user.BillingAddressID.Int64 != users[0].BillingAddressID {
t.Errorf("Expected result row to contain BillingAddressID %d, but got %d", user.BillingAddressID.Int64, users[0].BillingAddressID)
}
if user.BillingAddressID.Int64 != users[1].BillingAddressID {
t.Errorf("Expected result row to contain BillingAddressID %d, but got %d", user.BillingAddressID.Int64, users[0].BillingAddressID)
}
if users[0].EmailID == users[1].EmailID {
t.Errorf("Email ids should be unique. Got %d and %d", users[0].EmailID, users[1].EmailID)
}
if int64(user.Emails[0].Id) != users[0].EmailID && int64(user.Emails[1].Id) != users[0].EmailID {
t.Errorf("Expected result row ID to be either %d or %d, but was %d", user.Emails[0].Id, user.Emails[1].Id, users[0].EmailID)
}
if int64(user.Emails[0].Id) != users[1].EmailID && int64(user.Emails[1].Id) != users[1].EmailID {
t.Errorf("Expected result row ID to be either %d or %d, but was %d", user.Emails[0].Id, user.Emails[1].Id, users[1].EmailID)
}
}
func TestJoinsWithSelect(t *testing.T) {
type result struct {
Name string

View File

@ -486,8 +486,10 @@ func (scope *Scope) scan(rows *sql.Rows, columns []string, fields []*Field) {
values[index] = &ignored
selectFields = fields
offset := 0
if idx, ok := selectedColumnsMap[column]; ok {
selectFields = selectFields[idx+1:]
offset = idx + 1
selectFields = selectFields[offset:]
}
for fieldIndex, field := range selectFields {
@ -501,7 +503,7 @@ func (scope *Scope) scan(rows *sql.Rows, columns []string, fields []*Field) {
resetFields[index] = field
}
selectedColumnsMap[column] = fieldIndex
selectedColumnsMap[column] = offset + fieldIndex
if field.IsNormal {
break