Merge pull request #1 from moseszane168/support-gaussdb-dialect
Support gaussdb dialect
This commit is contained in:
		
						commit
						e32ea0b589
					
				| @ -206,9 +206,9 @@ func TestDeleteSliceWithAssociations(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // only sqlite, postgres, sqlserver support returning
 | // only sqlite, postgres, gaussdb, sqlserver support returning
 | ||||||
| func TestSoftDeleteReturning(t *testing.T) { | func TestSoftDeleteReturning(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "sqlserver" { | 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" && DB.Dialector.Name() != "sqlserver" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -233,7 +233,7 @@ func TestSoftDeleteReturning(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestDeleteReturning(t *testing.T) { | func TestDeleteReturning(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "sqlserver" { | 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" && DB.Dialector.Name() != "sqlserver" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ func TestSupportedDialectorWithErrDuplicatedKey(t *testing.T) { | |||||||
| 		t.Fatalf("failed to connect database, got error %v", err) | 		t.Fatalf("failed to connect database, got error %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dialectors := map[string]bool{"sqlite": true, "postgres": true, "mysql": true, "sqlserver": true} | 	dialectors := map[string]bool{"sqlite": true, "postgres": true, "gaussdb": true, "mysql": true, "sqlserver": true} | ||||||
| 	if supported, found := dialectors[db.Dialector.Name()]; !(found && supported) { | 	if supported, found := dialectors[db.Dialector.Name()]; !(found && supported) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -81,7 +81,7 @@ func TestSupportedDialectorWithErrForeignKeyViolated(t *testing.T) { | |||||||
| 		t.Fatalf("failed to connect database, got error %v", err) | 		t.Fatalf("failed to connect database, got error %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dialectors := map[string]bool{"sqlite": true, "postgres": true, "mysql": true, "sqlserver": true} | 	dialectors := map[string]bool{"sqlite": true, "postgres": true, "gaussdb": true, "mysql": true, "sqlserver": true} | ||||||
| 	if supported, found := dialectors[db.Dialector.Name()]; !(found && supported) { | 	if supported, found := dialectors[db.Dialector.Name()]; !(found && supported) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/moseszane168/gaussdb" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 	"gorm.io/driver/postgres" | 	"gorm.io/driver/postgres" | ||||||
| 
 | 
 | ||||||
| @ -83,7 +84,45 @@ func TestMigrate(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestAutoMigrateInt8PG(t *testing.T) { | func TestAutoMigrateInt8PG(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		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 TestAutoMigrateGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -182,7 +221,94 @@ func TestAutoMigrateNullable(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestSmartMigrateColumn(t *testing.T) { | func TestSmartMigrateColumn(t *testing.T) { | ||||||
| 	fullSupported := map[string]bool{"mysql": true, "postgres": true}[DB.Dialector.Name()] | 	fullSupported := map[string]bool{"mysql": true, "postgres": true, "gaussdb": true}[DB.Dialector.Name()] | ||||||
|  | 
 | ||||||
|  | 	type UserMigrateColumn struct { | ||||||
|  | 		ID       uint | ||||||
|  | 		Name     string | ||||||
|  | 		Salary   float64 | ||||||
|  | 		Birthday time.Time `gorm:"precision:4"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	DB.Migrator().DropTable(&UserMigrateColumn{}) | ||||||
|  | 
 | ||||||
|  | 	DB.AutoMigrate(&UserMigrateColumn{}) | ||||||
|  | 
 | ||||||
|  | 	type UserMigrateColumn2 struct { | ||||||
|  | 		ID                  uint | ||||||
|  | 		Name                string    `gorm:"size:128"` | ||||||
|  | 		Salary              float64   `gorm:"precision:2"` | ||||||
|  | 		Birthday            time.Time `gorm:"precision:2"` | ||||||
|  | 		NameIgnoreMigration string    `gorm:"size:100"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.Table("user_migrate_columns").AutoMigrate(&UserMigrateColumn2{}); err != nil { | ||||||
|  | 		t.Fatalf("failed to auto migrate, got error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	columnTypes, err := DB.Table("user_migrate_columns").Migrator().ColumnTypes(&UserMigrateColumn{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("failed to get column types, got error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, columnType := range columnTypes { | ||||||
|  | 		switch columnType.Name() { | ||||||
|  | 		case "name": | ||||||
|  | 			if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 128 { | ||||||
|  | 				t.Fatalf("name's length should be 128, but got %v", length) | ||||||
|  | 			} | ||||||
|  | 		case "salary": | ||||||
|  | 			if precision, o, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 2 { | ||||||
|  | 				t.Fatalf("salary's precision should be 2, but got %v %v", precision, o) | ||||||
|  | 			} | ||||||
|  | 		case "birthday": | ||||||
|  | 			if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 2 { | ||||||
|  | 				t.Fatalf("birthday's precision should be 2, but got %v", precision) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type UserMigrateColumn3 struct { | ||||||
|  | 		ID                  uint | ||||||
|  | 		Name                string    `gorm:"size:256"` | ||||||
|  | 		Salary              float64   `gorm:"precision:3"` | ||||||
|  | 		Birthday            time.Time `gorm:"precision:3"` | ||||||
|  | 		NameIgnoreMigration string    `gorm:"size:128;-:migration"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.Table("user_migrate_columns").AutoMigrate(&UserMigrateColumn3{}); err != nil { | ||||||
|  | 		t.Fatalf("failed to auto migrate, got error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	columnTypes, err = DB.Table("user_migrate_columns").Migrator().ColumnTypes(&UserMigrateColumn{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("failed to get column types, got error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, columnType := range columnTypes { | ||||||
|  | 		switch columnType.Name() { | ||||||
|  | 		case "name": | ||||||
|  | 			if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 256 { | ||||||
|  | 				t.Fatalf("name's length should be 128, but got %v", length) | ||||||
|  | 			} | ||||||
|  | 		case "salary": | ||||||
|  | 			if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 3 { | ||||||
|  | 				t.Fatalf("salary's precision should be 2, but got %v", precision) | ||||||
|  | 			} | ||||||
|  | 		case "birthday": | ||||||
|  | 			if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 3 { | ||||||
|  | 				t.Fatalf("birthday's precision should be 2, but got %v", precision) | ||||||
|  | 			} | ||||||
|  | 		case "name_ignore_migration": | ||||||
|  | 			if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 100 { | ||||||
|  | 				t.Fatalf("name_ignore_migration's length should still be 100 but got %v", length) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestSmartMigrateColumnGaussDB(t *testing.T) { | ||||||
|  | 	fullSupported := map[string]bool{"mysql": true, "gaussdb": true}[DB.Dialector.Name()] | ||||||
| 
 | 
 | ||||||
| 	type UserMigrateColumn struct { | 	type UserMigrateColumn struct { | ||||||
| 		ID       uint | 		ID       uint | ||||||
| @ -850,7 +976,68 @@ func TestMigrateColumnOrder(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| // https://github.com/go-gorm/gorm/issues/5047
 | // https://github.com/go-gorm/gorm/issues/5047
 | ||||||
| func TestMigrateSerialColumn(t *testing.T) { | func TestMigrateSerialColumn(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type Event struct { | ||||||
|  | 		ID  uint `gorm:"primarykey"` | ||||||
|  | 		UID uint32 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type Event1 struct { | ||||||
|  | 		ID  uint   `gorm:"primarykey"` | ||||||
|  | 		UID uint32 `gorm:"not null;autoIncrement"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type Event2 struct { | ||||||
|  | 		ID  uint   `gorm:"primarykey"` | ||||||
|  | 		UID uint16 `gorm:"not null;autoIncrement"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var err error | ||||||
|  | 	err = DB.Migrator().DropTable(&Event{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("DropTable err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// create sequence
 | ||||||
|  | 	err = DB.Table("events").AutoMigrate(&Event1{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// delete sequence
 | ||||||
|  | 	err = DB.Table("events").AutoMigrate(&Event{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// update sequence
 | ||||||
|  | 	err = DB.Table("events").AutoMigrate(&Event1{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 	err = DB.Table("events").AutoMigrate(&Event2{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	DB.Table("events").Save(&Event2{}) | ||||||
|  | 	DB.Table("events").Save(&Event2{}) | ||||||
|  | 	DB.Table("events").Save(&Event2{}) | ||||||
|  | 
 | ||||||
|  | 	events := make([]*Event, 0) | ||||||
|  | 	DB.Table("events").Find(&events) | ||||||
|  | 
 | ||||||
|  | 	AssertEqual(t, 3, len(events)) | ||||||
|  | 	for _, v := range events { | ||||||
|  | 		AssertEqual(t, v.ID, v.UID) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestMigrateSerialColumnGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -975,7 +1162,7 @@ func TestMigrateAutoIncrement(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| // https://github.com/go-gorm/gorm/issues/5320
 | // https://github.com/go-gorm/gorm/issues/5320
 | ||||||
| func TestPrimarykeyID(t *testing.T) { | func TestPrimarykeyID(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -1009,6 +1196,41 @@ func TestPrimarykeyID(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestPrimarykeyIDGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type MissPKLanguage struct { | ||||||
|  | 		ID   string `gorm:"type:uuid;default:uuid_generate_v4()"` | ||||||
|  | 		Name string | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type MissPKUser struct { | ||||||
|  | 		ID              string           `gorm:"type:uuid;default:uuid_generate_v4()"` | ||||||
|  | 		MissPKLanguages []MissPKLanguage `gorm:"many2many:miss_pk_user_languages;"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var err error | ||||||
|  | 	err = DB.Migrator().DropTable(&MissPKUser{}, &MissPKLanguage{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("DropTable err:%v", err) | ||||||
|  | 	} | ||||||
|  | 	// TODO: ERROR: could not open extension control file: No such file or directory (SQLSTATE 58P01)
 | ||||||
|  | 	DB.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`) | ||||||
|  | 
 | ||||||
|  | 	err = DB.AutoMigrate(&MissPKUser{}, &MissPKLanguage{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// patch
 | ||||||
|  | 	err = DB.AutoMigrate(&MissPKUser{}, &MissPKLanguage{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestCurrentTimestamp(t *testing.T) { | func TestCurrentTimestamp(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "mysql" { | 	if DB.Dialector.Name() != "mysql" { | ||||||
| 		return | 		return | ||||||
| @ -1175,7 +1397,7 @@ func findColumnType(dest interface{}, columnName string) ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestInvalidCachedPlanSimpleProtocol(t *testing.T) { | func TestInvalidCachedPlanSimpleProtocol(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -1209,6 +1431,42 @@ func TestInvalidCachedPlanSimpleProtocol(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // TODO: ERROR: must have at least one column (SQLSTATE 0A000)
 | ||||||
|  | func TestInvalidCachedPlanSimpleProtocolGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	db, err := gorm.Open(gaussdb.Open(gaussdbDSN), &gorm.Config{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Open err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type Object1 struct{} | ||||||
|  | 	type Object2 struct { | ||||||
|  | 		Field1 string | ||||||
|  | 	} | ||||||
|  | 	type Object3 struct { | ||||||
|  | 		Field2 string | ||||||
|  | 	} | ||||||
|  | 	db.Migrator().DropTable("objects") | ||||||
|  | 
 | ||||||
|  | 	err = db.Table("objects").AutoMigrate(&Object1{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = db.Table("objects").AutoMigrate(&Object2{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = db.Table("objects").AutoMigrate(&Object3{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("AutoMigrate err:%v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestDifferentTypeWithoutDeclaredLength(t *testing.T) { | func TestDifferentTypeWithoutDeclaredLength(t *testing.T) { | ||||||
| 	type DiffType struct { | 	type DiffType struct { | ||||||
| 		ID   uint | 		ID   uint | ||||||
| @ -1249,7 +1507,43 @@ func TestDifferentTypeWithoutDeclaredLength(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMigrateArrayTypeModel(t *testing.T) { | func TestMigrateArrayTypeModel(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type ArrayTypeModel struct { | ||||||
|  | 		ID              uint | ||||||
|  | 		Number          string     `gorm:"type:varchar(51);NOT NULL"` | ||||||
|  | 		TextArray       []string   `gorm:"type:text[];NOT NULL"` | ||||||
|  | 		NestedTextArray [][]string `gorm:"type:text[][]"` | ||||||
|  | 		NestedIntArray  [][]int64  `gorm:"type:integer[3][3]"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var err error | ||||||
|  | 	DB.Migrator().DropTable(&ArrayTypeModel{}) | ||||||
|  | 
 | ||||||
|  | 	err = DB.AutoMigrate(&ArrayTypeModel{}) | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 
 | ||||||
|  | 	ct, err := findColumnType(&ArrayTypeModel{}, "number") | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, "varchar", ct.DatabaseTypeName()) | ||||||
|  | 
 | ||||||
|  | 	ct, err = findColumnType(&ArrayTypeModel{}, "text_array") | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, "text[]", ct.DatabaseTypeName()) | ||||||
|  | 
 | ||||||
|  | 	ct, err = findColumnType(&ArrayTypeModel{}, "nested_text_array") | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, "text[]", ct.DatabaseTypeName()) | ||||||
|  | 
 | ||||||
|  | 	ct, err = findColumnType(&ArrayTypeModel{}, "nested_int_array") | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, "integer[]", ct.DatabaseTypeName()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestMigrateArrayTypeModelGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -1572,7 +1866,66 @@ func TestMigrateView(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMigrateExistingBoolColumnPG(t *testing.T) { | func TestMigrateExistingBoolColumnPG(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type ColumnStruct struct { | ||||||
|  | 		gorm.Model | ||||||
|  | 		Name         string | ||||||
|  | 		StringBool   string | ||||||
|  | 		SmallintBool int `gorm:"type:smallint"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type ColumnStruct2 struct { | ||||||
|  | 		gorm.Model | ||||||
|  | 		Name         string | ||||||
|  | 		StringBool   bool // change existing boolean column from string to boolean
 | ||||||
|  | 		SmallintBool bool // change existing boolean column from smallint or other to boolean
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	DB.Migrator().DropTable(&ColumnStruct{}) | ||||||
|  | 
 | ||||||
|  | 	if err := DB.AutoMigrate(&ColumnStruct{}); err != nil { | ||||||
|  | 		t.Errorf("Failed to migrate, got %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.Table("column_structs").AutoMigrate(&ColumnStruct2{}); err != nil { | ||||||
|  | 		t.Fatalf("no error should happened when auto migrate column, but got %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if columnTypes, err := DB.Migrator().ColumnTypes(&ColumnStruct{}); err != nil { | ||||||
|  | 		t.Fatalf("no error should returns for ColumnTypes") | ||||||
|  | 	} else { | ||||||
|  | 		stmt := &gorm.Statement{DB: DB} | ||||||
|  | 		stmt.Parse(&ColumnStruct2{}) | ||||||
|  | 
 | ||||||
|  | 		for _, columnType := range columnTypes { | ||||||
|  | 			switch columnType.Name() { | ||||||
|  | 			case "id": | ||||||
|  | 				if v, ok := columnType.PrimaryKey(); !ok || !v { | ||||||
|  | 					t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), | ||||||
|  | 						columnType) | ||||||
|  | 				} | ||||||
|  | 			case "string_bool": | ||||||
|  | 				dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name())) | ||||||
|  | 				if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) { | ||||||
|  | 					t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", | ||||||
|  | 						columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType) | ||||||
|  | 				} | ||||||
|  | 			case "smallint_bool": | ||||||
|  | 				dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name())) | ||||||
|  | 				if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) { | ||||||
|  | 					t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", | ||||||
|  | 						columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestMigrateExistingBoolColumnGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ func TestManyToManyWithMultiPrimaryKeys(t *testing.T) { | |||||||
| 		t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment") | 		t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if name := DB.Dialector.Name(); name == "postgres" || name == "mysql" { | 	if name := DB.Dialector.Name(); name == "postgres" || name == "mysql" || name == "gaussdb" { | ||||||
| 		stmt := gorm.Statement{DB: DB} | 		stmt := gorm.Statement{DB: DB} | ||||||
| 		stmt.Parse(&Blog{}) | 		stmt.Parse(&Blog{}) | ||||||
| 		stmt.Schema.LookUpField("ID").Unique = true | 		stmt.Schema.LookUpField("ID").Unique = true | ||||||
| @ -142,6 +142,9 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) { | |||||||
| 	if name := DB.Dialector.Name(); name == "postgres" { | 	if name := DB.Dialector.Name(); name == "postgres" { | ||||||
| 		t.Skip("skip postgres due to it only allow unique constraint matching given keys") | 		t.Skip("skip postgres due to it only allow unique constraint matching given keys") | ||||||
| 	} | 	} | ||||||
|  | 	if name := DB.Dialector.Name(); name == "gaussdb" { | ||||||
|  | 		t.Skip("skip gaussdb due to it only allow unique constraint matching given keys") | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") | 	DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") | ||||||
| 	if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { | 	if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { | ||||||
| @ -268,6 +271,10 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) { | |||||||
| 		t.Skip("skip postgres due to it only allow unique constraint matching given keys") | 		t.Skip("skip postgres due to it only allow unique constraint matching given keys") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if name := DB.Dialector.Name(); name == "gaussdb" { | ||||||
|  | 		t.Skip("skip gaussdb due to it only allow unique constraint matching given keys") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") | 	DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") | ||||||
| 	if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { | 	if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { | ||||||
| 		t.Fatalf("Failed to auto migrate, got error: %v", err) | 		t.Fatalf("Failed to auto migrate, got error: %v", err) | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestPostgresReturningIDWhichHasStringType(t *testing.T) { | func TestPostgresReturningIDWhichHasStringType(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		t.Skip() | 		t.Skip() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -62,7 +62,7 @@ func TestPostgresReturningIDWhichHasStringType(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPostgres(t *testing.T) { | func TestPostgres(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		t.Skip() | 		t.Skip() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -166,7 +166,7 @@ type Category struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMany2ManyWithDefaultValueUUID(t *testing.T) { | func TestMany2ManyWithDefaultValueUUID(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		t.Skip() | 		t.Skip() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -191,7 +191,7 @@ func TestMany2ManyWithDefaultValueUUID(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPostgresOnConstraint(t *testing.T) { | func TestPostgresOnConstraint(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" { | 	if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { | ||||||
| 		t.Skip() | 		t.Skip() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ type SerializerPostgresStruct struct { | |||||||
| func (*SerializerPostgresStruct) TableName() string { return "serializer_structs" } | func (*SerializerPostgresStruct) TableName() string { return "serializer_structs" } | ||||||
| 
 | 
 | ||||||
| func adaptorSerializerModel(s *SerializerStruct) interface{} { | func adaptorSerializerModel(s *SerializerStruct) interface{} { | ||||||
| 	if DB.Dialector.Name() == "postgres" { | 	if DB.Dialector.Name() == "postgres" || DB.Dialector.Name() == "gaussdb" { | ||||||
| 		sps := SerializerPostgresStruct(*s) | 		sps := SerializerPostgresStruct(*s) | ||||||
| 		return &sps | 		return &sps | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -487,7 +487,7 @@ func replaceQuoteInSQL(sql string) string { | |||||||
| 
 | 
 | ||||||
| 	// convert dialect special quote into double quote
 | 	// convert dialect special quote into double quote
 | ||||||
| 	switch DB.Dialector.Name() { | 	switch DB.Dialector.Name() { | ||||||
| 	case "postgres": | 	case "postgres", "gaussdb": | ||||||
| 		sql = strings.ReplaceAll(sql, `"`, `"`) | 		sql = strings.ReplaceAll(sql, `"`, `"`) | ||||||
| 	case "mysql", "sqlite": | 	case "mysql", "sqlite": | ||||||
| 		sql = strings.ReplaceAll(sql, "`", `"`) | 		sql = strings.ReplaceAll(sql, "`", `"`) | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/moseszane168/gaussdb" | ||||||
| 	"gorm.io/driver/postgres" | 	"gorm.io/driver/postgres" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| 	"gorm.io/gorm/schema" | 	"gorm.io/gorm/schema" | ||||||
| @ -251,6 +252,82 @@ func TestPostgresTableWithIdentifierLength(t *testing.T) { | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestPostgresTableWithIdentifierLengthGaussDB(t *testing.T) { | ||||||
|  | 	if DB.Dialector.Name() != "gaussdb" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type LongString struct { | ||||||
|  | 		ThisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString string `gorm:"unique"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	t.Run("default", func(t *testing.T) { | ||||||
|  | 		db, _ := gorm.Open(gaussdb.Open(gaussdbDSN), &gorm.Config{}) | ||||||
|  | 		user, err := schema.Parse(&LongString{}, &sync.Map{}, db.Config.NamingStrategy) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatalf("failed to parse user unique, got error %v", err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		constraints := user.ParseUniqueConstraints() | ||||||
|  | 		if len(constraints) != 1 { | ||||||
|  | 			t.Fatalf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for key := range constraints { | ||||||
|  | 			if len(key) != 63 { | ||||||
|  | 				t.Errorf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("naming strategy", func(t *testing.T) { | ||||||
|  | 		db, _ := gorm.Open(gaussdb.Open(gaussdbDSN), &gorm.Config{ | ||||||
|  | 			NamingStrategy: schema.NamingStrategy{}, | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		user, err := schema.Parse(&LongString{}, &sync.Map{}, db.Config.NamingStrategy) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatalf("failed to parse user unique, got error %v", err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		constraints := user.ParseUniqueConstraints() | ||||||
|  | 		if len(constraints) != 1 { | ||||||
|  | 			t.Fatalf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for key := range constraints { | ||||||
|  | 			if len(key) != 63 { | ||||||
|  | 				t.Errorf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("namer", func(t *testing.T) { | ||||||
|  | 		uname := "custom_unique_name" | ||||||
|  | 		db, _ := gorm.Open(gaussdb.Open(gaussdbDSN), &gorm.Config{ | ||||||
|  | 			NamingStrategy: mockUniqueNamingStrategy{ | ||||||
|  | 				UName: uname, | ||||||
|  | 			}, | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		user, err := schema.Parse(&LongString{}, &sync.Map{}, db.Config.NamingStrategy) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatalf("failed to parse user unique, got error %v", err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		constraints := user.ParseUniqueConstraints() | ||||||
|  | 		if len(constraints) != 1 { | ||||||
|  | 			t.Fatalf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for key := range constraints { | ||||||
|  | 			if key != uname { | ||||||
|  | 				t.Errorf("failed to find unique constraint, got %v", constraints) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type mockUniqueNamingStrategy struct { | type mockUniqueNamingStrategy struct { | ||||||
| 	UName string | 	UName string | ||||||
| 	schema.NamingStrategy | 	schema.NamingStrategy | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ import ( | |||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/moseszane168/gaussdb" | ||||||
| 	"gorm.io/driver/mysql" | 	"gorm.io/driver/mysql" | ||||||
| 	"gorm.io/driver/postgres" | 	"gorm.io/driver/postgres" | ||||||
| 	"gorm.io/driver/sqlite" | 	"gorm.io/driver/sqlite" | ||||||
| @ -21,6 +22,7 @@ var DB *gorm.DB | |||||||
| var ( | var ( | ||||||
| 	mysqlDSN     = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" | 	mysqlDSN     = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" | ||||||
| 	postgresDSN  = "user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" | 	postgresDSN  = "user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" | ||||||
|  | 	gaussdbDSN   = "user=gaussdb password=Gaussdb@123 dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" | ||||||
| 	sqlserverDSN = "sqlserver://sa:LoremIpsum86@localhost:9930?database=master" | 	sqlserverDSN = "sqlserver://sa:LoremIpsum86@localhost:9930?database=master" | ||||||
| 	tidbDSN      = "root:@tcp(localhost:9940)/test?charset=utf8&parseTime=True&loc=Local" | 	tidbDSN      = "root:@tcp(localhost:9940)/test?charset=utf8&parseTime=True&loc=Local" | ||||||
| ) | ) | ||||||
| @ -65,6 +67,15 @@ func OpenTestConnection(cfg *gorm.Config) (db *gorm.DB, err error) { | |||||||
| 			DSN:                  dbDSN, | 			DSN:                  dbDSN, | ||||||
| 			PreferSimpleProtocol: true, | 			PreferSimpleProtocol: true, | ||||||
| 		}), cfg) | 		}), cfg) | ||||||
|  | 	case "gaussdb": | ||||||
|  | 		log.Println("testing gaussdb...") | ||||||
|  | 		if dbDSN == "" { | ||||||
|  | 			dbDSN = gaussdbDSN | ||||||
|  | 		} | ||||||
|  | 		db, err = gorm.Open(gaussdb.New(gaussdb.Config{ | ||||||
|  | 			DSN:                  dbDSN, | ||||||
|  | 			PreferSimpleProtocol: true, | ||||||
|  | 		}), cfg) | ||||||
| 	case "sqlserver": | 	case "sqlserver": | ||||||
| 		// go install github.com/microsoft/go-sqlcmd/cmd/sqlcmd@latest
 | 		// go install github.com/microsoft/go-sqlcmd/cmd/sqlcmd@latest
 | ||||||
| 		// SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930
 | 		// SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930
 | ||||||
|  | |||||||
| @ -765,9 +765,9 @@ func TestSaveWithPrimaryValue(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // only sqlite, postgres, sqlserver support returning
 | // only sqlite, postgres, gaussdb, sqlserver support returning
 | ||||||
| func TestUpdateReturning(t *testing.T) { | func TestUpdateReturning(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "sqlserver" { | 	if DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" && DB.Dialector.Name() != "sqlserver" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -883,9 +883,9 @@ func TestSaveWithHooks(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // only postgres, sqlserver, sqlite support update from
 | // only postgres, gaussdb, sqlserver, sqlite support update from
 | ||||||
| func TestUpdateFrom(t *testing.T) { | func TestUpdateFrom(t *testing.T) { | ||||||
| 	if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "sqlserver" { | 	if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" && DB.Dialector.Name() != "sqlite" && DB.Dialector.Name() != "sqlserver" { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 moseszane168
						moseszane168