From a18e35f7f5bd105bd39eceb0079a4f2b278444b3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 19 Jan 2020 09:36:06 +0000 Subject: [PATCH 1/7] SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 --- session_insert.go | 94 +++++++++++++++--------------------------- session_insert_test.go | 58 ++++++++++++++++++++++++++ session_update.go | 10 ++++- session_update_test.go | 45 ++++++++++++++++++++ statement_exprparam.go | 10 ++++- 5 files changed, 153 insertions(+), 64 deletions(-) diff --git a/session_insert.go b/session_insert.go index 1e19ce7a..5f8f7e1e 100644 --- a/session_insert.go +++ b/session_insert.go @@ -729,66 +729,7 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err args = append(args, m[colName]) } - w := builder.NewWriter() - if session.statement.cond.IsValid() { - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil { - return 0, err - } - - if _, err := w.WriteString(") SELECT "); err != nil { - return 0, err - } - - if err := session.statement.writeArgs(w, args); err != nil { - return 0, err - } - - if len(exprs.args) > 0 { - if _, err := w.WriteString(","); err != nil { - return 0, err - } - if err := exprs.writeArgs(w); err != nil { - return 0, err - } - } - - if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := session.statement.cond.WriteTo(w); err != nil { - return 0, err - } - } else { - qm := strings.Repeat("?,", len(columns)) - qm = qm[:len(qm)-1] - - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil { - return 0, err - } - w.Append(args...) - } - - sql := w.String() - args = w.Args() - - if err := session.cacheInsert(tableName); err != nil { - return 0, err - } - - res, err := session.exec(sql, args...) - if err != nil { - return 0, err - } - affected, err := res.RowsAffected() - if err != nil { - return 0, err - } - return affected, nil + return session.insertMap(columns, args) } func (session *Session) insertMapString(m map[string]string) (int64, error) { @@ -808,6 +749,7 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { columns = append(columns, k) } } + sort.Strings(columns) var args = make([]interface{}, 0, len(m)) @@ -815,7 +757,18 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { args = append(args, m[colName]) } + return session.insertMap(columns, args) +} + +func (session *Session) insertMap(columns []string, args []interface{}) (int64, error) { + tableName := session.statement.TableName() + if len(tableName) <= 0 { + return 0, ErrTableNotFound + } + + exprs := session.statement.exprColumns w := builder.NewWriter() + // if insert where if session.statement.cond.IsValid() { if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil { return 0, err @@ -853,10 +806,29 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { qm := strings.Repeat("?,", len(columns)) qm = qm[:len(qm)-1] - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil { + if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil { return 0, err } + + if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil { + return 0, err + } + if _, err := w.WriteString(fmt.Sprintf(") VALUES (%s", qm)); err != nil { + return 0, err + } + w.Append(args...) + if len(exprs.args) > 0 { + if _, err := w.WriteString(","); err != nil { + return 0, err + } + if err := exprs.writeArgs(w); err != nil { + return 0, err + } + } + if _, err := w.WriteString(")"); err != nil { + return 0, err + } } sql := w.String() diff --git a/session_insert_test.go b/session_insert_test.go index e6100fdc..657d2b12 100644 --- a/session_insert_test.go +++ b/session_insert_test.go @@ -928,6 +928,64 @@ func TestInsertWhere(t *testing.T) { assert.EqualValues(t, 5, j5.Index) } +func TestInsertExpr2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type InsertExprsRelease struct { + Id int64 + RepoId int + IsTag bool + IsDraft bool + NumCommits int + Sha1 string + } + + assertSync(t, new(InsertExprsRelease)) + + var ie = InsertExprsRelease{ + RepoId: 1, + IsTag: true, + } + inserted, err := testEngine. + SetExpr("is_draft", true). + SetExpr("num_commits", 0). + SetExpr("sha1", ""). + Insert(&ie) + assert.NoError(t, err) + assert.EqualValues(t, 1, inserted) + + var ie2 InsertExprsRelease + has, err := testEngine.ID(ie.Id).Get(&ie2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, true, ie2.IsDraft) + assert.EqualValues(t, "", ie2.Sha1) + assert.EqualValues(t, 0, ie2.NumCommits) + assert.EqualValues(t, 1, ie2.RepoId) + assert.EqualValues(t, true, ie2.IsTag) + + inserted, err = testEngine.Table(new(InsertExprsRelease)). + SetExpr("is_draft", true). + SetExpr("num_commits", 0). + SetExpr("sha1", ""). + Insert(map[string]interface{}{ + "repo_id": 1, + "is_tag": true, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, inserted) + + var ie3 InsertExprsRelease + has, err = testEngine.ID(ie.Id + 1).Get(&ie3) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, true, ie3.IsDraft) + assert.EqualValues(t, "", ie3.Sha1) + assert.EqualValues(t, 0, ie3.NumCommits) + assert.EqualValues(t, 1, ie3.RepoId) + assert.EqualValues(t, true, ie3.IsTag) +} + type NightlyRate struct { ID int64 `xorm:"'id' not null pk BIGINT(20)" json:"id"` } diff --git a/session_update.go b/session_update.go index 231163e0..47ced66d 100644 --- a/session_update.go +++ b/session_update.go @@ -239,14 +239,20 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 for i, colName := range exprColumns.colNames { switch tp := exprColumns.args[i].(type) { case string: - colNames = append(colNames, session.engine.Quote(colName)+" = "+tp) + if len(tp) == 0 { + tp = "''" + } + colNames = append(colNames, session.engine.Quote(colName)+"="+tp) case *builder.Builder: subQuery, subArgs, err := builder.ToSQL(tp) if err != nil { return 0, err } - colNames = append(colNames, session.engine.Quote(colName)+" = ("+subQuery+")") + colNames = append(colNames, session.engine.Quote(colName)+"=("+subQuery+")") args = append(args, subArgs...) + default: + colNames = append(colNames, session.engine.Quote(colName)+"=?") + args = append(args, exprColumns.args[i]) } } diff --git a/session_update_test.go b/session_update_test.go index 386a68d1..d0ecef33 100644 --- a/session_update_test.go +++ b/session_update_test.go @@ -1359,3 +1359,48 @@ func TestUpdateAlias(t *testing.T) { assert.EqualValues(t, 2, ue.NumIssues) assert.EqualValues(t, "lunny xiao", ue.Name) } + +func TestUpdateExprs2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UpdateExprsRelease struct { + Id int64 + RepoId int + IsTag bool + IsDraft bool + NumCommits int + Sha1 string + } + + assertSync(t, new(UpdateExprsRelease)) + + var uer = UpdateExprsRelease{ + RepoId: 1, + IsTag: false, + IsDraft: false, + NumCommits: 1, + Sha1: "sha1", + } + inserted, err := testEngine.Insert(&uer) + assert.NoError(t, err) + assert.EqualValues(t, 1, inserted) + + updated, err := testEngine. + Where("repo_id = ? AND is_tag = ?", 1, false). + SetExpr("is_draft", true). + SetExpr("num_commits", 0). + SetExpr("sha1", ""). + Update(new(UpdateExprsRelease)) + assert.NoError(t, err) + assert.EqualValues(t, 1, updated) + + var uer2 UpdateExprsRelease + has, err := testEngine.ID(uer.Id).Get(&uer2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, 1, uer2.RepoId) + assert.EqualValues(t, false, uer2.IsTag) + assert.EqualValues(t, true, uer2.IsDraft) + assert.EqualValues(t, 0, uer2.NumCommits) + assert.EqualValues(t, "", uer2.Sha1) +} diff --git a/statement_exprparam.go b/statement_exprparam.go index 4da4f1ea..fc62e36f 100644 --- a/statement_exprparam.go +++ b/statement_exprparam.go @@ -69,10 +69,18 @@ func (exprs *exprParams) writeArgs(w *builder.BytesWriter) error { if _, err := w.WriteString(")"); err != nil { return err } - default: + case string: + if arg == "" { + arg = "''" + } if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil { return err } + default: + if _, err := w.WriteString("?"); err != nil { + return err + } + w.Append(arg) } if i != len(exprs.args)-1 { if _, err := w.WriteString(","); err != nil { From c37aff9b3a4a0f614f659c068dde0d62b7eb39bf Mon Sep 17 00:00:00 2001 From: Guillermo Prandi Date: Mon, 20 Jan 2020 02:45:00 +0000 Subject: [PATCH 2/7] Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 --- dialect_postgres.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dialect_postgres.go b/dialect_postgres.go index ccef3086..ac6d4fe8 100644 --- a/dialect_postgres.go +++ b/dialect_postgres.go @@ -901,7 +901,7 @@ func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) { } func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string { - if len(db.Schema) == 0 { + if len(db.Schema) == 0 || strings.Contains(tableName, ".") { return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", tableName, col.Name, db.SqlType(col)) } @@ -913,8 +913,8 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string { quote := db.Quote idxName := index.Name - tableName = strings.Replace(tableName, `"`, "", -1) - tableName = strings.Replace(tableName, `.`, "_", -1) + tableParts := strings.Split(strings.Replace(tableName, `"`, "", -1), ".") + tableName = tableParts[len(tableParts)-1] if !strings.HasPrefix(idxName, "UQE_") && !strings.HasPrefix(idxName, "IDX_") { From bd20ffba3b5c309c7bd9e6db0ccf5a4f705a7408 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Jan 2020 05:24:12 +0000 Subject: [PATCH 3/7] fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 --- interface.go | 2 ++ session_update.go | 20 ++++++++++++-------- session_update_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/interface.go b/interface.go index a564db12..81a4b68a 100644 --- a/interface.go +++ b/interface.go @@ -92,6 +92,7 @@ type EngineInterface interface { Quote(string) string SetCacher(string, core.Cacher) SetConnMaxLifetime(time.Duration) + SetColumnMapper(core.IMapper) SetDefaultCacher(core.Cacher) SetLogger(logger core.ILogger) SetLogLevel(core.LogLevel) @@ -99,6 +100,7 @@ type EngineInterface interface { SetMaxOpenConns(int) SetMaxIdleConns(int) SetSchema(string) + SetTableMapper(core.IMapper) SetTZDatabase(tz *time.Location) SetTZLocation(tz *time.Location) ShowExecTime(...bool) diff --git a/session_update.go b/session_update.go index 47ced66d..22d516e7 100644 --- a/session_update.go +++ b/session_update.go @@ -300,21 +300,25 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 st := &session.statement - var sqlStr string - var condArgs []interface{} - var condSQL string - cond := session.statement.cond.And(autoCond) + var ( + sqlStr string + condArgs []interface{} + condSQL string + cond = session.statement.cond.And(autoCond) - var doIncVer = (table != nil && table.Version != "" && session.statement.checkVersion) - var verValue *reflect.Value + doIncVer = isStruct && (table != nil && table.Version != "" && session.statement.checkVersion) + verValue *reflect.Value + ) if doIncVer { verValue, err = table.VersionColumn().ValueOf(bean) if err != nil { return 0, err } - cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()}) - colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1") + if verValue != nil { + cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()}) + colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1") + } } condSQL, condArgs, err = builder.ToSQL(cond) diff --git a/session_update_test.go b/session_update_test.go index d0ecef33..274a6bfa 100644 --- a/session_update_test.go +++ b/session_update_test.go @@ -1404,3 +1404,45 @@ func TestUpdateExprs2(t *testing.T) { assert.EqualValues(t, 0, uer2.NumCommits) assert.EqualValues(t, "", uer2.Sha1) } + +func TestUpdateMap3(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UpdateMapUser struct { + Id uint64 `xorm:"PK autoincr"` + Name string `xorm:""` + Ver uint64 `xorm:"version"` + } + + oldMapper := testEngine.GetColumnMapper() + defer func() { + testEngine.SetColumnMapper(oldMapper) + }() + + mapper := core.NewPrefixMapper(core.SnakeMapper{}, "F") + testEngine.SetColumnMapper(mapper) + + assertSync(t, new(UpdateMapUser)) + + _, err := testEngine.Table(new(UpdateMapUser)).Insert(map[string]interface{}{ + "Fname": "first user name", + "Fver": 1, + }) + assert.NoError(t, err) + + update := map[string]interface{}{ + "Fname": "user name", + "Fver": 1, + } + rows, err := testEngine.Table(new(UpdateMapUser)).ID(1).Update(update) + assert.NoError(t, err) + assert.EqualValues(t, 1, rows) + + update = map[string]interface{}{ + "Name": "user name", + "Ver": 1, + } + rows, err = testEngine.Table(new(UpdateMapUser)).ID(1).Update(update) + assert.Error(t, err) + assert.EqualValues(t, 0, rows) +} From 14a0c19a0c92de6c3c65d6ba9f7251b3aaf77ae7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Jan 2020 05:28:07 +0000 Subject: [PATCH 4/7] fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 --- session_iterate.go | 27 +++++++++++++++------------ session_iterate_test.go | 11 +++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/session_iterate.go b/session_iterate.go index ca996c28..a1642bb3 100644 --- a/session_iterate.go +++ b/session_iterate.go @@ -4,7 +4,9 @@ package xorm -import "reflect" +import ( + "reflect" +) // IterFunc only use by Iterate type IterFunc func(idx int, bean interface{}) error @@ -60,10 +62,6 @@ func (session *Session) BufferSize(size int) *Session { } func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { - if session.isAutoClose { - defer session.Close() - } - var bufferSize = session.statement.bufferSize var limit = session.statement.LimitN if limit > 0 && bufferSize > limit { @@ -73,9 +71,14 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { v := rValue(bean) sliceType := reflect.SliceOf(v.Type()) var idx = 0 - for { + session.autoResetStatement = false + defer func() { + session.autoResetStatement = true + }() + + for bufferSize > 0 { slice := reflect.New(sliceType) - if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil { + if err := session.NoCache().Limit(bufferSize, start).find(slice.Interface(), bean); err != nil { return err } @@ -86,13 +89,13 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { idx++ } - start = start + slice.Elem().Len() - if limit > 0 && idx+bufferSize > limit { - bufferSize = limit - idx + if bufferSize > slice.Elem().Len() { + break } - if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit { - break + start = start + slice.Elem().Len() + if limit > 0 && start+bufferSize > limit { + bufferSize = limit - start } } diff --git a/session_iterate_test.go b/session_iterate_test.go index 9a7ec25f..bb0c59c4 100644 --- a/session_iterate_test.go +++ b/session_iterate_test.go @@ -89,4 +89,15 @@ func TestBufferIterate(t *testing.T) { }) assert.NoError(t, err) assert.EqualValues(t, 7, cnt) + + cnt = 0 + err = testEngine.Where("id <= 10").BufferSize(2).Iterate(new(UserBufferIterate), func(i int, bean interface{}) error { + user := bean.(*UserBufferIterate) + assert.EqualValues(t, cnt+1, user.Id) + assert.EqualValues(t, true, user.IsMan) + cnt++ + return nil + }) + assert.NoError(t, err) + assert.EqualValues(t, 10, cnt) } From 6dfe337869d9e6cf5be8b39b441207ef6472cb6c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Jan 2020 08:22:06 +0000 Subject: [PATCH 5/7] fix statement.LimitN(0) will delete or update all data (#1119) fix test fix nil pointer fix statement.Limit(0) will update or delete all data fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve ci tests (#1477) Rewrite Engine.QuoteTo() to accept multi-part identifiers (#1476) Support local sql log (#1338) Fix go mod and update version (#1460) Move github.com/go-xorm/xorm to xorm.io/xorm (#1459) add support custom type Nullfloat64 (#1450) fix bug when query map condtion with no quote (#1449) Don't warn when bool column default is 1 but not true (#1447) * don't warn when bool column default is 1 but not true * fix default case sensitive Fix sync2 with custom table name (#1445) * fix sync2 with custom table name * fix bug on postgres * fix bug on postgres fix bug when update with setexpr (#1446) add tidb tests on drone ci (#1444) improve sync2 (#1443) Fix wrong dbmetas (#1442) * add tests for db metas * add more tests * fix bug on mssql Fix default value parse bugs (#1437) * fix default value * fix default value tags * fix postgres default * fix default on postgres * fix default on postgres * fix mssql default fix arg conversion (#1441) * fix arg conversion * fix bugs * fix bug on postgres * use traditional positional parameters on insert into select * remove unnecessary tests upgrade core (#1440) add tests (#1439) add go1.13 tests on drone (#1416) Fix bug on insert where (#1436) * fix bug on insert where * fix bug * fix lint fix bug when insert multiple slices with customize table name (#1433) * fix bug when insert multiple slices with customize table name * fix tests on mssql * fix tests fix insert where with bool bug on mssql (#1432) fix setexpr missing big quotes (#1431) * fix setexpr missing big quotes * fix tests * fix tests Add support subquery on SetExpr (#1428) * add support subquery on SetExpr * fix tests fix go mod (#1427) fix tests (#1429) Use strings.Builder instead of builder.StringBuilder (#1417) * use strings.Builder instead of builder.StringBuilder * fix dependency * fix dependency Remove unuse get cols code (#1413) Add mssql ci test (#1410) * add mssql ci test * fix drone test Add insert select where support (#1401) Use drone new format (#1388) * use drone new format fix get customize type bug (#1382) fix bugs (#1375) update drone (#1374) Add tests for get var (#1305) * add test for SQL get * fix tests fix error when get null var (#890) * fix error when get null var * add support get for null var * fix bug Remove quotestr totally (#1366) * remove QuoteStr() totally * update xorm.core -> v0.7.0 * update dialect Quote remove QuoteStr() usage in dialects (#1364) document of FindAndCount() (#1365) remove QuoteStr() usage (#1360) Co-authored-by: yifhao Co-authored-by: yifhao <1124210681@qq.com> Co-authored-by: Guillermo Prandi Co-authored-by: Guillermo Prandi Co-authored-by: yudppp Co-authored-by: BetaCat Reviewed-on: https://gitea.com/xorm/xorm/pulls/1119 --- session_delete.go | 12 +++++++----- session_iterate.go | 10 +++++----- session_update.go | 13 +++++++------ statement.go | 31 +++++++++++++++++++------------ tag_id_test.go | 4 ++-- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/session_delete.go b/session_delete.go index 675d4d8c..7b0a0641 100644 --- a/session_delete.go +++ b/session_delete.go @@ -101,7 +101,8 @@ func (session *Session) Delete(bean interface{}) (int64, error) { if err != nil { return 0, err } - if len(condSQL) == 0 && session.statement.LimitN == 0 { + pLimitN := session.statement.LimitN + if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) { return 0, ErrNeedDeletedCond } @@ -119,8 +120,9 @@ func (session *Session) Delete(bean interface{}) (int64, error) { if len(session.statement.OrderStr) > 0 { orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr) } - if session.statement.LimitN > 0 { - orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN) + if pLimitN != nil && *pLimitN > 0 { + limitNValue := *pLimitN + orderSQL += fmt.Sprintf(" LIMIT %d", limitNValue) } if len(orderSQL) > 0 { @@ -139,7 +141,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) { } else { deleteSQL += " WHERE " + inSQL } - // TODO: how to handle delete limit on mssql? + // TODO: how to handle delete limit on mssql? case core.MSSQL: return 0, ErrNotImplemented default: @@ -180,7 +182,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) { } else { realSQL += " WHERE " + inSQL } - // TODO: how to handle delete limit on mssql? + // TODO: how to handle delete limit on mssql? case core.MSSQL: return 0, ErrNotImplemented default: diff --git a/session_iterate.go b/session_iterate.go index a1642bb3..4a3cc083 100644 --- a/session_iterate.go +++ b/session_iterate.go @@ -63,9 +63,9 @@ func (session *Session) BufferSize(size int) *Session { func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { var bufferSize = session.statement.bufferSize - var limit = session.statement.LimitN - if limit > 0 && bufferSize > limit { - bufferSize = limit + var pLimitN = session.statement.LimitN + if pLimitN != nil && bufferSize > *pLimitN { + bufferSize = *pLimitN } var start = session.statement.Start v := rValue(bean) @@ -94,8 +94,8 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { } start = start + slice.Elem().Len() - if limit > 0 && start+bufferSize > limit { - bufferSize = limit - start + if pLimitN != nil && start+bufferSize > *pLimitN { + bufferSize = *pLimitN - start } } diff --git a/session_update.go b/session_update.go index 22d516e7..a26b15a6 100644 --- a/session_update.go +++ b/session_update.go @@ -337,11 +337,12 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 var tableName = session.statement.TableName() // TODO: Oracle support needed var top string - if st.LimitN > 0 { + if st.LimitN != nil { + limitValue := *st.LimitN if st.Engine.dialect.DBType() == core.MYSQL { - condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + condSQL = condSQL + fmt.Sprintf(" LIMIT %d", limitValue) } else if st.Engine.dialect.DBType() == core.SQLITE { - tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue) cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", session.engine.Quote(tableName), tempCondSQL), condArgs...)) condSQL, condArgs, err = builder.ToSQL(cond) @@ -352,7 +353,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 condSQL = "WHERE " + condSQL } } else if st.Engine.dialect.DBType() == core.POSTGRES { - tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue) cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", session.engine.Quote(tableName), tempCondSQL), condArgs...)) condSQL, condArgs, err = builder.ToSQL(cond) @@ -367,7 +368,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 if st.OrderStr != "" && st.Engine.dialect.DBType() == core.MSSQL && table != nil && len(table.PrimaryKeys) == 1 { cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)", - table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0], + table.PrimaryKeys[0], limitValue, table.PrimaryKeys[0], session.engine.Quote(tableName), condSQL), condArgs...) condSQL, condArgs, err = builder.ToSQL(cond) @@ -378,7 +379,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 condSQL = "WHERE " + condSQL } } else { - top = fmt.Sprintf("TOP (%d) ", st.LimitN) + top = fmt.Sprintf("TOP (%d) ", limitValue) } } } diff --git a/statement.go b/statement.go index 67e35213..dc251d30 100644 --- a/statement.go +++ b/statement.go @@ -20,7 +20,7 @@ type Statement struct { RefTable *core.Table Engine *Engine Start int - LimitN int + LimitN *int idParam *core.PK OrderStr string JoinStr string @@ -65,7 +65,7 @@ type Statement struct { func (statement *Statement) Init() { statement.RefTable = nil statement.Start = 0 - statement.LimitN = 0 + statement.LimitN = nil statement.OrderStr = "" statement.UseCascade = true statement.JoinStr = "" @@ -671,7 +671,7 @@ func (statement *Statement) Top(limit int) *Statement { // Limit generate LIMIT start, limit statement func (statement *Statement) Limit(limit int, start ...int) *Statement { - statement.LimitN = limit + statement.LimitN = &limit if len(start) > 0 { statement.Start = start[0] } @@ -1071,9 +1071,11 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr) } + pLimitN := statement.LimitN if dialect.DBType() == core.MSSQL { - if statement.LimitN > 0 { - top = fmt.Sprintf("TOP %d ", statement.LimitN) + if pLimitN != nil { + LimitNValue := *pLimitN + top = fmt.Sprintf("TOP %d ", LimitNValue) } if statement.Start > 0 { var column string @@ -1134,12 +1136,16 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n if needLimit { if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE { if statement.Start > 0 { - fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start) - } else if statement.LimitN > 0 { - fmt.Fprint(&buf, " LIMIT ", statement.LimitN) + if pLimitN != nil { + fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", *pLimitN, statement.Start) + } else { + fmt.Fprintf(&buf, "LIMIT 0 OFFSET %v", statement.Start) + } + } else if pLimitN != nil { + fmt.Fprint(&buf, " LIMIT ", *pLimitN) } } else if dialect.DBType() == core.ORACLE { - if statement.Start != 0 || statement.LimitN != 0 { + if statement.Start != 0 || pLimitN != nil { oldString := buf.String() buf.Reset() rawColStr := columnStr @@ -1147,7 +1153,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n rawColStr = "at.*" } fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", - columnStr, rawColStr, oldString, statement.Start+statement.LimitN, statement.Start) + columnStr, rawColStr, oldString, statement.Start+*pLimitN, statement.Start) } } } @@ -1204,8 +1210,9 @@ func (statement *Statement) convertIDSQL(sqlStr string) string { } var top string - if statement.LimitN > 0 && statement.Engine.dialect.DBType() == core.MSSQL { - top = fmt.Sprintf("TOP %d ", statement.LimitN) + pLimitN := statement.LimitN + if pLimitN != nil && statement.Engine.dialect.DBType() == core.MSSQL { + top = fmt.Sprintf("TOP %d ", *pLimitN) } newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1]) diff --git a/tag_id_test.go b/tag_id_test.go index f1c5a6bc..dce5f688 100644 --- a/tag_id_test.go +++ b/tag_id_test.go @@ -7,8 +7,8 @@ package xorm import ( "testing" - "xorm.io/core" "github.com/stretchr/testify/assert" + "xorm.io/core" ) type IDGonicMapper struct { @@ -76,7 +76,7 @@ func TestSameMapperID(t *testing.T) { for _, tb := range tables { if tb.Name == "IDSameMapper" { if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "ID" { - t.Fatal(tb) + t.Fatalf("tb %s tb.PKColumns() is %d not 1, tb.PKColumns()[0].Name is %s not ID", tb.Name, len(tb.PKColumns()), tb.PKColumns()[0].Name) } return } From 43b364ccfd3ec5cd6935a69db9fcb23b2a27e7c6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Jan 2020 08:23:54 +0000 Subject: [PATCH 6/7] Allow update created field if indicated on Cols (#1513) Allow update created field if indicated on Cols Reviewed-on: https://gitea.com/xorm/xorm/pulls/1513 --- statement.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statement.go b/statement.go index dc251d30..ea3ecabe 100644 --- a/statement.go +++ b/statement.go @@ -247,7 +247,7 @@ func (statement *Statement) buildUpdates(bean interface{}, if !includeVersion && col.IsVersion { continue } - if col.IsCreated { + if col.IsCreated && !columnMap.contain(col.Name) { continue } if !includeUpdated && col.IsUpdated { From 062d9960b227d77e6c21b7ff79a9b46b199cb94d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Jan 2020 08:25:21 +0000 Subject: [PATCH 7/7] For nullable columns, store nil values as NULL (#531) Merge branch 'master' into jcsalem/fix/nil_ptr_is_nullable fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 For nullable columns, store nil values as NULL fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve ci tests (#1477) Rewrite Engine.QuoteTo() to accept multi-part identifiers (#1476) Support local sql log (#1338) Fix go mod and update version (#1460) Move github.com/go-xorm/xorm to xorm.io/xorm (#1459) add support custom type Nullfloat64 (#1450) fix bug when query map condtion with no quote (#1449) Don't warn when bool column default is 1 but not true (#1447) * don't warn when bool column default is 1 but not true * fix default case sensitive Fix sync2 with custom table name (#1445) * fix sync2 with custom table name * fix bug on postgres * fix bug on postgres fix bug when update with setexpr (#1446) add tidb tests on drone ci (#1444) improve sync2 (#1443) Fix wrong dbmetas (#1442) * add tests for db metas * add more tests * fix bug on mssql Fix default value parse bugs (#1437) * fix default value * fix default value tags * fix postgres default * fix default on postgres * fix default on postgres * fix mssql default fix arg conversion (#1441) * fix arg conversion * fix bugs * fix bug on postgres * use traditional positional parameters on insert into select * remove unnecessary tests upgrade core (#1440) add tests (#1439) add go1.13 tests on drone (#1416) Fix bug on insert where (#1436) * fix bug on insert where * fix bug * fix lint fix bug when insert multiple slices with customize table name (#1433) * fix bug when insert multiple slices with customize table name * fix tests on mssql * fix tests fix insert where with bool bug on mssql (#1432) fix setexpr missing big quotes (#1431) * fix setexpr missing big quotes * fix tests * fix tests Add support subquery on SetExpr (#1428) * add support subquery on SetExpr * fix tests fix go mod (#1427) fix tests (#1429) Use strings.Builder instead of builder.StringBuilder (#1417) * use strings.Builder instead of builder.StringBuilder * fix dependency * fix dependency Remove unuse get cols code (#1413) Add mssql ci test (#1410) * add mssql ci test * fix drone test Add insert select where support (#1401) Use drone new format (#1388) * use drone new format fix get customize type bug (#1382) fix bugs (#1375) update drone (#1374) Add tests for get var (#1305) * add test for SQL get * fix tests fix error when get null var (#890) * fix error when get null var * add support get for null var * fix bug Remove quotestr totally (#1366) * remove QuoteStr() totally * update xorm.core -> v0.7.0 * update dialect Quote remove QuoteStr() usage in dialects (#1364) document of FindAndCount() (#1365) remove QuoteStr() usage (#1360) make sure timeout in context timeout t... Co-authored-by: Guillermo Prandi Co-authored-by: Jim Salem Co-authored-by: Guillermo Prandi Co-authored-by: yudppp Co-authored-by: BetaCat Reviewed-on: https://gitea.com/xorm/xorm/pulls/531 --- helpers.go | 11 +++++++++++ session_insert.go | 2 +- session_update.go | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/helpers.go b/helpers.go index a31e922c..aadeb6dc 100644 --- a/helpers.go +++ b/helpers.go @@ -155,6 +155,17 @@ func isZero(k interface{}) bool { return false } +func isZeroValue(v reflect.Value) bool { + if isZero(v.Interface()) { + return true + } + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + func isStructZero(v reflect.Value) bool { if !v.IsValid() { return true diff --git a/session_insert.go b/session_insert.go index 5f8f7e1e..c9859b7a 100644 --- a/session_insert.go +++ b/session_insert.go @@ -674,7 +674,7 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac // !evalphobia! set fieldValue as nil when column is nullable and zero-value if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok { - if col.Nullable && isZero(fieldValue.Interface()) { + if col.Nullable && isZeroValue(fieldValue) { var nilValue *int fieldValue = reflect.ValueOf(nilValue) } diff --git a/session_update.go b/session_update.go index a26b15a6..18425ec3 100644 --- a/session_update.go +++ b/session_update.go @@ -517,7 +517,7 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac // !evalphobia! set fieldValue as nil when column is nullable and zero-value if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok { - if col.Nullable && isZero(fieldValue.Interface()) { + if col.Nullable && isZeroValue(fieldValue) { var nilValue *int fieldValue = reflect.ValueOf(nilValue) }