Skip to content

Wrong create SQL Args generated, Wrong SQL log generated #7613

@cruvie

Description

@cruvie

GORM Playground Link

go-gorm/playground#1

Description

type UserStatus int32

const (
	Active UserStatus = 9
)

func (x UserStatus) String() string {
	return "UserStatus String"
}

type User2 struct {
	Status UserStatus
}

func (u User2) TableName() string {
	return "ss.test_user"
}

func TestName(t *testing.T) {
	if results := DB.Debug().Create(&User2{Status: Active}); results.Error != nil {
		t.Fatalf("errors happened when create: %v", results.Error)
	} else if results.RowsAffected != 1 {
		t.Fatalf("rows affected expects: %v, got %v", 1, results.RowsAffected)
	}
}
2025/09/14 22:56:00 testing postgres...
=== RUN   TestName

2025/09/14 22:56:00 /Users/cruvie/Documents/open-source/gorm/tests/create_test.go:56 ERROR: invalid input syntax for type smallint: "UserStatus String" (SQLSTATE 22P02)
[55.297ms] [rows:0] INSERT INTO "ss"."test_user" ("status") VALUES (9)
    create_test.go:57: errors happened when create: ERROR: invalid input syntax for type smallint: "UserStatus String" (SQLSTATE 22P02)
--- FAIL: TestName (0.06s)

FAIL

gorm says the sql is INSERT INTO "ss"."test_user" ("status") VALUES (9)
but the real sql is INSERT INTO "ss"."test_user" ("status") VALUES (UserStatus String) which cause the error

I try to fix this by change schema/field.go

func (field *Field) setupValuerAndSetter(modelType reflect.Type) {
	// Setup NewValuePool
	field.setupNewValuePool()

	// ValueOf returns field's value and if it is zero
	fieldIndex := field.StructField.Index[0]
	switch {
	case len(field.StructField.Index) == 1 && fieldIndex >= 0:
		field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
			v = reflect.Indirect(v)
			fieldValue := v.Field(fieldIndex)
			return fieldValue.Interface(), fieldValue.IsZero()

to

func (field *Field) setupValuerAndSetter(modelType reflect.Type) {
	// Setup NewValuePool
	field.setupNewValuePool()

	// ValueOf returns field's value and if it is zero
	fieldIndex := field.StructField.Index[0]
	switch {
	case len(field.StructField.Index) == 1 && fieldIndex >= 0:
		field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
			v = reflect.Indirect(v)
			fieldValue := v.Field(fieldIndex)
			switch fieldValue.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				return fieldValue.Int(), fieldValue.IsZero()
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				return fieldValue.Uint(), fieldValue.IsZero()
			default:
				return fieldValue.Interface(), fieldValue.IsZero()
			}
		}

it works.

but I found a issue in pgx jackc/pgx#1551

I am not sure whether gorm or pgx could fix this.

the String() method mostly generated by protobuf for every enum,this is also why it is so hard to avoid

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions