Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
36 changes: 36 additions & 0 deletions migrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,39 @@ func openRecreateTestDB(t *testing.T, name string) *gorm.DB {
})
return db
}

type compositeKeyModel struct {
A int `gorm:"primaryKey;autoIncrement"`
B string `gorm:"primaryKey"`
}

func (compositeKeyModel) TableName() string { return "composite_key_models" }

// A composite primary key that includes an auto-increment field must keep all
// key columns. AUTOINCREMENT only applies to a single-column INTEGER PRIMARY
// KEY, and emitting it made GORM skip the table-level PRIMARY KEY clause,
// silently reducing the key to one column.
func TestCompositePrimaryKeyAutoIncrement(t *testing.T) {
db, err := gorm.Open(Open("file:composite_pk?mode=memory&cache=shared"), &gorm.Config{})
if err != nil {
t.Fatalf("gorm.Open: %v", err)
}
t.Cleanup(func() {
if sqlDB, err := db.DB(); err == nil {
_ = sqlDB.Close()
}
})

if err := db.AutoMigrate(&compositeKeyModel{}); err != nil {
t.Fatalf("AutoMigrate: %v", err)
}
var pkCount int
if err := db.Raw("SELECT count(*) FROM pragma_table_info('composite_key_models') WHERE pk > 0").Scan(&pkCount).Error; err != nil {
t.Fatal(err)
}
if pkCount != 2 {
var ddl string
_ = db.Raw("SELECT sql FROM sqlite_master WHERE type='table' AND name='composite_key_models'").Scan(&ddl).Error
t.Errorf("primary key column count = %d, want 2 (DDL: %s)", pkCount, ddl)
}
}
11 changes: 10 additions & 1 deletion sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (dialector Dialector) dataTypeOf(field *schema.Field) string {
case schema.Bool:
return "numeric"
case schema.Int, schema.Uint:
if field.AutoIncrement {
if field.AutoIncrement && !isCompositePrimaryKey(field) {
// doesn't check `PrimaryKey`, to keep backward compatibility
// https://www.sqlite.org/autoinc.html
return "integer PRIMARY KEY AUTOINCREMENT"
Expand Down Expand Up @@ -317,3 +317,12 @@ func isIdentityKeyword(value string) bool {
}
return identity
}

// isCompositePrimaryKey reports whether field is part of a multi-column
// primary key. AUTOINCREMENT only works on a single-column INTEGER PRIMARY
// KEY; emitting it for a composite key would silently reduce the primary key
// to that one column (GORM skips the table-level PRIMARY KEY clause when a
// field type already contains PRIMARY KEY).
func isCompositePrimaryKey(field *schema.Field) bool {
return field.PrimaryKey && field.Schema != nil && len(field.Schema.PrimaryFields) > 1
}
Loading