Skip to content

Commit

Permalink
add test: TestAutoMigrateInt8PG: shouldn't execute ALTER COLUMN TYPE …
Browse files Browse the repository at this point in the history
…smallint, close #5762
  • Loading branch information
viatoriche authored and jinzhu committed Oct 18, 2022
1 parent a0f4d3f commit 62593cf
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 26 deletions.
51 changes: 25 additions & 26 deletions migrator/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,50 +406,49 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
fullDataType := strings.TrimSpace(strings.ToLower(m.DB.Migrator().FullDataTypeOf(field).SQL))
realDataType := strings.ToLower(columnType.DatabaseTypeName())

alterColumn := false
var (
alterColumn, isSameType bool
)

if !field.PrimaryKey {
// check type
var isSameType bool
if strings.HasPrefix(fullDataType, realDataType) {
isSameType = true
}

// check type aliases
if !isSameType {
if !strings.HasPrefix(fullDataType, realDataType) {
// check type aliases
aliases := m.DB.Migrator().GetTypeAliases(realDataType)
for _, alias := range aliases {
if strings.HasPrefix(fullDataType, alias) {
isSameType = true
break
}
}
}

if !isSameType {
alterColumn = true
if !isSameType {
alterColumn = true
}
}
}

// check size
if length, ok := columnType.Length(); length != int64(field.Size) {
if length > 0 && field.Size > 0 {
alterColumn = true
} else {
// has size in data type and not equal
// Since the following code is frequently called in the for loop, reg optimization is needed here
matches2 := regFullDataType.FindAllStringSubmatch(fullDataType, -1)
if !field.PrimaryKey &&
(len(matches2) == 1 && matches2[0][1] != fmt.Sprint(length) && ok) {
if !isSameType {
// check size
if length, ok := columnType.Length(); length != int64(field.Size) {
if length > 0 && field.Size > 0 {
alterColumn = true
} else {
// has size in data type and not equal
// Since the following code is frequently called in the for loop, reg optimization is needed here
matches2 := regFullDataType.FindAllStringSubmatch(fullDataType, -1)
if !field.PrimaryKey &&
(len(matches2) == 1 && matches2[0][1] != fmt.Sprint(length) && ok) {
alterColumn = true
}
}
}
}

// check precision
if precision, _, ok := columnType.DecimalSize(); ok && int64(field.Precision) != precision {
if regexp.MustCompile(fmt.Sprintf("[^0-9]%d[^0-9]", field.Precision)).MatchString(m.DataTypeOf(field)) {
alterColumn = true
// check precision
if precision, _, ok := columnType.DecimalSize(); ok && int64(field.Precision) != precision {
if regexp.MustCompile(fmt.Sprintf("[^0-9]%d[^0-9]", field.Precision)).MatchString(m.DataTypeOf(field)) {
alterColumn = true
}
}
}

Expand Down
40 changes: 40 additions & 0 deletions tests/migrate_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tests_test

import (
"context"
"fmt"
"math/rand"
"reflect"
Expand All @@ -9,6 +10,7 @@ import (
"time"

"gorm.io/driver/postgres"

"gorm.io/gorm"
"gorm.io/gorm/schema"
. "gorm.io/gorm/utils/tests"
Expand Down Expand Up @@ -72,6 +74,44 @@ func TestMigrate(t *testing.T) {
t.Fatalf("Failed to find index for many2many for %v %v", indexes[0], indexes[1])
}
}

}

func TestAutoMigrateInt8PG(t *testing.T) {
if DB.Dialector.Name() != "postgres" {
return
}

type Smallint int8

type MigrateInt struct {
Int8 Smallint
}

tracer := Tracer{
Logger: DB.Config.Logger,
Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
sql, _ := fc()
if strings.HasPrefix(sql, "ALTER TABLE \"migrate_ints\" ALTER COLUMN \"int8\" TYPE smallint") {
t.Fatalf("shouldn't execute ALTER COLUMN TYPE if such type is already existed in DB schema: sql: %s", sql)
}
},
}

DB.Migrator().DropTable(&MigrateInt{})

// The first AutoMigrate to make table with field with correct type
if err := DB.AutoMigrate(&MigrateInt{}); err != nil {
t.Fatalf("Failed to auto migrate: error: %v", err)
}

// make new session to set custom logger tracer
session := DB.Session(&gorm.Session{Logger: tracer})

// The second AutoMigrate to catch an error
if err := session.AutoMigrate(&MigrateInt{}); err != nil {
t.Fatalf("Failed to auto migrate: error: %v", err)
}
}

func TestAutoMigrateSelfReferential(t *testing.T) {
Expand Down
34 changes: 34 additions & 0 deletions tests/tracer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package tests_test

import (
"context"
"time"

"gorm.io/gorm/logger"
)

type Tracer struct {
Logger logger.Interface
Test func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}

func (S Tracer) LogMode(level logger.LogLevel) logger.Interface {
return S.Logger.LogMode(level)
}

func (S Tracer) Info(ctx context.Context, s string, i ...interface{}) {
S.Logger.Info(ctx, s, i...)
}

func (S Tracer) Warn(ctx context.Context, s string, i ...interface{}) {
S.Logger.Warn(ctx, s, i...)
}

func (S Tracer) Error(ctx context.Context, s string, i ...interface{}) {
S.Logger.Error(ctx, s, i...)
}

func (S Tracer) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
S.Logger.Trace(ctx, begin, fc, err)
S.Test(ctx, begin, fc, err)
}

0 comments on commit 62593cf

Please sign in to comment.