mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
fix(database/gdb): Raw SQL Count ignores Where condition (#4611)
## Summary - Fixed a bug where `Raw()` with `Where()` and `Count()`/`ScanAndCount()` was ignoring the Where conditions in Count queries - The issue was in `getFormattedSqlAndArgs()` which returned `nil` for `conditionArgs` without calling `formatCondition()` for Raw SQL in `SelectTypeCount` case ## Changes - Modified `database/gdb/gdb_model_select.go` to call `formatCondition()` for Raw SQL Count queries - Added comprehensive test cases for MySQL and PostgreSQL drivers - Fixed incorrect test expectation in `Test_Model_Raw` ## Test plan - [x] Added `Test_Issue4500` with 6 edge cases covering: - Raw SQL with WHERE + external Where condition - Raw SQL without WHERE + external Where condition - Raw + Where + ScanAndCount - Raw + multiple Where conditions - Raw SQL with no external Where (baseline) - Verify All() still works correctly - [x] All tests pass on PostgreSQL Closes #4500
This commit is contained in:
@ -2359,7 +2359,12 @@ func Test_Model_Raw(t *testing.T) {
|
||||
OrderDesc("id").
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, int64(6))
|
||||
// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.
|
||||
// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)
|
||||
// WhereLT("id", 8): id < 8 -> (1, 5, 7)
|
||||
// WhereIn("id", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)
|
||||
// Result: 3 records match all conditions
|
||||
t.Assert(count, int64(3))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1865,3 +1865,87 @@ func Test_Issue4086(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/4500
|
||||
// Raw() Count ignores Where condition
|
||||
func Test_Issue4500(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
// Test 1: Raw SQL with WHERE + external Where condition + Count
|
||||
// This tests that formatCondition correctly uses AND when Raw SQL already has WHERE
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw SQL: id IN (1,5,7,8,9,10) = 6 records
|
||||
// Where: id < 8 filters to {1,5,7} = 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 2: Raw SQL without WHERE + external Where condition + Count
|
||||
// This tests that formatCondition correctly adds WHERE
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s", table)).
|
||||
WhereLT("id", 5).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw SQL: all 10 records
|
||||
// Where: id < 5 = {1,2,3,4} = 4 records
|
||||
t.Assert(count, 4)
|
||||
})
|
||||
|
||||
// Test 3: Raw + Where + ScanAndCount
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
}
|
||||
var users []User
|
||||
var total int
|
||||
err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
ScanAndCount(&users, &total, false)
|
||||
t.AssertNil(err)
|
||||
// Both scan result and count should respect Where condition
|
||||
t.Assert(len(users), 3)
|
||||
t.Assert(total, 3)
|
||||
})
|
||||
|
||||
// Test 4: Raw + multiple Where conditions + Count
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id > ?", table), 0).
|
||||
WhereLT("id", 5).
|
||||
WhereGTE("id", 2).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw: id > 0 (all 10 records)
|
||||
// Where: id < 5 AND id >= 2 = {2, 3, 4} = 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 5: Raw SQL with no external Where + Count (baseline test)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 2, 3}).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Should count 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 6: Verify All() still works correctly with Raw + Where
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(all), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -2944,7 +2944,9 @@ func Test_Model_Raw(t *testing.T) {
|
||||
Limit(2).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, int64(6))
|
||||
// Raw SQL selects {1,5,7,8,9,10}, Where filters to id < 8 AND id IN {1,2,3,4,5,6,7}
|
||||
// Result: {1,5,7} = 3 records
|
||||
t.Assert(count, int64(3))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1347,7 +1347,12 @@ func Test_Model_Raw(t *testing.T) {
|
||||
OrderDesc("ID").
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 6)
|
||||
// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.
|
||||
// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)
|
||||
// WhereLT("ID", 8): id < 8 -> (1, 5, 7)
|
||||
// WhereIn("ID", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)
|
||||
// Result: 3 records match all conditions
|
||||
t.Assert(count, int64(3))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -206,6 +206,90 @@ func Test_Issue4033(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/4500
|
||||
// Raw() Count ignores Where condition
|
||||
func Test_Issue4500(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
// Test 1: Raw SQL with WHERE + external Where condition + Count
|
||||
// This tests that formatCondition correctly uses AND when Raw SQL already has WHERE
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw SQL: id IN (1,5,7,8,9,10) = 6 records
|
||||
// Where: id < 8 filters to {1,5,7} = 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 2: Raw SQL without WHERE + external Where condition + Count
|
||||
// This tests that formatCondition correctly adds WHERE
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s", table)).
|
||||
WhereLT("id", 5).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw SQL: all 10 records
|
||||
// Where: id < 5 = {1,2,3,4} = 4 records
|
||||
t.Assert(count, 4)
|
||||
})
|
||||
|
||||
// Test 3: Raw + Where + ScanAndCount
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
}
|
||||
var users []User
|
||||
var total int
|
||||
err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
ScanAndCount(&users, &total, false)
|
||||
t.AssertNil(err)
|
||||
// Both scan result and count should respect Where condition
|
||||
t.Assert(len(users), 3)
|
||||
t.Assert(total, 3)
|
||||
})
|
||||
|
||||
// Test 4: Raw + multiple Where conditions + Count
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id > ?", table), 0).
|
||||
WhereLT("id", 5).
|
||||
WhereGTE("id", 2).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Raw: id > 0 (all 10 records)
|
||||
// Where: id < 5 AND id >= 2 = {2, 3, 4} = 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 5: Raw SQL with no external Where + Count (baseline test)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 2, 3}).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
// Should count 3 records
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
|
||||
// Test 6: Verify All() still works correctly with Raw + Where
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.
|
||||
Raw(fmt.Sprintf("SELECT * FROM %s WHERE id IN (?)", table), g.Slice{1, 5, 7, 8, 9, 10}).
|
||||
WhereLT("id", 8).
|
||||
All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(all), 3)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/4595
|
||||
// FieldsPrefix silently drops fields when using table alias before LeftJoin.
|
||||
func Test_Issue4595(t *testing.T) {
|
||||
|
||||
@ -3482,7 +3482,12 @@ func Test_Model_Raw(t *testing.T) {
|
||||
Limit(2).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, int64(6))
|
||||
// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.
|
||||
// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)
|
||||
// WhereLT("id", 8): id < 8 -> (1, 5, 7)
|
||||
// WhereIn("id", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)
|
||||
// Result: 3 records match all conditions
|
||||
t.Assert(count, int64(3))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -3480,7 +3480,12 @@ func Test_Model_Raw(t *testing.T) {
|
||||
Limit(2).
|
||||
Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, int64(6))
|
||||
// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.
|
||||
// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)
|
||||
// WhereLT("id", 8): id < 8 -> (1, 5, 7)
|
||||
// WhereIn("id", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)
|
||||
// Result: 3 records match all conditions
|
||||
t.Assert(count, int64(3))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -724,8 +724,12 @@ func (m *Model) getFormattedSqlAndArgs(
|
||||
}
|
||||
// Raw SQL Model.
|
||||
if m.rawSql != "" {
|
||||
sqlWithHolder = fmt.Sprintf("SELECT %s FROM (%s) AS T", queryFields, m.rawSql)
|
||||
return sqlWithHolder, nil
|
||||
conditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, false, true)
|
||||
sqlWithHolder = fmt.Sprintf(
|
||||
"SELECT %s FROM (%s%s) AS T",
|
||||
queryFields, m.rawSql, conditionWhere+conditionExtra,
|
||||
)
|
||||
return sqlWithHolder, conditionArgs
|
||||
}
|
||||
conditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, false, true)
|
||||
sqlWithHolder = fmt.Sprintf("SELECT %s FROM %s%s", queryFields, m.tables, conditionWhere+conditionExtra)
|
||||
|
||||
Reference in New Issue
Block a user