From 4109ce1e237d49594956e7f6a80946814d2d9da4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 25 Jul 2023 08:37:12 +0000 Subject: [PATCH 1/2] Fix a serious bug when using rows and reuse the session (#2309) Reviewed-on: https://gitea.com/xorm/xorm/pulls/2309 --- integrations/session_query_test.go | 73 +++++++++++++++++++++++++----- rows.go | 2 + 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/integrations/session_query_test.go b/integrations/session_query_test.go index 00b7d7a6..ff62f25d 100644 --- a/integrations/session_query_test.go +++ b/integrations/session_query_test.go @@ -30,7 +30,7 @@ func TestQueryString(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVar2))) - var data = GetVar2{ + data := GetVar2{ Msg: "hi", Age: 28, Money: 1.5, @@ -58,7 +58,7 @@ func TestQueryString2(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVar3))) - var data = GetVar3{ + data := GetVar3{ Msg: false, } _, err := testEngine.Insert(data) @@ -95,7 +95,7 @@ func TestQueryInterface(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVarInterface))) - var data = GetVarInterface{ + data := GetVarInterface{ Msg: "hi", Age: 28, Money: 1.5, @@ -128,7 +128,7 @@ func TestQueryNoParams(t *testing.T) { assert.NoError(t, testEngine.Sync(new(QueryNoParams))) - var q = QueryNoParams{ + q := QueryNoParams{ Msg: "message", Age: 20, Money: 3000, @@ -172,7 +172,7 @@ func TestQueryStringNoParam(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVar4))) - var data = GetVar4{ + data := GetVar4{ Msg: false, } _, err := testEngine.Insert(data) @@ -209,7 +209,7 @@ func TestQuerySliceStringNoParam(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVar6))) - var data = GetVar6{ + data := GetVar6{ Msg: false, } _, err := testEngine.Insert(data) @@ -246,7 +246,7 @@ func TestQueryInterfaceNoParam(t *testing.T) { assert.NoError(t, testEngine.Sync(new(GetVar5))) - var data = GetVar5{ + data := GetVar5{ Msg: false, } _, err := testEngine.Insert(data) @@ -280,7 +280,7 @@ func TestQueryWithBuilder(t *testing.T) { assert.NoError(t, testEngine.Sync(new(QueryWithBuilder))) - var q = QueryWithBuilder{ + q := QueryWithBuilder{ Msg: "message", Age: 20, Money: 3000, @@ -329,14 +329,14 @@ func TestJoinWithSubQuery(t *testing.T) { assert.NoError(t, testEngine.Sync(new(JoinWithSubQuery1), new(JoinWithSubQueryDepart))) - var depart = JoinWithSubQueryDepart{ + depart := JoinWithSubQueryDepart{ Name: "depart1", } cnt, err := testEngine.Insert(&depart) assert.NoError(t, err) assert.EqualValues(t, 1, cnt) - var q = JoinWithSubQuery1{ + q := JoinWithSubQuery1{ Msg: "message", DepartId: depart.Id, Money: 3000, @@ -401,7 +401,7 @@ func TestQueryBLOBInMySQL(t *testing.T) { } const N = 10 - var data = []Avatar{} + data := []Avatar{} for i := 0; i < N; i++ { // allocate a []byte that is as twice big as the last one // so that the underlying buffer will need to reallocate when querying @@ -448,3 +448,54 @@ func TestQueryBLOBInMySQL(t *testing.T) { } } } + +func TestRowsReset(t *testing.T) { + assert.NoError(t, PrepareEngine()) + + type RowsReset1 struct { + Id int64 + Name string + } + + type RowsReset2 struct { + Id int64 + Name string + } + + assert.NoError(t, testEngine.Sync(new(RowsReset1), new(RowsReset2))) + + data := []RowsReset1{ + {0, "1"}, + {0, "2"}, + {0, "3"}, + } + _, err := testEngine.Insert(data) + assert.NoError(t, err) + + data2 := []RowsReset2{ + {0, "4"}, + {0, "5"}, + {0, "6"}, + } + _, err = testEngine.Insert(data2) + assert.NoError(t, err) + + sess := testEngine.NewSession() + defer sess.Close() + + rows, err := sess.Rows(new(RowsReset1)) + assert.NoError(t, err) + for rows.Next() { + var data1 RowsReset1 + assert.NoError(t, rows.Scan(&data1)) + } + rows.Close() + + var rrs []RowsReset2 + assert.NoError(t, sess.Find(&rrs)) + + assert.Len(t, rrs, 3) + assert.EqualValues(t, "4", rrs[0].Name) + assert.EqualValues(t, "5", rrs[1].Name) + assert.EqualValues(t, "6", rrs[2].Name) +} diff --git a/rows.go b/rows.go index a42eedb9..c539410e 100644 --- a/rows.go +++ b/rows.go @@ -144,6 +144,8 @@ func (rows *Rows) Close() error { defer rows.session.Close() } + defer rows.session.resetStatement() + if rows.rows != nil { return rows.rows.Close() } From 9aab1f689cde85322856b9410194d7c26f4cd217 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 25 Jul 2023 09:27:25 +0000 Subject: [PATCH 2/2] Count will ignore order by as before (#2307) Reviewed-on: https://gitea.com/xorm/xorm/pulls/2307 --- integrations/session_count_test.go | 5 +++++ internal/statements/query.go | 31 ++++++++++++++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/integrations/session_count_test.go b/integrations/session_count_test.go index 079602c3..c6e64e76 100644 --- a/integrations/session_count_test.go +++ b/integrations/session_count_test.go @@ -125,6 +125,11 @@ func TestWithTableName(t *testing.T) { total, err = testEngine.OrderBy("count(`id`) desc").Count(CountWithTableName{}) assert.NoError(t, err) assert.EqualValues(t, 2, total) + + // the orderby will be ignored by count because some databases will return errors if the orderby columns not in group by + total, err = testEngine.OrderBy("`name`").Count(CountWithTableName{}) + assert.NoError(t, err) + assert.EqualValues(t, 2, total) } func TestCountWithSelectCols(t *testing.T) { diff --git a/internal/statements/query.go b/internal/statements/query.go index 0f4c40b1..216a2028 100644 --- a/internal/statements/query.go +++ b/internal/statements/query.go @@ -35,7 +35,7 @@ func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []int } buf := builder.NewWriter() - if err := statement.writeSelect(buf, statement.genSelectColumnStr(), true); err != nil { + if err := statement.writeSelect(buf, statement.genSelectColumnStr(), true, true); err != nil { return "", nil, err } return buf.String(), buf.Args(), nil @@ -66,7 +66,7 @@ func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (stri } buf := builder.NewWriter() - if err := statement.writeSelect(buf, strings.Join(sumStrs, ", "), true); err != nil { + if err := statement.writeSelect(buf, strings.Join(sumStrs, ", "), true, true); err != nil { return "", nil, err } return buf.String(), buf.Args(), nil @@ -122,7 +122,7 @@ func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{}, } buf := builder.NewWriter() - if err := statement.writeSelect(buf, columnStr, true); err != nil { + if err := statement.writeSelect(buf, columnStr, true, true); err != nil { return "", nil, err } return buf.String(), buf.Args(), nil @@ -153,12 +153,6 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa selectSQL = "count(*)" } } - var subQuerySelect string - if statement.GroupByStr != "" { - subQuerySelect = statement.GroupByStr - } else { - subQuerySelect = selectSQL - } buf := builder.NewWriter() if statement.GroupByStr != "" { @@ -167,7 +161,14 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa } } - if err := statement.writeSelect(buf, subQuerySelect, false); err != nil { + var subQuerySelect string + if statement.GroupByStr != "" { + subQuerySelect = statement.GroupByStr + } else { + subQuerySelect = selectSQL + } + + if err := statement.writeSelect(buf, subQuerySelect, false, false); err != nil { return "", nil, err } @@ -364,7 +365,7 @@ func (statement *Statement) writeOracleLimit(w *builder.BytesWriter, columnStr s return err } -func (statement *Statement) writeSelect(buf *builder.BytesWriter, columnStr string, needLimit bool) error { +func (statement *Statement) writeSelect(buf *builder.BytesWriter, columnStr string, needLimit, needOrderBy bool) error { if err := statement.writeSelectColumns(buf, columnStr); err != nil { return err } @@ -380,8 +381,10 @@ func (statement *Statement) writeSelect(buf *builder.BytesWriter, columnStr stri if err := statement.writeHaving(buf); err != nil { return err } - if err := statement.writeOrderBys(buf); err != nil { - return err + if needOrderBy { + if err := statement.writeOrderBys(buf); err != nil { + return err + } } dialect := statement.dialect @@ -519,7 +522,7 @@ func (statement *Statement) GenFindSQL(autoCond builder.Cond) (string, []interfa statement.cond = statement.cond.And(autoCond) buf := builder.NewWriter() - if err := statement.writeSelect(buf, statement.genSelectColumnStr(), true); err != nil { + if err := statement.writeSelect(buf, statement.genSelectColumnStr(), true, true); err != nil { return "", nil, err } return buf.String(), buf.Args(), nil