Repository: go-gorm/gorm
Pull request #6191 (2023-03-27 09:44:38)

fix: `limit(0).offset(b)` return all data, where b <= 0
<!--
Make sure these boxes checked before submitting your pull request.

For significant changes, please open an issue to make an agreement on an implementation design/plan first before starting it.
-->

- [x] Do only one thing
- [x] Non breaking API changes
- [x] Tested

### What did this pull request do?

fix for issue https://github.com/go-gorm/gorm/issues/6188#issue-1641432003



<!--
provide a general description of the code changes in your pull request
-->

### User Case Description

<!-- Your use case -->


when execute `db.Limit(0).Offset(0).Where("id > ?", 10).Find(&users)`, it will return all data satified where condition. Namely, sql generated is `select * from users where id > 10`, but not `select * from users where id > 10 limit 0`, which is diff from sql semantics.





Patch:
diff --git a/clause/limit.go b/clause/limit.go
index 3ede738..abda005 100644
--- a/clause/limit.go
+++ b/clause/limit.go
@@ -33,7 +33,7 @@ func (limit Limit) MergeClause(clause *Clause) {
 	clause.Name = ""
 
 	if v, ok := clause.Expression.(Limit); ok {
-		if (limit.Limit == nil || *limit.Limit == 0) && (v.Limit != nil && *v.Limit != 0) {
+		if (limit.Limit == nil || *limit.Limit == 0) && v.Limit != nil {
 			limit.Limit = v.Limit
 		}
 
diff --git a/schema/field.go b/schema/field.go
index 00beb06..15edab9 100644
--- a/schema/field.go
+++ b/schema/field.go
@@ -580,8 +580,6 @@ func (field *Field) setupValuerAndSetter() {
 			case **bool:
 				if data != nil && *data != nil {
 					field.ReflectValueOf(ctx, value).SetBool(**data)
-				} else {
-					field.ReflectValueOf(ctx, value).SetBool(false)
 				}
 			case bool:
 				field.ReflectValueOf(ctx, value).SetBool(data)
@@ -601,8 +599,6 @@ func (field *Field) setupValuerAndSetter() {
 			case **int64:
 				if data != nil && *data != nil {
 					field.ReflectValueOf(ctx, value).SetInt(**data)
-				} else {
-					field.ReflectValueOf(ctx, value).SetInt(0)
 				}
 			case int64:
 				field.ReflectValueOf(ctx, value).SetInt(data)
@@ -667,8 +663,6 @@ func (field *Field) setupValuerAndSetter() {
 			case **uint64:
 				if data != nil && *data != nil {
 					field.ReflectValueOf(ctx, value).SetUint(**data)
-				} else {
-					field.ReflectValueOf(ctx, value).SetUint(0)
 				}
 			case uint64:
 				field.ReflectValueOf(ctx, value).SetUint(data)
@@ -721,8 +715,6 @@ func (field *Field) setupValuerAndSetter() {
 			case **float64:
 				if data != nil && *data != nil {
 					field.ReflectValueOf(ctx, value).SetFloat(**data)
-				} else {
-					field.ReflectValueOf(ctx, value).SetFloat(0)
 				}
 			case float64:
 				field.ReflectValueOf(ctx, value).SetFloat(data)
@@ -767,8 +759,6 @@ func (field *Field) setupValuerAndSetter() {
 			case **string:
 				if data != nil && *data != nil {
 					field.ReflectValueOf(ctx, value).SetString(**data)
-				} else {
-					field.ReflectValueOf(ctx, value).SetString("")
 				}
 			case string:
 				field.ReflectValueOf(ctx, value).SetString(data)


Test patch:
diff --git a/clause/limit_test.go b/clause/limit_test.go
index 79065ab..a9fd4e2 100644
--- a/clause/limit_test.go
+++ b/clause/limit_test.go
@@ -28,6 +28,10 @@ func TestLimit(t *testing.T) {
 			[]clause.Interface{clause.Select{}, clause.From{}, clause.Limit{Limit: &limit0}},
 			"SELECT * FROM `users` LIMIT 0", nil,
 		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Limit{Limit: &limit0}, clause.Limit{Offset: 0}},
+			"SELECT * FROM `users` LIMIT 0", nil,
+		},
 		{
 			[]clause.Interface{clause.Select{}, clause.From{}, clause.Limit{Offset: 20}},
 			"SELECT * FROM `users` OFFSET 20", nil,
diff --git a/tests/embedded_struct_test.go b/tests/embedded_struct_test.go
index 63ec53e..0d240fd 100644
--- a/tests/embedded_struct_test.go
+++ b/tests/embedded_struct_test.go
@@ -103,9 +103,16 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) {
 		URL   string
 	}
 
+	type Author struct {
+		ID    string
+		Name  string
+		Email string
+	}
+
 	type HNPost struct {
 		*BasePost
 		Upvotes int32
+		*Author `gorm:"EmbeddedPrefix:user_"` // Embedded struct
 	}
 
 	DB.Migrator().DropTable(&HNPost{})
@@ -123,6 +130,10 @@ func TestEmbeddedPointerTypeStruct(t *testing.T) {
 	if hnPost.Title != "embedded_pointer_type" {
 		t.Errorf("Should find correct value for embedded pointer type")
 	}
+
+	if hnPost.Author != nil {
+		t.Errorf("Expected to get back a nil Author but got: %v", hnPost.Author)
+	}
 }
 
 type Content struct {