From 57365108ae98aefd57a732f0e2e65fa38f865798 Mon Sep 17 00:00:00 2001 From: satorunooshie Date: Mon, 27 Dec 2021 10:11:44 +0800 Subject: [PATCH 01/10] Fix insertMultipleStruct to insert null value under certain circumstances (#2077) The behavior of multi insertion of null differs from that of single insertion. On the other hand, behavior between single and bulk insertion of null using pointer of struct field is identical. Please see the example below. ```go s := engineGroup.NewSession() type User struct { ID int `xorm:"not null pk autoincr INT(10)"` Name string `xorm:"not null VARCHAR(191)"` Age int64 `xorm:"null BIGINT(20)"` } list := []*User{ { Name: "John", }, { Name: "Wick", }, } s.Nullable("age") // Single insertion works _, err := s.Insert(list[0]) // [table] `user` INSERT INTO `user` (`name`,`age`) VALUES (?, ?) [John ] s.Nullable("age") // Bulk insertion does not work _, err := s.Insert(list) // [table] `user` INSERT INTO `user` (`name,`age`) VALUES (?, ?),(?, ?) [John, 0, Wick, 0] //--------------------------------- //Using pointer, which is nullable, the generated sql has no difference. //--------------------------------- type User struct { ID int `xorm:"not null pk autoincr INT(10)"` Name string `xorm:"not null VARCHAR(191)"` Age *int64 `xorm:"null BIGINT(20)"` } list := []*User{ { Name: "John", }, { Name: "Wick", }, } s.Nullable("age") // Single insertion works _, err := s.Insert(list[0]) // [table] `user` INSERT INTO `user` (`name`,`age`) VALUES (?, ?) [John ] s.Nullable("age") // Bulk insertion does not work _, err := s.Insert(list) // [table] `user` INSERT INTO `user` (`name,`age`) VALUES (?, ?),(?, ?) [John, , Wick, ] ``` Reviewed-on: https://gitea.com/xorm/xorm/pulls/2077 Co-authored-by: satorunooshie Co-committed-by: satorunooshie --- session_insert.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/session_insert.go b/session_insert.go index 4835eb14..fc025613 100644 --- a/session_insert.go +++ b/session_insert.go @@ -142,6 +142,13 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e if len(session.statement.ColumnMap) > 0 && !session.statement.ColumnMap.Contain(col.Name) { continue } + // !satorunooshie! set fieldValue as nil when column is nullable and zero-value + if _, ok := getFlagForColumn(session.statement.NullableMap, col); ok { + if col.Nullable && utils.IsValueZero(fieldValue) { + var nilValue *int + fieldValue = reflect.ValueOf(nilValue) + } + } if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime { val, t, err := session.engine.nowTime(col) if err != nil { From 470807151d0a443bcdd49a13d3ec108e1eb65bd2 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Wed, 5 Jan 2022 09:37:18 +0800 Subject: [PATCH 02/10] fix cross db dumping of bools (#2089) When dumping booleans these need to be converted from the original DB representation to the new db representation. In the case of most DBs this is simply to 0 or 1 but for postgres these have to be false or true. Signed-off-by: Andrew Thornton Reviewed-on: https://gitea.com/xorm/xorm/pulls/2089 Reviewed-by: Lunny Xiao Co-authored-by: Andrew Thornton Co-committed-by: Andrew Thornton --- engine.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/engine.go b/engine.go index 709cc384..1257de20 100644 --- a/engine.go +++ b/engine.go @@ -12,6 +12,7 @@ import ( "os" "reflect" "runtime" + "strconv" "strings" "time" @@ -438,16 +439,14 @@ func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...sch return engine.dumpTables(context.Background(), tables, w, tp...) } -func formatBool(s string, dstDialect dialects.Dialect) string { - if dstDialect.URI().DBType == schemas.MSSQL { - switch s { - case "true": +func formatBool(s bool, dstDialect dialects.Dialect) string { + if dstDialect.URI().DBType != schemas.POSTGRES { + if s { return "1" - case "false": - return "0" } + return "0" } - return s + return strconv.FormatBool(s) } // dumpTables dump database all table structs and data to w with specify db type @@ -581,8 +580,13 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w return err } } else { - if stp.IsBool() || (dstDialect.URI().DBType == schemas.MSSQL && strings.EqualFold(stp.Name, schemas.Bit)) { - if _, err = io.WriteString(w, formatBool(s.String, dstDialect)); err != nil { + if table.Columns()[i].SQLType.IsBool() || stp.IsBool() || (dstDialect.URI().DBType == schemas.MSSQL && strings.EqualFold(stp.Name, schemas.Bit)) { + val, err := strconv.ParseBool(s.String) + if err != nil { + return err + } + + if _, err = io.WriteString(w, formatBool(val, dstDialect)); err != nil { return err } } else if stp.IsNumeric() { From 2fa71307041bd5c181cd37f48492bdc4620d6674 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 6 Jan 2022 19:43:06 +0800 Subject: [PATCH 03/10] Improve find interface (#2092) Reviewed-on: https://gitea.com/xorm/xorm/pulls/2092 --- session_find.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/session_find.go b/session_find.go index dcac93b7..57ac7bb7 100644 --- a/session_find.go +++ b/session_find.go @@ -254,9 +254,9 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect switch elemType.Kind() { case reflect.Slice: - err = rows.ScanSlice(bean) + err = session.getSlice(rows, types, fields, bean) case reflect.Map: - err = rows.ScanMap(bean) + err = session.getMap(rows, types, fields, bean) default: err = rows.Scan(bean) } From cd36b112ae482f4fa9f0c590e103e32211a2ad80 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Fri, 7 Jan 2022 16:04:01 +0800 Subject: [PATCH 04/10] Escape string and blob results from dump more correctly (#2091) dumpTables currently badly handles BLOB and TEXT data containing control characters: * MySQL will interpret and unescape string literals e.g.`\r` will become carriage return. * Postgres will not allow string literals to contain NUL nor will SQLite so BLOBs will not dump correctly. * Schemas should not be set on the destination dump * MSSQL needs the N prefix to correctly ensure that UTF-8 data is correctly transferred. Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2091 Reviewed-by: Lunny Xiao Co-authored-by: Andrew Thornton Co-committed-by: Andrew Thornton --- engine.go | 191 +++++++++++++++++++++++++++++++++++- integrations/engine_test.go | 13 ++- 2 files changed, 199 insertions(+), 5 deletions(-) diff --git a/engine.go b/engine.go index 1257de20..b7dcf5a2 100644 --- a/engine.go +++ b/engine.go @@ -11,6 +11,7 @@ import ( "io" "os" "reflect" + "regexp" "runtime" "strconv" "strings" @@ -449,6 +450,8 @@ func formatBool(s bool, dstDialect dialects.Dialect) string { return strconv.FormatBool(s) } +var controlCharactersRe = regexp.MustCompile(`[\x00-\x1f\x7f]+`) + // dumpTables dump database all table structs and data to w with specify db type func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error { var dstDialect dialects.Dialect @@ -464,7 +467,10 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w destURI := dialects.URI{ DBType: tp[0], DBName: uri.DBName, - Schema: uri.Schema, + // DO NOT SET SCHEMA HERE + } + if tp[0] == schemas.POSTGRES { + destURI.Schema = engine.dialect.URI().Schema } if err := dstDialect.Init(&destURI); err != nil { return err @@ -479,6 +485,13 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w return err } + if dstDialect.URI().DBType == schemas.MYSQL { + // For MySQL set NO_BACKLASH_ESCAPES so that strings work properly + if _, err := io.WriteString(w, "SET sql_mode='NO_BACKSLASH_ESCAPES';\n"); err != nil { + return err + } + } + for i, table := range tables { dstTable := table if table.Type != nil { @@ -598,6 +611,182 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w if _, err = io.WriteString(w, "'"+r+"'"); err != nil { return err } + } else if len(s.String) == 0 { + if _, err := io.WriteString(w, "''"); err != nil { + return err + } + } else if dstDialect.URI().DBType == schemas.POSTGRES { + if dstTable.Columns()[i].SQLType.IsBlob() { + // Postgres has the escape format and we should use that for bytea data + if _, err := fmt.Fprintf(w, "'\\x%x'", s.String); err != nil { + return err + } + } else { + // Postgres concatentates strings using || (NOTE: a NUL byte in a text segment will fail) + toCheck := strings.ReplaceAll(s.String, "'", "''") + for len(toCheck) > 0 { + loc := controlCharactersRe.FindStringIndex(toCheck) + if loc == nil { + if _, err := io.WriteString(w, "'"+toCheck+"'"); err != nil { + return err + } + break + } + if loc[0] > 0 { + if _, err := io.WriteString(w, "'"+toCheck[:loc[0]]+"' || "); err != nil { + return err + } + } + if _, err := io.WriteString(w, "e'"); err != nil { + return err + } + for i := loc[0]; i < loc[1]; i++ { + if _, err := fmt.Fprintf(w, "\\x%02x", toCheck[i]); err != nil { + return err + } + } + toCheck = toCheck[loc[1]:] + if len(toCheck) > 0 { + if _, err := io.WriteString(w, "' || "); err != nil { + return err + } + } else { + if _, err := io.WriteString(w, "'"); err != nil { + return err + } + } + } + } + } else if dstDialect.URI().DBType == schemas.MYSQL { + loc := controlCharactersRe.FindStringIndex(s.String) + if loc == nil { + if _, err := io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil { + return err + } + } else { + if _, err := io.WriteString(w, "CONCAT("); err != nil { + return err + } + toCheck := strings.ReplaceAll(s.String, "'", "''") + for len(toCheck) > 0 { + loc := controlCharactersRe.FindStringIndex(toCheck) + if loc == nil { + if _, err := io.WriteString(w, "'"+toCheck+"')"); err != nil { + return err + } + break + } + if loc[0] > 0 { + if _, err := io.WriteString(w, "'"+toCheck[:loc[0]]+"', "); err != nil { + return err + } + } + for i := loc[0]; i < loc[1]-1; i++ { + if _, err := io.WriteString(w, "CHAR("+strconv.Itoa(int(toCheck[i]))+"), "); err != nil { + return err + } + } + char := toCheck[loc[1]-1] + toCheck = toCheck[loc[1]:] + if len(toCheck) > 0 { + if _, err := io.WriteString(w, "CHAR("+strconv.Itoa(int(char))+"), "); err != nil { + return err + } + } else { + if _, err = io.WriteString(w, "CHAR("+strconv.Itoa(int(char))+"))"); err != nil { + return err + } + } + } + } + } else if dstDialect.URI().DBType == schemas.SQLITE { + if dstTable.Columns()[i].SQLType.IsBlob() { + // SQLite has its escape format + if _, err := fmt.Fprintf(w, "X'%x'", s.String); err != nil { + return err + } + } else { + // SQLite concatentates strings using || (NOTE: a NUL byte in a text segment will fail) + toCheck := strings.ReplaceAll(s.String, "'", "''") + for len(toCheck) > 0 { + loc := controlCharactersRe.FindStringIndex(toCheck) + if loc == nil { + if _, err := io.WriteString(w, "'"+toCheck+"'"); err != nil { + return err + } + break + } + if loc[0] > 0 { + if _, err := io.WriteString(w, "'"+toCheck[:loc[0]]+"' || "); err != nil { + return err + } + } + if _, err := fmt.Fprintf(w, "X'%x'", toCheck[loc[0]:loc[1]]); err != nil { + return err + } + toCheck = toCheck[loc[1]:] + if len(toCheck) > 0 { + if _, err := io.WriteString(w, " || "); err != nil { + return err + } + } + } + } + } else if dstDialect.URI().DBType == schemas.DAMENG || dstDialect.URI().DBType == schemas.ORACLE { + if dstTable.Columns()[i].SQLType.IsBlob() { + // ORACLE/DAMENG uses HEXTORAW + if _, err := fmt.Fprintf(w, "HEXTORAW('%x')", s.String); err != nil { + return err + } + } else { + // ORACLE/DAMENG concatentates strings in multiple ways but uses CHAR and has CONCAT + // (NOTE: a NUL byte in a text segment will fail) + if _, err := io.WriteString(w, "CONCAT("); err != nil { + return err + } + toCheck := strings.ReplaceAll(s.String, "'", "''") + for len(toCheck) > 0 { + loc := controlCharactersRe.FindStringIndex(toCheck) + if loc == nil { + if _, err := io.WriteString(w, "'"+toCheck+"')"); err != nil { + return err + } + break + } + if loc[0] > 0 { + if _, err := io.WriteString(w, "'"+toCheck[:loc[0]]+"', "); err != nil { + return err + } + } + for i := loc[0]; i < loc[1]-1; i++ { + if _, err := io.WriteString(w, "CHAR("+strconv.Itoa(int(toCheck[i]))+"), "); err != nil { + return err + } + } + char := toCheck[loc[1]-1] + toCheck = toCheck[loc[1]:] + if len(toCheck) > 0 { + if _, err := io.WriteString(w, "CHAR("+strconv.Itoa(int(char))+"), "); err != nil { + return err + } + } else { + if _, err = io.WriteString(w, "CHAR("+strconv.Itoa(int(char))+"))"); err != nil { + return err + } + } + } + } + } else if dstDialect.URI().DBType == schemas.MSSQL { + if dstTable.Columns()[i].SQLType.IsBlob() { + // MSSQL uses CONVERT(VARBINARY(MAX), '0xDEADBEEF', 1) + if _, err := fmt.Fprintf(w, "CONVERT(VARBINARY(MAX), '0x%x', 1)", s.String); err != nil { + return err + } + } else { + if _, err = io.WriteString(w, "N'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil { + return err + } + } } else { if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil { return err diff --git a/integrations/engine_test.go b/integrations/engine_test.go index dbe17571..cdcdd6be 100644 --- a/integrations/engine_test.go +++ b/integrations/engine_test.go @@ -143,6 +143,7 @@ func TestDumpTables(t *testing.T) { type TestDumpTableStruct struct { Id int64 + Data []byte `xorm:"BLOB"` Name string IsMan bool Created time.Time `xorm:"created"` @@ -152,10 +153,14 @@ func TestDumpTables(t *testing.T) { _, err := testEngine.Insert([]TestDumpTableStruct{ {Name: "1", IsMan: true}, - {Name: "2\n"}, - {Name: "3;"}, - {Name: "4\n;\n''"}, - {Name: "5'\n"}, + {Name: "2\n", Data: []byte{'\000', '\001', '\002'}}, + {Name: "3;", Data: []byte("0x000102")}, + {Name: "4\n;\n''", Data: []byte("Help")}, + {Name: "5'\n", Data: []byte("0x48656c70")}, + {Name: "6\\n'\n", Data: []byte("48656c70")}, + {Name: "7\\n'\r\n", Data: []byte("7\\n'\r\n")}, + {Name: "x0809ee"}, + {Name: "090a10"}, }) assert.NoError(t, err) From 3d1c9fb761325f98ea2c5493bbb28e0431936784 Mon Sep 17 00:00:00 2001 From: jixianlqb Date: Sun, 16 Jan 2022 16:36:07 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E5=AF=B9=20DATE=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E8=BD=AC=E6=8D=A2=20(#2093)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对 DATE格式进行转换 Co-authored-by: laiqiangbin Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2093 Reviewed-by: Lunny Xiao Co-authored-by: jixianlqb Co-committed-by: jixianlqb --- convert/time.go | 10 ++++++++++ convert/time_test.go | 1 + 2 files changed, 11 insertions(+) diff --git a/convert/time.go b/convert/time.go index e53a19cd..cc2e0a10 100644 --- a/convert/time.go +++ b/convert/time.go @@ -48,6 +48,16 @@ func String2Time(s string, originalLocation *time.Location, convertedLocation *t } dt = dt.In(convertedLocation) return &dt, nil + } else if len(s) == 10 && s[4] == '-' { + if s == "0000-00-00" || s == "0001-01-01" { + return &time.Time{}, nil + } + dt, err := time.ParseInLocation("2006-01-02", s, originalLocation) + if err != nil { + return nil, err + } + dt = dt.In(convertedLocation) + return &dt, nil } else { i, err := strconv.ParseInt(s, 10, 64) if err == nil { diff --git a/convert/time_test.go b/convert/time_test.go index ef01b362..5ddceb64 100644 --- a/convert/time_test.go +++ b/convert/time_test.go @@ -16,6 +16,7 @@ func TestString2Time(t *testing.T) { assert.NoError(t, err) var kases = map[string]time.Time{ + "2021-08-10": time.Date(2021, 8, 10, 8, 0, 0, 0, expectedLoc), "2021-06-06T22:58:20+08:00": time.Date(2021, 6, 6, 22, 58, 20, 0, expectedLoc), "2021-07-11 10:44:00": time.Date(2021, 7, 11, 18, 44, 0, 0, expectedLoc), "2021-08-10T10:33:04Z": time.Date(2021, 8, 10, 18, 33, 04, 0, expectedLoc), From d13b607d75d50c494b1ffa24552f3733f2dde8af Mon Sep 17 00:00:00 2001 From: fuge Date: Sun, 16 Jan 2022 18:04:24 +0800 Subject: [PATCH 06/10] =?UTF-8?q?oracle=E5=88=86=E9=A1=B5=EF=BC=8Cstart=20?= =?UTF-8?q?=E4=B8=BA=200=20=E7=9A=84bug=20(#2098)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除前面判断即可。 Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2098 Reviewed-by: Lunny Xiao Co-authored-by: fuge Co-committed-by: fuge --- internal/statements/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/statements/query.go b/internal/statements/query.go index 16253417..8b383866 100644 --- a/internal/statements/query.go +++ b/internal/statements/query.go @@ -334,7 +334,7 @@ func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderB fmt.Fprint(&buf, " LIMIT ", *pLimitN) } } else if dialect.URI().DBType == schemas.ORACLE { - if statement.Start != 0 && pLimitN != nil { + if pLimitN != nil { oldString := buf.String() buf.Reset() rawColStr := columnStr From e4e830bc78d321154b739d86b2ac05854ba2f6e5 Mon Sep 17 00:00:00 2001 From: appleboy Date: Sun, 16 Jan 2022 19:04:15 +0800 Subject: [PATCH 07/10] chore(lint): remove revive and misspell command from makefile (#2088) replace revive and misspell with golangci lint Signed-off-by: Bo-Yi Wu Co-authored-by: Bo-Yi Wu Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2088 Co-authored-by: appleboy Co-committed-by: appleboy --- .revive.toml | 29 ----------------------------- Makefile | 22 ---------------------- 2 files changed, 51 deletions(-) delete mode 100644 .revive.toml diff --git a/.revive.toml b/.revive.toml deleted file mode 100644 index 9e3b629d..00000000 --- a/.revive.toml +++ /dev/null @@ -1,29 +0,0 @@ -ignoreGeneratedHeader = false -severity = "warning" -confidence = 0.8 -errorCode = 1 -warningCode = 1 - -[rule.blank-imports] -[rule.context-as-argument] -[rule.context-keys-type] -[rule.dot-imports] -[rule.empty-lines] -[rule.errorf] -[rule.error-return] -[rule.error-strings] -[rule.error-naming] -[rule.exported] -[rule.if-return] -[rule.increment-decrement] -[rule.indent-error-flow] -[rule.package-comments] -[rule.range] -[rule.receiver-naming] -[rule.struct-tag] -[rule.time-naming] -[rule.unexported-return] -[rule.unnecessary-stmt] -[rule.var-declaration] -[rule.var-naming] - arguments = [["ID", "UID", "UUID", "URL", "JSON"], []] \ No newline at end of file diff --git a/Makefile b/Makefile index 220c8592..b43c4a4c 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,6 @@ help: @echo " - clean delete integration files and build files but not css and js files" @echo " - fmt format the code" @echo " - lint run code linter" - @echo " - misspell check if a word is written wrong" @echo " - test run default unit test" @echo " - test-cockroach run integration tests for cockroach" @echo " - test-mysql run integration tests for mysql" @@ -131,27 +130,6 @@ golangci-lint-check: curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \ fi -.PHONY: revive -revive: - @hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/mgechev/revive; \ - fi - revive -config .revive.toml -exclude=./vendor/... ./... || exit 1 - -.PHONY: misspell -misspell: - @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ - fi - misspell -w -i unknwon $(GOFILES) - -.PHONY: misspell-check -misspell-check: - @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ - fi - misspell -error -i unknwon,destory $(GOFILES) - .PHONY: test test: go-check $(GO) test $(PACKAGES) From 7802393d01519f2e64537dfd1c8b9900ad4db9b5 Mon Sep 17 00:00:00 2001 From: finelog Date: Tue, 25 Jan 2022 11:09:41 +0800 Subject: [PATCH 08/10] fix reset colmap when counting distinct cols (#2096) when using distinct cols with FindAndCount, reset statement.ColumnMap will make the counting sql an syntax error, this pr try fix this. is this pr ok for merge? error sql logging: ```sql [SQL] SELECT DISTINCT `Fid` FROM `table_demo` WHERE Fkey = ? [val] [SQL] SELECT count(DISTINCT ) FROM `table_demo` WHERE Fkey = ? [val] ``` after fix: ```sql [SQL] SELECT DISTINCT `Fid` FROM `table_demo` WHERE Fkey = ? [val] [SQL] SELECT count(DISTINCT `Fid`) FROM `table_demo` WHERE Fkey = ? [val] ``` Co-authored-by: finelog Reviewed-on: https://gitea.com/xorm/xorm/pulls/2096 Reviewed-by: Lunny Xiao Co-authored-by: finelog Co-committed-by: finelog --- integrations/session_find_test.go | 30 ++++++++++++++++++++++++++++++ session_find.go | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/integrations/session_find_test.go b/integrations/session_find_test.go index f7af45fa..0e0c7bb4 100644 --- a/integrations/session_find_test.go +++ b/integrations/session_find_test.go @@ -711,6 +711,36 @@ func TestFindAndCountWithGroupBy(t *testing.T) { assert.EqualValues(t, 2, len(results)) } +func TestFindAndCountWithDistinct(t *testing.T) { + assert.NoError(t, PrepareEngine()) + + type FindAndCountWithDistinct struct { + Id int64 + Age int `xorm:"index"` + Name string + } + + assert.NoError(t, testEngine.Sync(new(FindAndCountWithDistinct))) + + _, err := testEngine.Insert([]FindAndCountWithDistinct{ + { + Name: "test1", + Age: 10, + }, + { + Name: "test2", + Age: 20, + }, + }) + assert.NoError(t, err) + + var results []FindAndCountWithDistinct + cnt, err := testEngine.Distinct("`age`").FindAndCount(&results) + assert.NoError(t, err) + assert.EqualValues(t, 2, cnt) + assert.EqualValues(t, 2, len(results)) +} + type FindMapDevice struct { Deviceid string `xorm:"pk"` Status int diff --git a/session_find.go b/session_find.go index 57ac7bb7..caf79ee3 100644 --- a/session_find.go +++ b/session_find.go @@ -57,7 +57,7 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte if session.statement.SelectStr != "" { session.statement.SelectStr = "" } - if len(session.statement.ColumnMap) > 0 { + if len(session.statement.ColumnMap) > 0 && !session.statement.IsDistinct { session.statement.ColumnMap = []string{} } if session.statement.OrderStr != "" { From 3180c418c2454771181690a360a88204a2514826 Mon Sep 17 00:00:00 2001 From: fuge Date: Tue, 25 Jan 2022 13:28:46 +0800 Subject: [PATCH 09/10] bugfix :Oid It's a special index. You can't put it in (#2105) Co-authored-by: fuge <8342337@qq.com> Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2105 Co-authored-by: fuge Co-committed-by: fuge --- dialects/postgres.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dialects/postgres.go b/dialects/postgres.go index 76279d32..a5b080aa 100644 --- a/dialects/postgres.go +++ b/dialects/postgres.go @@ -1300,6 +1300,19 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN indexType = schemas.IndexType } colNames = getIndexColName(indexdef) + + isSkip := false + //Oid It's a special index. You can't put it in + for _, element := range colNames { + if "oid" == element { + isSkip = true + break + } + } + if isSkip { + continue + } + var isRegular bool if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { newIdxName := indexName[5+len(tableName):] From 79a21b68aafacfaa11b47f45ce595dc336c51036 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bonicoli Date: Thu, 31 Mar 2022 14:26:05 +0800 Subject: [PATCH 10/10] replace GitHub links: xorm has been moved to gitea.com (#2126) Co-authored-by: Pierre-Louis Bonicoli Reviewed-on: https://gitea.com/xorm/xorm/pulls/2126 Reviewed-by: Lunny Xiao Co-authored-by: Pierre-Louis Bonicoli Co-committed-by: Pierre-Louis Bonicoli --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6925a5c..27e6929b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,13 @@ ## Contributing to xorm -`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very -much welcome. You can help with patch review, submitting bug reports, +`xorm` has a backlog of [pull requests](https://gitea.com/xorm/xorm/pulls), but contributions are still very +much welcome. You can help with patch review, submitting [bug reports](https://gitea.com/xorm/xorm/issues), or adding new functionality. There is no formal style guide, but please conform to the style of existing code and general Go formatting conventions when submitting patches. -* [fork a repo](https://help.github.com/articles/fork-a-repo) -* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request) +* [fork the repo](https://gitea.com/repo/fork/2038) +* [creating a pull request ](https://docs.gitea.io/en-us/pull-request/) ### Language @@ -15,7 +15,7 @@ Since `xorm` is a world-wide open source project, please describe your issues or ### Sign your codes with comments ``` -// !! your comments +// !! your comments e.g., @@ -65,7 +65,7 @@ And if your branch is related with cache, you could also enable it via `TEST_CAC ### Patch review -Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or +Help review existing open [pull requests](https://gitea.com/xorm/xorm/pulls) by commenting on the code or proposed functionality. ### Bug reports