add test: TestAutoMigrateInt8PG: shouldn't execute ALTER COLUMN TYPE smallint, close #5762
This commit is contained in:
		
							parent
							
								
									a0f4d3f7d2
								
							
						
					
					
						commit
						62593cfad0
					
				| @ -406,17 +406,14 @@ 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) { | ||||
| @ -424,32 +421,34 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		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 { | ||||
| 				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 | ||||
| 	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 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package tests_test | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"reflect" | ||||
| @ -9,6 +10,7 @@ import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"gorm.io/driver/postgres" | ||||
| 
 | ||||
| 	"gorm.io/gorm" | ||||
| 	"gorm.io/gorm/schema" | ||||
| 	. "gorm.io/gorm/utils/tests" | ||||
| @ -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) { | ||||
|  | ||||
							
								
								
									
										34
									
								
								tests/tracer_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/tracer_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 viatoriche / Maxim Panfilov
						viatoriche / Maxim Panfilov