Merge branch 'master' into lunny/fix_oracle_time

This commit is contained in:
Lunny Xiao 2022-03-31 14:28:56 +08:00
commit e88a207b51
89 changed files with 3618 additions and 1418 deletions

View File

@ -73,7 +73,7 @@ steps:
TEST_MYSQL_PASSWORD:
commands:
- make test-mysql
- TEST_QUOTE_POLICY=reserved make test-mysql
- TEST_QUOTE_POLICY=reserved make test-mysql-tls
volumes:
- name: cache
@ -363,6 +363,41 @@ services:
commands:
- /cockroach/cockroach start --insecure
# ---
# kind: pipeline
# name: test-dameng
# depends_on:
# - test-cockroach
# trigger:
# ref:
# - refs/heads/master
# - refs/pull/*/head
# steps:
# - name: test-dameng
# pull: never
# image: golang:1.15
# volumes:
# - name: cache
# path: /go/pkg/mod
# environment:
# TEST_DAMENG_HOST: "dameng:5236"
# TEST_DAMENG_USERNAME: SYSDBA
# TEST_DAMENG_PASSWORD: SYSDBA
# commands:
# - sleep 30
# - make test-dameng
# volumes:
# - name: cache
# host:
# path: /tmp/cache
# services:
# - name: dameng
# image: lunny/dm:v1.0
# commands:
# - /bin/bash /startDm.sh
---
kind: pipeline
name: merge_coverage
@ -374,6 +409,7 @@ depends_on:
- test-mssql
- test-tidb
- test-cockroach
#- test-dameng
trigger:
ref:
- refs/heads/master

24
.golangci.yml Normal file
View File

@ -0,0 +1,24 @@
linters:
enable:
- gosimple
- deadcode
- typecheck
- govet
- errcheck
- staticcheck
- unused
- structcheck
- varcheck
- dupl
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
- bidichk
- ineffassign
enable-all: false
disable-all: true
fast: false
run:
timeout: 3m

View File

@ -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"], []]

View File

@ -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
```
// !<you github id>! your comments
// !<your gitea.com id>! 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

View File

@ -43,6 +43,10 @@ TEST_TIDB_DBNAME ?= xorm_test
TEST_TIDB_USERNAME ?= root
TEST_TIDB_PASSWORD ?=
TEST_DAMENG_HOST ?= dameng:5236
TEST_DAMENG_USERNAME ?= SYSDBA
TEST_DAMENG_PASSWORD ?= SYSDBA
TEST_CACHE_ENABLE ?= false
TEST_QUOTE_POLICY ?= always
@ -94,8 +98,7 @@ help:
@echo " - build creates the entire project"
@echo " - clean delete integration files and build files but not css and js files"
@echo " - fmt format the code"
@echo " - lint run code linter revive"
@echo " - misspell check if a word is written wrong"
@echo " - lint run code linter"
@echo " - test run default unit test"
@echo " - test-cockroach run integration tests for cockroach"
@echo " - test-mysql run integration tests for mysql"
@ -107,28 +110,25 @@ help:
@echo " - vet examines Go source code and reports suspicious constructs"
.PHONY: lint
lint: revive
lint: golangci-lint
.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: golangci-lint
golangci-lint: golangci-lint-check
golangci-lint run --timeout 10m
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
.PHONY: golangci-lint-check
golangci-lint-check:
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
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); \
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
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
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
@ -186,6 +186,18 @@ test-mysql\#%: go-check
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
.PNONY: test-mysql-tls
test-mysql-tls: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)&tls=skip-verify" \
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic -timeout=20m
.PHONY: test-mysql-tls\#%
test-mysql-tls\#%: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)&tls=skip-verify" \
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
.PNONY: test-postgres
test-postgres: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
@ -240,7 +252,6 @@ test-sqlite\#%: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite -conn_str="./test.db?cache=shared&mode=rwc" \
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
.PNONY: test-tidb
test-tidb: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
@ -253,6 +264,18 @@ test-tidb\#%: go-check
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
-quote=$(TEST_QUOTE_POLICY) -coverprofile=tidb.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
.PNONY: test-dameng
test-dameng: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=dm -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
-conn_str="dm://$(TEST_DAMENG_USERNAME):$(TEST_DAMENG_PASSWORD)@$(TEST_DAMENG_HOST)" \
-coverprofile=dameng.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic -timeout=20m
.PHONY: test-dameng\#%
test-dameng\#%: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=dm -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
-conn_str="dm://$(TEST_DAMENG_USERNAME):$(TEST_DAMENG_PASSWORD)@$(TEST_DAMENG_HOST)" \
-coverprofile=dameng.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic -timeout=20m
.PHONY: vet
vet:
$(GO) vet $(shell $(GO) list ./...)

View File

@ -74,7 +74,7 @@ Firstly, we should new an engine for a database.
engine, err := xorm.NewEngine(driverName, dataSourceName)
```
* Define a struct and Sync2 table struct to database
* Define a struct and Sync table struct to database
```Go
type User struct {
@ -87,7 +87,7 @@ type User struct {
Updated time.Time `xorm:"updated"`
}
err := engine.Sync2(new(User))
err := engine.Sync(new(User))
```
* Create Engine Group
@ -141,6 +141,24 @@ affected, err := engine.Insert(&users)
affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
affected, err := engine.Table("user").Insert(map[string]interface{}{
"name": "lunny",
"age": 18,
})
// INSERT INTO user (name, age) values (?,?)
affected, err := engine.Table("user").Insert([]map[string]interface{}{
{
"name": "lunny",
"age": 18,
},
{
"name": "lunny2",
"age": 19,
},
})
// INSERT INTO user (name, age) values (?,?),(?,?)
```
* `Get` query one record from database
@ -161,6 +179,11 @@ has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ?
var id int64
var name string
has, err := engine.Table(&user).Cols("id", "name").Get(&id, &name)
// SELECT id, name FROM user LIMIT 1
var valuesMap = make(map[string]string)
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
@ -234,7 +257,11 @@ err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean inter
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
```
You can use rows which is similiar with `sql.Rows`
```Go
rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
@ -244,6 +271,19 @@ for rows.Next() {
}
```
or
```Go
rows, err := engine.Cols("name", "age").Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
for rows.Next() {
var name string
var age int
err = rows.Scan(&name, &age)
}
```
* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
```Go

View File

@ -84,7 +84,7 @@ type User struct {
Updated time.Time `xorm:"updated"`
}
err := engine.Sync2(new(User))
err := engine.Sync(new(User))
```
* 创建Engine组
@ -138,6 +138,24 @@ affected, err := engine.Insert(&users)
affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
affected, err := engine.Table("user").Insert(map[string]interface{}{
"name": "lunny",
"age": 18,
})
// INSERT INTO user (name, age) values (?,?)
affected, err := engine.Table("user").Insert([]map[string]interface{}{
{
"name": "lunny",
"age": 18,
},
{
"name": "lunny2",
"age": 19,
},
})
// INSERT INTO user (name, age) values (?,?),(?,?)
```
* `Get` 查询单条记录
@ -158,6 +176,11 @@ has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ?
var id int64
var name string
has, err := engine.Table(&user).Cols("id", "name").Get(&id, &name)
// SELECT id, name FROM user LIMIT 1
var valuesMap = make(map[string]string)
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
@ -209,7 +232,7 @@ type UserDetail struct {
}
var users []UserDetail
err := engine.Table("user").Select("user.*, detail.*")
err := engine.Table("user").Select("user.*, detail.*").
Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0).
Find(&users)
@ -231,7 +254,11 @@ err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean inter
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
```
Rows 的用法类似 `sql.Rows`
```Go
rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
@ -241,6 +268,19 @@ for rows.Next() {
}
```
或者
```Go
rows, err := engine.Cols("name", "age").Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
for rows.Next() {
var name string
var age int
err = rows.Scan(&name, &age)
}
```
* `Update` 更新数据除非使用Cols,AllCols函数指明默认只更新非空和非0的字段
```Go

View File

@ -16,19 +16,19 @@ import (
// Md5 return md5 hash string
func Md5(str string) string {
m := md5.New()
io.WriteString(m, str)
_, _ = io.WriteString(m, str)
return fmt.Sprintf("%x", m.Sum(nil))
}
// Encode Encode data
func Encode(data interface{}) ([]byte, error) {
//return JsonEncode(data)
// return JsonEncode(data)
return GobEncode(data)
}
// Decode decode data
func Decode(data []byte, to interface{}) error {
//return JsonDecode(data, to)
// return JsonDecode(data, to)
return GobDecode(data, to)
}

View File

@ -56,7 +56,7 @@ func (m *LRUCacher) GC() {
var removedNum int
for e := m.idList.Front(); e != nil; {
if removedNum <= CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
time.Since(e.Value.(*idNode).lastVisit) > m.Expired {
removedNum++
next := e.Next()
node := e.Value.(*idNode)
@ -70,7 +70,7 @@ func (m *LRUCacher) GC() {
removedNum = 0
for e := m.sqlList.Front(); e != nil; {
if removedNum <= CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
time.Since(e.Value.(*sqlNode).lastVisit) > m.Expired {
removedNum++
next := e.Next()
node := e.Value.(*sqlNode)
@ -96,7 +96,7 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
} else {
lastTime := el.Value.(*sqlNode).lastVisit
// if expired, remove the node and return nil
if time.Now().Sub(lastTime) > m.Expired {
if time.Since(lastTime) > m.Expired {
m.delIds(tableName, sql)
return nil
}
@ -122,7 +122,7 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
if el, ok := m.idIndex[tableName][id]; ok {
lastTime := el.Value.(*idNode).lastVisit
// if expired, remove the node and return nil
if time.Now().Sub(lastTime) > m.Expired {
if time.Since(lastTime) > m.Expired {
m.delBean(tableName, id)
return nil
}
@ -145,7 +145,7 @@ func (m *LRUCacher) clearIds(tableName string) {
if tis, ok := m.sqlIndex[tableName]; ok {
for sql, v := range tis {
m.sqlList.Remove(v)
m.store.Del(sql)
_ = m.store.Del(sql)
}
}
m.sqlIndex[tableName] = make(map[string]*list.Element)
@ -163,7 +163,7 @@ func (m *LRUCacher) clearBeans(tableName string) {
for id, v := range tis {
m.idList.Remove(v)
tid := genID(tableName, id)
m.store.Del(tid)
_ = m.store.Del(tid)
}
}
m.idIndex[tableName] = make(map[string]*list.Element)
@ -188,7 +188,7 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
} else {
el.Value.(*sqlNode).lastVisit = time.Now()
}
m.store.Put(sql, ids)
_ = m.store.Put(sql, ids)
if m.sqlList.Len() > m.MaxElementSize {
e := m.sqlList.Front()
node := e.Value.(*sqlNode)
@ -210,7 +210,7 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
el.Value.(*idNode).lastVisit = time.Now()
}
m.store.Put(genID(tableName, id), obj)
_ = m.store.Put(genID(tableName, id), obj)
if m.idList.Len() > m.MaxElementSize {
e := m.idList.Front()
node := e.Value.(*idNode)
@ -226,7 +226,7 @@ func (m *LRUCacher) delIds(tableName, sql string) {
m.sqlList.Remove(el)
}
}
m.store.Del(sql)
_ = m.store.Del(sql)
}
// DelIds deletes ids
@ -243,7 +243,7 @@ func (m *LRUCacher) delBean(tableName string, id string) {
m.idList.Remove(el)
m.clearIds(tableName)
}
m.store.Del(tid)
_ = m.store.Del(tid)
}
// DelBean deletes beans in some table
@ -265,10 +265,6 @@ type sqlNode struct {
lastVisit time.Time
}
func genSQLKey(sql string, args interface{}) string {
return fmt.Sprintf("%s-%v", sql, args)
}
func genID(prefix string, id string) string {
return fmt.Sprintf("%s-%s", prefix, id)
}

View File

@ -36,7 +36,7 @@ func (c *ContextHook) End(ctx context.Context, result sql.Result, err error) {
c.Ctx = ctx
c.Result = result
c.Err = err
c.ExecuteTime = time.Now().Sub(c.start)
c.ExecuteTime = time.Since(c.start)
}
// Hook represents a hook behaviour

View File

@ -283,11 +283,9 @@ func Assign(dest, src interface{}, originalLocation *time.Location, convertedLoc
}
}
var sv reflect.Value
switch d := dest.(type) {
case *string:
sv = reflect.ValueOf(src)
var sv = reflect.ValueOf(src)
switch sv.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,

View File

@ -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 {

View File

@ -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),

View File

@ -136,7 +136,7 @@ func (db *DB) reflectNew(typ reflect.Type) reflect.Value {
cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
db.reflectCache[typ] = cs
} else {
cs.idx = cs.idx + 1
cs.idx++
}
return cs.value.Index(cs.idx).Addr()
}

View File

@ -96,7 +96,7 @@ func BenchmarkOriQuery(b *testing.B) {
if err != nil {
b.Error(err)
}
//fmt.Println(Id, Name, Title, Age, Alias, NickName)
// fmt.Println(Id, Name, Title, Age, Alias, NickName)
}
rows.Close()
}
@ -245,13 +245,13 @@ func BenchmarkSliceInterfaceQuery(b *testing.B) {
b.Error(err)
}
b.Log(slice)
switch slice[1].(type) {
switch st := slice[1].(type) {
case *string:
if *slice[1].(*string) != "xlw" {
if *st != "xlw" {
b.Error(errors.New("name should be xlw"))
}
case []byte:
if string(slice[1].([]byte)) != "xlw" {
if string(st) != "xlw" {
b.Error(errors.New("name should be xlw"))
}
}
@ -399,14 +399,14 @@ func BenchmarkMapInterfaceQuery(b *testing.B) {
if err != nil {
b.Error(err)
}
switch m["name"].(type) {
switch t := m["name"].(type) {
case string:
if m["name"].(string) != "xlw" {
if t != "xlw" {
b.Log(m)
b.Error(errors.New("name should be xlw"))
}
case []byte:
if string(m["name"].([]byte)) != "xlw" {
if string(t) != "xlw" {
b.Log(m)
b.Error(errors.New("name should be xlw"))
}

View File

@ -62,7 +62,7 @@ func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
for _, vvv := range vvvs {
for j := 0; j < vvv.NumField(); j++ {
newDest[i] = vvv.Field(j).Addr().Interface()
i = i + 1
i++
}
}

View File

@ -93,7 +93,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result
if err != nil {
return nil, err
}
res, err := s.Stmt.ExecContext(ctx, args)
res, err := s.Stmt.ExecContext(ctx, args...)
hookCtx.End(ctx, res, err)
if err := s.db.afterProcess(hookCtx); err != nil {
return nil, err

1201
dialects/dameng.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -38,11 +38,23 @@ func (uri *URI) SetSchema(schema string) {
}
}
// enumerates all autoincr mode
const (
IncrAutoincrMode = iota
SequenceAutoincrMode
)
// DialectFeatures represents a dialect parameters
type DialectFeatures struct {
AutoincrMode int // 0 autoincrement column, 1 sequence
}
// Dialect represents a kind of database
type Dialect interface {
Init(*URI) error
URI() *URI
Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error)
Features() *DialectFeatures
SQLType(*schemas.Column) string
Alias(string) string // return what a sql type's alias of
@ -61,9 +73,13 @@ type Dialect interface {
GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error)
IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error)
CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool)
CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error)
DropTableSQL(tableName string) (string, bool)
CreateSequenceSQL(ctx context.Context, queryer core.Queryer, seqName string) (string, error)
IsSequenceExist(ctx context.Context, queryer core.Queryer, seqName string) (bool, error)
DropSequenceSQL(seqName string) (string, error)
GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error)
IsColumnExist(queryer core.Queryer, ctx context.Context, tableName string, colName string) (bool, error)
AddColumnSQL(tableName string, col *schemas.Column) string
@ -103,6 +119,59 @@ func (db *Base) URI() *URI {
return db.uri
}
// CreateTableSQL implements Dialect
func (db *Base) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
if tableName == "" {
tableName = table.Name
}
quoter := db.dialect.Quoter()
var b strings.Builder
b.WriteString("CREATE TABLE IF NOT EXISTS ")
if err := quoter.QuoteTo(&b, tableName); err != nil {
return "", false, err
}
b.WriteString(" (")
for i, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1)
b.WriteString(s)
if i != len(table.ColumnsSeq())-1 {
b.WriteString(", ")
}
}
if len(table.PrimaryKeys) > 1 {
b.WriteString(", PRIMARY KEY (")
b.WriteString(quoter.Join(table.PrimaryKeys, ","))
b.WriteString(")")
}
b.WriteString(")")
return b.String(), false, nil
}
func (db *Base) CreateSequenceSQL(ctx context.Context, queryer core.Queryer, seqName string) (string, error) {
return fmt.Sprintf(`CREATE SEQUENCE %s
minvalue 1
nomaxvalue
start with 1
increment by 1
nocycle
nocache`, seqName), nil
}
func (db *Base) IsSequenceExist(ctx context.Context, queryer core.Queryer, seqName string) (bool, error) {
return false, fmt.Errorf("unsupported sequence feature")
}
func (db *Base) DropSequenceSQL(seqName string) (string, error) {
return fmt.Sprintf("DROP SEQUENCE %s", seqName), nil
}
// DropTableSQL returns drop table SQL
func (db *Base) DropTableSQL(tableName string) (string, bool) {
quote := db.dialect.Quoter().Quote
@ -141,7 +210,7 @@ func (db *Base) IsColumnExist(queryer core.Queryer, ctx context.Context, tableNa
// AddColumnSQL returns a SQL to add a column
func (db *Base) AddColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, true)
return fmt.Sprintf("ALTER TABLE %v ADD %v", db.dialect.Quoter().Quote(tableName), s)
return fmt.Sprintf("ALTER TABLE %s ADD %s", db.dialect.Quoter().Quote(tableName), s)
}
// CreateIndexSQL returns a SQL to create index
@ -173,7 +242,7 @@ func (db *Base) DropIndexSQL(tableName string, index *schemas.Index) string {
// ModifyColumnSQL returns a SQL to modify SQL
func (db *Base) ModifyColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, false)
return fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s", tableName, s)
return fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s", db.quoter.Quote(tableName), s)
}
// ForUpdateSQL returns for updateSQL
@ -252,43 +321,41 @@ func ColumnString(dialect Dialect, col *schemas.Column, includePrimaryKey bool)
return "", err
}
if err := bd.WriteByte(' '); err != nil {
return "", err
}
if includePrimaryKey && col.IsPrimaryKey {
if _, err := bd.WriteString("PRIMARY KEY "); err != nil {
if _, err := bd.WriteString(" PRIMARY KEY"); err != nil {
return "", err
}
if col.IsAutoIncrement {
if _, err := bd.WriteString(dialect.AutoIncrStr()); err != nil {
return "", err
}
if err := bd.WriteByte(' '); err != nil {
return "", err
}
if _, err := bd.WriteString(dialect.AutoIncrStr()); err != nil {
return "", err
}
}
}
if col.Default != "" {
if _, err := bd.WriteString("DEFAULT "); err != nil {
if !col.DefaultIsEmpty {
if _, err := bd.WriteString(" DEFAULT "); err != nil {
return "", err
}
if _, err := bd.WriteString(col.Default); err != nil {
return "", err
}
if err := bd.WriteByte(' '); err != nil {
return "", err
if col.Default == "" {
if _, err := bd.WriteString("''"); err != nil {
return "", err
}
} else {
if _, err := bd.WriteString(col.Default); err != nil {
return "", err
}
}
}
if col.Nullable {
if _, err := bd.WriteString("NULL "); err != nil {
if _, err := bd.WriteString(" NULL"); err != nil {
return "", err
}
} else {
if _, err := bd.WriteString("NOT NULL "); err != nil {
if _, err := bd.WriteString(" NOT NULL"); err != nil {
return "", err
}
}

View File

@ -282,6 +282,12 @@ func (db *mssql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Ve
}, nil
}
func (db *mssql) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *mssql) SQLType(c *schemas.Column) string {
var res string
switch t := c.SQLType.Name; t {
@ -423,7 +429,7 @@ func (db *mssql) DropTableSQL(tableName string) (string, bool) {
func (db *mssql) ModifyColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, false)
return fmt.Sprintf("ALTER TABLE %s ALTER COLUMN %s", tableName, s)
return fmt.Sprintf("ALTER TABLE %s ALTER COLUMN %s", db.quoter.Quote(tableName), s)
}
func (db *mssql) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
@ -625,35 +631,38 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
return indexes, nil
}
func (db *mssql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
var sql string
func (db *mssql) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
if tableName == "" {
tableName = table.Name
}
sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
quoter := db.dialect.Quoter()
var b strings.Builder
b.WriteString("IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '")
quoter.QuoteTo(&b, tableName)
b.WriteString("' ) CREATE TABLE ")
quoter.QuoteTo(&b, tableName)
b.WriteString(" (")
sql += db.Quoter().Quote(tableName) + " ("
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
for i, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
sql += s
sql = strings.TrimSpace(sql)
sql += ", "
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1)
b.WriteString(s)
if i != len(table.ColumnsSeq())-1 {
b.WriteString(", ")
}
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += strings.Join(pkList, ",")
sql += " ), "
if len(table.PrimaryKeys) > 1 {
b.WriteString(", PRIMARY KEY (")
b.WriteString(quoter.Join(table.PrimaryKeys, ","))
b.WriteString(")")
}
sql = sql[:len(sql)-2] + ")"
sql += ";"
return []string{sql}, true
b.WriteString(")")
return b.String(), true, nil
}
func (db *mssql) ForUpdateSQL(query string) string {

View File

@ -6,7 +6,6 @@ package dialects
import (
"context"
"crypto/tls"
"database/sql"
"errors"
"fmt"
@ -172,16 +171,7 @@ var (
type mysql struct {
Base
net string
addr string
params map[string]string
loc *time.Location
timeout time.Duration
tls *tls.Config
allowAllFiles bool
allowOldPasswords bool
clientFoundRows bool
rowFormat string
rowFormat string
}
func (db *mysql) Init(uri *URI) error {
@ -244,6 +234,12 @@ func (db *mysql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Ve
}, nil
}
func (db *mysql) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *mysql) SetParams(params map[string]string) {
rowFormat, ok := params["rowFormat"]
if ok {
@ -491,15 +487,15 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
if _, ok := schemas.SqlTypes[colType]; ok {
col.SQLType = schemas.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
} else {
return nil, nil, fmt.Errorf("Unknown colType %v", colType)
return nil, nil, fmt.Errorf("unknown colType %v", colType)
}
if colKey == "PRI" {
col.IsPrimaryKey = true
}
if colKey == "UNI" {
// col.is
}
// if colKey == "UNI" {
// col.is
// }
if extra == "auto_increment" {
col.IsAutoIncrement = true
@ -625,43 +621,44 @@ func (db *mysql) GetIndexes(queryer core.Queryer, ctx context.Context, tableName
return indexes, nil
}
func (db *mysql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
var sql = "CREATE TABLE IF NOT EXISTS "
func (db *mysql) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
if tableName == "" {
tableName = table.Name
}
quoter := db.Quoter()
quoter := db.dialect.Quoter()
var b strings.Builder
b.WriteString("CREATE TABLE IF NOT EXISTS ")
quoter.QuoteTo(&b, tableName)
b.WriteString(" (")
sql += quoter.Quote(tableName)
sql += " ("
for i, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1)
b.WriteString(s)
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
sql += s
sql = strings.TrimSpace(sql)
if len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ", "
if len(col.Comment) > 0 {
b.WriteString(" COMMENT '")
b.WriteString(col.Comment)
b.WriteString("'")
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += quoter.Join(pkList, ",")
sql += " ), "
if i != len(table.ColumnsSeq())-1 {
b.WriteString(", ")
}
sql = sql[:len(sql)-2]
}
sql += ")"
if len(table.PrimaryKeys) > 1 {
b.WriteString(", PRIMARY KEY (")
b.WriteString(quoter.Join(table.PrimaryKeys, ","))
b.WriteString(")")
}
b.WriteString(")")
if table.StoreEngine != "" {
sql += " ENGINE=" + table.StoreEngine
b.WriteString(" ENGINE=")
b.WriteString(table.StoreEngine)
}
var charset = table.Charset
@ -669,13 +666,22 @@ func (db *mysql) CreateTableSQL(table *schemas.Table, tableName string) ([]strin
charset = db.URI().Charset
}
if len(charset) != 0 {
sql += " DEFAULT CHARSET " + charset
b.WriteString(" DEFAULT CHARSET ")
b.WriteString(charset)
}
if db.rowFormat != "" {
sql += " ROW_FORMAT=" + db.rowFormat
b.WriteString(" ROW_FORMAT=")
b.WriteString(db.rowFormat)
}
return []string{sql}, true
if table.Comment != "" {
b.WriteString(" COMMENT='")
b.WriteString(table.Comment)
b.WriteString("'")
}
return b.String(), true, nil
}
func (db *mysql) Filters() []Filter {
@ -769,7 +775,7 @@ func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*URI, error) {
// Parse protocol part of URI
p := strings.SplitN(pd[0], ":", 2)
if len(p) != 2 {
return nil, errors.New("Wrong protocol part of URI")
return nil, errors.New("wrong protocol part of URI")
}
uri.Proto = p[0]
options := strings.Split(p[1], ",")
@ -792,7 +798,7 @@ func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*URI, error) {
}
uri.Timeout = to
default:
return nil, errors.New("Unknown option: " + k)
return nil, errors.New("unknown option: " + k)
}
}
// Remove protocol part

View File

@ -539,6 +539,12 @@ func (db *oracle) Version(ctx context.Context, queryer core.Queryer) (*schemas.V
}, nil
}
func (db *oracle) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: SequenceAutoincrMode,
}
}
func (db *oracle) SQLType(c *schemas.Column) string {
var res string
switch t := c.SQLType.Name; t {
@ -599,7 +605,7 @@ func (db *oracle) DropTableSQL(tableName string) (string, bool) {
return fmt.Sprintf("DROP TABLE `%s`", tableName), false
}
func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
func (db *oracle) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
var sql = "CREATE TABLE "
if tableName == "" {
tableName = table.Name
@ -629,7 +635,7 @@ func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]stri
}
sql = sql[:len(sql)-2] + ")"
return []string{sql}, false
return sql, false, nil
}
func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) {

View File

@ -941,6 +941,12 @@ func (db *postgres) SQLType(c *schemas.Column) string {
return res
}
func (db *postgres) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *postgres) ColumnTypeKind(t string) int {
switch strings.ToUpper(t) {
case "DATETIME", "TIMESTAMP":
@ -965,41 +971,6 @@ func (db *postgres) AutoIncrStr() string {
return ""
}
func (db *postgres) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
quoter := db.Quoter()
sql += quoter.Quote(tableName)
sql += " ("
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
sql += s
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += quoter.Join(pkList, ",")
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
return []string{sql}, true
}
func (db *postgres) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
if len(db.getSchema()) == 0 {
args := []interface{}{tableName, idxName}
@ -1020,13 +991,37 @@ func (db *postgres) IsTableExist(queryer core.Queryer, ctx context.Context, tabl
db.getSchema(), tableName)
}
func (db *postgres) ModifyColumnSQL(tableName string, col *schemas.Column) string {
func (db *postgres) AddColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, true)
quoter := db.dialect.Quoter()
addColumnSQL := ""
commentSQL := "; "
if len(db.getSchema()) == 0 || strings.Contains(tableName, ".") {
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
tableName, col.Name, db.SQLType(col))
addColumnSQL = fmt.Sprintf("ALTER TABLE %s ADD %s", quoter.Quote(tableName), s)
commentSQL += fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'", quoter.Quote(tableName), quoter.Quote(col.Name), col.Comment)
return addColumnSQL + commentSQL
}
return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
db.getSchema(), tableName, col.Name, db.SQLType(col))
addColumnSQL = fmt.Sprintf("ALTER TABLE %s.%s ADD %s", quoter.Quote(db.getSchema()), quoter.Quote(tableName), s)
commentSQL += fmt.Sprintf("COMMENT ON COLUMN %s.%s.%s IS '%s'", quoter.Quote(db.getSchema()), quoter.Quote(tableName), quoter.Quote(col.Name), col.Comment)
return addColumnSQL + commentSQL
}
func (db *postgres) ModifyColumnSQL(tableName string, col *schemas.Column) string {
quoter := db.dialect.Quoter()
modifyColumnSQL := ""
commentSQL := "; "
if len(db.getSchema()) == 0 || strings.Contains(tableName, ".") {
modifyColumnSQL = fmt.Sprintf("ALTER TABLE %s ALTER COLUMN %s TYPE %s", quoter.Quote(tableName), quoter.Quote(col.Name), db.SQLType(col))
commentSQL += fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'", quoter.Quote(tableName), quoter.Quote(col.Name), col.Comment)
return modifyColumnSQL + commentSQL
}
modifyColumnSQL = fmt.Sprintf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s", quoter.Quote(db.getSchema()), quoter.Quote(tableName), quoter.Quote(col.Name), db.SQLType(col))
commentSQL += fmt.Sprintf("COMMENT ON COLUMN %s.%s.%s IS '%s'", quoter.Quote(db.getSchema()), quoter.Quote(tableName), quoter.Quote(col.Name), col.Comment)
return modifyColumnSQL + commentSQL
}
func (db *postgres) DropIndexSQL(tableName string, index *schemas.Index) string {
@ -1211,9 +1206,7 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
col.Default = "'" + col.Default + "'"
}
} else if col.SQLType.IsTime() {
if strings.HasSuffix(col.Default, "::timestamp without time zone") {
col.Default = strings.TrimSuffix(col.Default, "::timestamp without time zone")
}
col.Default = strings.TrimSuffix(col.Default, "::timestamp without time zone")
}
}
cols[col.Name] = col
@ -1274,7 +1267,7 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN
s := "SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1"
if len(db.getSchema()) != 0 {
args = append(args, db.getSchema())
s = s + " AND schemaname=$2"
s += " AND schemaname=$2"
}
rows, err := queryer.QueryContext(ctx, s, args...)
@ -1307,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):]
@ -1331,6 +1337,26 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN
return indexes, nil
}
func (db *postgres) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
quoter := db.dialect.Quoter()
if len(db.getSchema()) != 0 && !strings.Contains(tableName, ".") {
tableName = fmt.Sprintf("%s.%s", db.getSchema(), tableName)
}
createTableSQL, ok, err := db.Base.CreateTableSQL(ctx, queryer, table, tableName)
if err != nil {
return "", ok, err
}
commentSQL := "; "
if table.Comment != "" {
// support schema.table -> "schema"."table"
commentSQL += fmt.Sprintf("COMMENT ON TABLE %s IS '%s'", quoter.Quote(tableName), table.Comment)
}
return createTableSQL + commentSQL, true, nil
}
func (db *postgres) Filters() []Filter {
return []Filter{&SeqFilter{Prefix: "$", Start: 1}}
}

View File

@ -184,6 +184,12 @@ func (db *sqlite3) Version(ctx context.Context, queryer core.Queryer) (*schemas.
}, nil
}
func (db *sqlite3) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) {
switch quotePolicy {
case QuotePolicyNone:
@ -285,41 +291,6 @@ func (db *sqlite3) DropIndexSQL(tableName string, index *schemas.Index) string {
return fmt.Sprintf("DROP INDEX %v", db.Quoter().Quote(idxName))
}
func (db *sqlite3) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
quoter := db.Quoter()
sql += quoter.Quote(tableName)
sql += " ("
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
sql += s
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += quoter.Join(pkList, ",")
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
return []string{sql}, true
}
func (db *sqlite3) ForUpdateSQL(query string) string {
return query
}

View File

@ -17,8 +17,7 @@ import (
func TableNameWithSchema(dialect Dialect, tableName string) string {
// Add schema name as prefix of table name.
// Only for postgres database.
if dialect.URI().Schema != "" &&
strings.Index(tableName, ".") == -1 {
if dialect.URI().Schema != "" && !strings.Contains(tableName, ".") {
return fmt.Sprintf("%s.%s", dialect.URI().Schema, tableName)
}
return tableName
@ -27,20 +26,18 @@ func TableNameWithSchema(dialect Dialect, tableName string) string {
// TableNameNoSchema returns table name with given tableName
func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface{}) string {
quote := dialect.Quoter().Quote
switch tableName.(type) {
switch tt := tableName.(type) {
case []string:
t := tableName.([]string)
if len(t) > 1 {
return fmt.Sprintf("%v AS %v", quote(t[0]), quote(t[1]))
} else if len(t) == 1 {
return quote(t[0])
if len(tt) > 1 {
return fmt.Sprintf("%v AS %v", quote(tt[0]), quote(tt[1]))
} else if len(tt) == 1 {
return quote(tt[0])
}
case []interface{}:
t := tableName.([]interface{})
l := len(t)
l := len(tt)
var table string
if l > 0 {
f := t[0]
f := tt[0]
switch f.(type) {
case string:
table = f.(string)
@ -57,7 +54,7 @@ func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface
}
}
if l > 1 {
return fmt.Sprintf("%v AS %v", quote(table), quote(fmt.Sprintf("%v", t[1])))
return fmt.Sprintf("%v AS %v", quote(table), quote(fmt.Sprintf("%v", tt[1])))
} else if l == 1 {
return quote(table)
}

16
doc.go
View File

@ -67,6 +67,11 @@ There are 8 major ORM methods and many helpful methods to use to operate databas
has, err := engine.Table("user").Where("name = ?", name).Get(&id)
// SELECT id FROM user WHERE name = ? LIMIT 1
var id int64
var name string
has, err := engine.Table(&user).Cols("id", "name").Get(&id, &name)
// SELECT id, name FROM user LIMIT 1
3. Query multiple records from database
var sliceOfStructs []Struct
@ -97,6 +102,17 @@ another is Rows
err = rows.Scan(bean)
}
or
rows, err := engine.Cols("name", "age").Rows(...)
// SELECT * FROM user
defer rows.Close()
for rows.Next() {
var name string
var age int
err = rows.Scan(&name, &age)
}
5. Update one or more records
affected, err := engine.ID(...).Update(&user)

395
engine.go
View File

@ -7,12 +7,13 @@ package xorm
import (
"context"
"database/sql"
"errors"
"fmt"
"io"
"os"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"time"
@ -248,11 +249,6 @@ func (engine *Engine) SQLType(c *schemas.Column) string {
return engine.dialect.SQLType(c)
}
// AutoIncrStr Database's autoincrement statement
func (engine *Engine) AutoIncrStr() string {
return engine.dialect.AutoIncrStr()
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.DB().SetConnMaxLifetime(d)
@ -441,23 +437,23 @@ func (engine *Engine) DumpTablesToFile(tables []*schemas.Table, fp string, tp ..
// DumpTables dump specify tables to io.Writer
func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
return engine.dumpTables(tables, w, tp...)
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)
}
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(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
var dstDialect dialects.Dialect
if len(tp) == 0 {
dstDialect = engine.dialect
@ -471,9 +467,14 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
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
}
dstDialect.Init(&destURI)
}
cacherMgr := caches.NewManager()
dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper(), cacherMgr)
@ -484,6 +485,13 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
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 {
@ -494,9 +502,12 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
}
dstTableName := dstTable.Name
var dstTableName = dstTable.Name
var quoter = dstDialect.Quoter().Quote
var quotedDstTableName = quoter(dstTable.Name)
if dstDialect.URI().Schema != "" {
dstTableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, dstTable.Name)
quotedDstTableName = fmt.Sprintf("%s.%s", quoter(dstDialect.URI().Schema), quoter(dstTable.Name))
}
originalTableName := table.Name
if engine.dialect.URI().Schema != "" {
@ -509,13 +520,26 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
}
sqls, _ := dstDialect.CreateTableSQL(dstTable, dstTableName)
for _, s := range sqls {
_, err = io.WriteString(w, s+";\n")
if dstTable.AutoIncrement != "" && dstDialect.Features().AutoincrMode == dialects.SequenceAutoincrMode {
sqlstr, err := dstDialect.CreateSequenceSQL(ctx, engine.db, utils.SeqName(dstTableName))
if err != nil {
return err
}
_, err = io.WriteString(w, sqlstr+";\n")
if err != nil {
return err
}
}
sqlstr, _, err := dstDialect.CreateTableSQL(ctx, engine.db, dstTable, dstTableName)
if err != nil {
return err
}
_, err = io.WriteString(w, sqlstr+";\n")
if err != nil {
return err
}
if len(dstTable.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", dstTable.Name)
}
@ -552,7 +576,7 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
sess := engine.NewSession()
defer sess.Close()
for rows.Next() {
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(dstTableName)+" ("+destColNames+") VALUES (")
_, err = io.WriteString(w, "INSERT INTO "+quotedDstTableName+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
@ -563,36 +587,208 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
for i, scanResult := range scanResults {
stp := schemas.SQLType{Name: types[i].DatabaseTypeName()}
if stp.IsNumeric() {
s := scanResult.(*sql.NullString)
if s.Valid {
if _, err = io.WriteString(w, formatBool(s.String, dstDialect)); err != nil {
return err
}
} else {
if _, err = io.WriteString(w, "NULL"); err != nil {
return err
}
}
} else if stp.IsBool() {
s := scanResult.(*sql.NullString)
if s.Valid {
if _, err = io.WriteString(w, formatBool(s.String, dstDialect)); err != nil {
return err
}
} else {
if _, err = io.WriteString(w, "NULL"); err != nil {
return err
}
s := scanResult.(*sql.NullString)
if !s.Valid {
if _, err = io.WriteString(w, "NULL"); err != nil {
return err
}
} else {
s := scanResult.(*sql.NullString)
if s.Valid {
if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); 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() {
if _, err = io.WriteString(w, s.String); err != nil {
return err
}
} else if sess.engine.dialect.URI().DBType == schemas.DAMENG && stp.IsTime() && len(s.String) == 25 {
r := strings.ReplaceAll(s.String[:19], "T", " ")
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, "NULL"); err != nil {
if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil {
return err
}
}
@ -923,104 +1119,13 @@ func (engine *Engine) UnMapType(t reflect.Type) {
func (engine *Engine) Sync(beans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
for _, bean := range beans {
v := utils.ReflectValue(bean)
tableNameNoSchema := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean)
table, err := engine.tagParser.ParseWithCache(v)
if err != nil {
return err
}
isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
if err != nil {
return err
}
if !isExist {
err = session.createTable(bean)
if err != nil {
return err
}
}
/*isEmpty, err := engine.IsEmptyTable(bean)
if err != nil {
return err
}*/
var isEmpty bool
if isEmpty {
err = session.dropTable(bean)
if err != nil {
return err
}
err = session.createTable(bean)
if err != nil {
return err
}
} else {
for _, col := range table.Columns() {
isExist, err := engine.dialect.IsColumnExist(engine.db, session.ctx, tableNameNoSchema, col.Name)
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
return err
}
err = session.addColumn(col.Name)
if err != nil {
return err
}
}
}
for name, index := range table.Indexes {
if err := session.statement.SetRefBean(bean); err != nil {
return err
}
if index.Type == schemas.UniqueType {
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
return err
}
err = session.addUnique(tableNameNoSchema, name)
if err != nil {
return err
}
}
} else if index.Type == schemas.IndexType {
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
return err
}
err = session.addIndex(tableNameNoSchema, name)
if err != nil {
return err
}
}
} else {
return errors.New("unknow index type")
}
}
}
}
return nil
return session.Sync(beans...)
}
// Sync2 synchronize structs to database tables
// Depricated
func (engine *Engine) Sync2(beans ...interface{}) error {
s := engine.NewSession()
defer s.Close()
return s.Sync2(beans...)
return engine.Sync(beans...)
}
// CreateTables create tabls according bean
@ -1036,7 +1141,7 @@ func (engine *Engine) CreateTables(beans ...interface{}) error {
for _, bean := range beans {
err = session.createTable(bean)
if err != nil {
session.Rollback()
_ = session.Rollback()
return err
}
}
@ -1056,7 +1161,7 @@ func (engine *Engine) DropTables(beans ...interface{}) error {
for _, bean := range beans {
err = session.dropTable(bean)
if err != nil {
session.Rollback()
_ = session.Rollback()
return err
}
}
@ -1133,10 +1238,10 @@ func (engine *Engine) Delete(beans ...interface{}) (int64, error) {
// Get retrieve one record from table, bean's non-empty fields
// are conditions
func (engine *Engine) Get(bean interface{}) (bool, error) {
func (engine *Engine) Get(beans ...interface{}) (bool, error) {
session := engine.NewSession()
defer session.Close()
return session.Get(bean)
return session.Get(beans...)
}
// Exist returns true if the record exist otherwise return false

10
go.mod
View File

@ -3,17 +3,19 @@ module xorm.io/xorm
go 1.13
require (
gitee.com/travelliu/dm v1.8.11192
github.com/denisenkom/go-mssqldb v0.10.0
github.com/go-sql-driver/mysql v1.6.0
github.com/goccy/go-json v0.7.4
github.com/goccy/go-json v0.8.1
github.com/golang/snappy v0.0.4 // indirect
github.com/jackc/pgx/v4 v4.12.0
github.com/json-iterator/go v1.1.11
github.com/json-iterator/go v1.1.12
github.com/lib/pq v1.10.2
github.com/mattn/go-sqlite3 v1.14.8
github.com/mattn/go-sqlite3 v1.14.9
github.com/shopspring/decimal v1.2.0
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.0
github.com/ziutek/mymysql v1.5.4
modernc.org/sqlite v1.11.2
modernc.org/sqlite v1.14.2
xorm.io/builder v0.3.9
)

136
go.sum
View File

@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192 h1:aqJT0xhodZjRutIfEXxKYv0CxqmHUHzsbz6SFaRL6OY=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
@ -76,8 +78,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@ -95,8 +97,10 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -107,6 +111,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@ -203,8 +209,8 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
@ -242,9 +248,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -258,8 +263,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
@ -457,9 +463,10 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -539,34 +546,117 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc=
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/ccgo/v3 v3.9.5 h1:dEuUSf8WN51rDkprFuAqjfchKEzN0WttP/Py3enBwjk=
modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.18 h1:rMZhRcWrba0y3nVmdiQ7kxAgOOSq2m2f2VzjHLgEs6U=
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag=
modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw=
modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ=
modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c=
modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo=
modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg=
modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I=
modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs=
modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8=
modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE=
modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk=
modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w=
modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE=
modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8=
modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc=
modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU=
modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE=
modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk=
modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI=
modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE=
modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg=
modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74=
modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU=
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4=
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
modernc.org/ccgo/v3 v3.12.82 h1:wudcnJyjLj1aQQCXF3IM9Gz2X6UNjw+afIghzdtn0v8=
modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11 h1:QUxZMs48Ahg2F7SN41aERvMfGLY2HU/ADnB9DC4Yts8=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M=
modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU=
modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE=
modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso=
modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8=
modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8=
modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I=
modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk=
modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY=
modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE=
modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg=
modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM=
modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg=
modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo=
modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8=
modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ=
modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA=
modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM=
modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg=
modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE=
modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM=
modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU=
modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
modernc.org/libc v1.11.87 h1:PzIzOqtlzMDDcCzJ5cUP6h/Ku6Fa9iyflP2ccTY64aE=
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.0 h1:GCjoRaBew8ECCKINQA2nYjzvufFW9YiEuuB+rQ9bn2E=
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w=
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE=
modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.5.5 h1:N03RwthgTR/l/eQvz3UjfYnvVVj1G2sZqzFGfoD4HE4=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
modernc.org/tcl v1.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw=
modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao=
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=

View File

@ -26,7 +26,7 @@ func TestCacheFind(t *testing.T) {
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox)))
assert.NoError(t, testEngine.Sync(new(MailBox)))
var inserts = []*MailBox{
{
@ -62,7 +62,8 @@ func TestCacheFind(t *testing.T) {
}
boxes = make([]MailBox, 0, 2)
assert.NoError(t, testEngine.Alias("a").Where("a.id > -1").Asc("a.id").Find(&boxes))
assert.NoError(t, testEngine.Alias("a").Where("`a`.`id`> -1").
Asc("`a`.`id`").Find(&boxes))
assert.EqualValues(t, 2, len(boxes))
for i, box := range boxes {
assert.Equal(t, inserts[i].Id, box.Id)
@ -77,7 +78,8 @@ func TestCacheFind(t *testing.T) {
}
boxes2 := make([]MailBox4, 0, 2)
assert.NoError(t, testEngine.Table("mail_box").Where("mail_box.id > -1").Asc("mail_box.id").Find(&boxes2))
assert.NoError(t, testEngine.Table("mail_box").Where("`mail_box`.`id` > -1").
Asc("mail_box.id").Find(&boxes2))
assert.EqualValues(t, 2, len(boxes2))
for i, box := range boxes2 {
assert.Equal(t, inserts[i].Id, box.Id)
@ -101,7 +103,7 @@ func TestCacheFind2(t *testing.T) {
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox2)))
assert.NoError(t, testEngine.Sync(new(MailBox2)))
var inserts = []*MailBox2{
{
@ -152,7 +154,7 @@ func TestCacheGet(t *testing.T) {
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox3)))
assert.NoError(t, testEngine.Sync(new(MailBox3)))
var inserts = []*MailBox3{
{
@ -164,14 +166,14 @@ func TestCacheGet(t *testing.T) {
assert.NoError(t, err)
var box1 MailBox3
has, err := testEngine.Where("id = ?", inserts[0].Id).Get(&box1)
has, err := testEngine.Where("`id` = ?", inserts[0].Id).Get(&box1)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "user1", box1.Username)
assert.EqualValues(t, "pass1", box1.Password)
var box2 MailBox3
has, err = testEngine.Where("id = ?", inserts[0].Id).Get(&box2)
has, err = testEngine.Where("`id` = ?", inserts[0].Id).Get(&box2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "user1", box2.Username)

View File

@ -0,0 +1,13 @@
// Copyright 2021 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dm
package integrations
import "xorm.io/xorm/schemas"
func init() {
dbtypes = append(dbtypes, schemas.DAMENG)
}

View File

@ -14,6 +14,7 @@ import (
"xorm.io/xorm"
"xorm.io/xorm/schemas"
_ "gitee.com/travelliu/dm"
_ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql"
_ "github.com/jackc/pgx/v4/stdlib"
@ -52,17 +53,18 @@ func TestAutoTransaction(t *testing.T) {
Created time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(TestTx)))
assert.NoError(t, testEngine.Sync(new(TestTx)))
engine := testEngine.(*xorm.Engine)
// will success
engine.Transaction(func(session *xorm.Session) (interface{}, error) {
_, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
_, err := session.Insert(TestTx{Msg: "hi"})
assert.NoError(t, err)
return nil, nil
})
assert.NoError(t, err)
has, err := engine.Exist(&TestTx{Msg: "hi"})
assert.NoError(t, err)
@ -86,7 +88,7 @@ func assertSync(t *testing.T, beans ...interface{}) {
for _, bean := range beans {
t.Run(testEngine.TableName(bean, true), func(t *testing.T) {
assert.NoError(t, testEngine.DropTables(bean))
assert.NoError(t, testEngine.Sync2(bean))
assert.NoError(t, testEngine.Sync(bean))
})
}
}
@ -134,11 +136,14 @@ func TestDump(t *testing.T) {
}
}
var dbtypes = []schemas.DBType{schemas.SQLITE, schemas.MYSQL, schemas.POSTGRES, schemas.MSSQL}
func TestDumpTables(t *testing.T) {
assert.NoError(t, PrepareEngine())
type TestDumpTableStruct struct {
Id int64
Data []byte `xorm:"BLOB"`
Name string
IsMan bool
Created time.Time `xorm:"created"`
@ -146,13 +151,18 @@ func TestDumpTables(t *testing.T) {
assertSync(t, new(TestDumpTableStruct))
testEngine.Insert([]TestDumpTableStruct{
_, 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)
fp := fmt.Sprintf("%v-table.sql", testEngine.Dialect().URI().DBType)
os.Remove(fp)
@ -169,7 +179,7 @@ func TestDumpTables(t *testing.T) {
assert.NoError(t, err)
assert.NoError(t, sess.Commit())
for _, tp := range []schemas.DBType{schemas.SQLITE, schemas.MYSQL, schemas.POSTGRES, schemas.MSSQL} {
for _, tp := range dbtypes {
name := fmt.Sprintf("dump_%v-table.sql", tp)
t.Run(name, func(t *testing.T) {
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, name, tp))

View File

@ -21,7 +21,7 @@ func BenchmarkGetVars(b *testing.B) {
Name string
}
assert.NoError(b, testEngine.Sync2(new(BenchmarkGetVars)))
assert.NoError(b, testEngine.Sync(new(BenchmarkGetVars)))
var v = BenchmarkGetVars{
Name: "myname",
@ -32,7 +32,7 @@ func BenchmarkGetVars(b *testing.B) {
b.StartTimer()
var myname string
for i := 0; i < b.N; i++ {
has, err := testEngine.Cols("name").Table("benchmark_get_vars").Where("id=?", v.Id).Get(&myname)
has, err := testEngine.Cols("name").Table("benchmark_get_vars").Where("`id`=?", v.Id).Get(&myname)
b.StopTimer()
myname = ""
assert.True(b, has)
@ -52,7 +52,7 @@ func BenchmarkGetStruct(b *testing.B) {
Name string
}
assert.NoError(b, testEngine.Sync2(new(BenchmarkGetStruct)))
assert.NoError(b, testEngine.Sync(new(BenchmarkGetStruct)))
var v = BenchmarkGetStruct{
Name: "myname",
@ -84,7 +84,7 @@ func BenchmarkFindStruct(b *testing.B) {
Name string
}
assert.NoError(b, testEngine.Sync2(new(BenchmarkFindStruct)))
assert.NoError(b, testEngine.Sync(new(BenchmarkFindStruct)))
var v = BenchmarkFindStruct{
Name: "myname",
@ -92,8 +92,8 @@ func BenchmarkFindStruct(b *testing.B) {
_, err := testEngine.Insert(&v)
assert.NoError(b, err)
b.StartTimer()
var mynames = make([]BenchmarkFindStruct, 0, 1)
b.StartTimer()
for i := 0; i < b.N; i++ {
err := testEngine.Find(&mynames)
b.StopTimer()

View File

@ -23,7 +23,7 @@ func TestBefore_Get(t *testing.T) {
Val string `xorm:"-"`
}
assert.NoError(t, testEngine.Sync2(new(BeforeTable)))
assert.NoError(t, testEngine.Sync(new(BeforeTable)))
cnt, err := testEngine.Insert(&BeforeTable{
Name: "test",
@ -50,7 +50,7 @@ func TestBefore_Find(t *testing.T) {
Val string `xorm:"-"`
}
assert.NoError(t, testEngine.Sync2(new(BeforeTable2)))
assert.NoError(t, testEngine.Sync(new(BeforeTable2)))
cnt, err := testEngine.Insert([]BeforeTable2{
{Name: "test1"},
@ -104,7 +104,7 @@ func (p *ProcessorsStruct) BeforeDelete() {
}
func (p *ProcessorsStruct) BeforeSet(col string, cell xorm.Cell) {
p.BeforeSetFlag = p.BeforeSetFlag + 1
p.BeforeSetFlag++
}
func (p *ProcessorsStruct) AfterInsert() {
@ -120,7 +120,7 @@ func (p *ProcessorsStruct) AfterDelete() {
}
func (p *ProcessorsStruct) AfterSet(col string, cell xorm.Cell) {
p.AfterSetFlag = p.AfterSetFlag + 1
p.AfterSetFlag++
}
func TestProcessors(t *testing.T) {

View File

@ -18,7 +18,7 @@ func TestRows(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserRows)))
assert.NoError(t, testEngine.Sync(new(UserRows)))
cnt, err := testEngine.Insert(&UserRows{
IsMan: true,
@ -94,7 +94,7 @@ func TestRowsMyTableName(t *testing.T) {
var tableName = "user_rows_my_table_name"
assert.NoError(t, testEngine.Table(tableName).Sync2(new(UserRowsMyTable)))
assert.NoError(t, testEngine.Table(tableName).Sync(new(UserRowsMyTable)))
cnt, err := testEngine.Table(tableName).Insert(&UserRowsMyTable{
IsMan: true,
@ -141,7 +141,7 @@ func (UserRowsSpecTable) TableName() string {
func TestRowsSpecTableName(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(UserRowsSpecTable)))
assert.NoError(t, testEngine.Sync(new(UserRowsSpecTable)))
cnt, err := testEngine.Insert(&UserRowsSpecTable{
IsMan: true,
@ -160,5 +160,49 @@ func TestRowsSpecTableName(t *testing.T) {
assert.NoError(t, err)
cnt++
}
assert.NoError(t, rows.Err())
assert.EqualValues(t, 1, cnt)
}
func TestRowsScanVars(t *testing.T) {
type RowsScanVars struct {
Id int64
Name string
Age int
}
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(RowsScanVars)))
cnt, err := testEngine.Insert(&RowsScanVars{
Name: "xlw",
Age: 42,
}, &RowsScanVars{
Name: "xlw2",
Age: 24,
})
assert.NoError(t, err)
assert.EqualValues(t, 2, cnt)
rows, err := testEngine.Cols("name", "age").Rows(new(RowsScanVars))
assert.NoError(t, err)
defer rows.Close()
cnt = 0
for rows.Next() {
var name string
var age int
err = rows.Scan(&name, &age)
assert.NoError(t, err)
if cnt == 0 {
assert.EqualValues(t, "xlw", name)
assert.EqualValues(t, 42, age)
} else if cnt == 1 {
assert.EqualValues(t, "xlw2", name)
assert.EqualValues(t, 24, age)
}
cnt++
}
assert.NoError(t, rows.Err())
assert.EqualValues(t, 2, cnt)
}

View File

@ -20,7 +20,7 @@ func TestSetExpr(t *testing.T) {
Title string
}
assert.NoError(t, testEngine.Sync2(new(UserExprIssue)))
assert.NoError(t, testEngine.Sync(new(UserExprIssue)))
var issue = UserExprIssue{
Title: "my issue",
@ -36,7 +36,7 @@ func TestSetExpr(t *testing.T) {
Show bool
}
assert.NoError(t, testEngine.Sync2(new(UserExpr)))
assert.NoError(t, testEngine.Sync(new(UserExpr)))
cnt, err = testEngine.Insert(&UserExpr{
Show: true,
@ -45,7 +45,7 @@ func TestSetExpr(t *testing.T) {
assert.EqualValues(t, 1, cnt)
var not = "NOT"
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
if testEngine.Dialect().URI().DBType == schemas.MSSQL || testEngine.Dialect().URI().DBType == schemas.DAMENG {
not = "~"
}
cnt, err = testEngine.SetExpr("show", not+" `show`").ID(1).Update(new(UserExpr))
@ -54,9 +54,9 @@ func TestSetExpr(t *testing.T) {
tableName := testEngine.TableName(new(UserExprIssue), true)
cnt, err = testEngine.SetExpr("issue_id",
builder.Select("id").
From(tableName).
Where(builder.Eq{"id": issue.Id})).
builder.Select("`id`").
From(testEngine.Quote(tableName)).
Where(builder.Eq{"`id`": issue.Id})).
ID(1).
Update(new(UserExpr))
assert.NoError(t, err)

View File

@ -37,49 +37,50 @@ func TestBuilder(t *testing.T) {
assert.NoError(t, err)
var cond Condition
has, err := testEngine.Where(builder.Eq{"col_name": "col1"}).Get(&cond)
var q = testEngine.Quote
has, err := testEngine.Where(builder.Eq{q("col_name"): "col1"}).Get(&cond)
assert.NoError(t, err)
assert.Equal(t, true, has, "records should exist")
has, err = testEngine.Where(builder.Eq{"col_name": "col1"}.
And(builder.Eq{"op": OpEqual})).
has, err = testEngine.Where(builder.Eq{q("col_name"): "col1"}.
And(builder.Eq{q("op"): OpEqual})).
NoAutoCondition().
Get(&cond)
assert.NoError(t, err)
assert.Equal(t, true, has, "records should exist")
has, err = testEngine.Where(builder.Eq{"col_name": "col1", "op": OpEqual, "value": "1"}).
has, err = testEngine.Where(builder.Eq{q("col_name"): "col1", q("op"): OpEqual, q("value"): "1"}).
NoAutoCondition().
Get(&cond)
assert.NoError(t, err)
assert.Equal(t, true, has, "records should exist")
has, err = testEngine.Where(builder.Eq{"col_name": "col1"}.
And(builder.Neq{"op": OpEqual})).
has, err = testEngine.Where(builder.Eq{q("col_name"): "col1"}.
And(builder.Neq{q("op"): OpEqual})).
NoAutoCondition().
Get(&cond)
assert.NoError(t, err)
assert.Equal(t, false, has, "records should not exist")
var conds []Condition
err = testEngine.Where(builder.Eq{"col_name": "col1"}.
And(builder.Eq{"op": OpEqual})).
err = testEngine.Where(builder.Eq{q("col_name"): "col1"}.
And(builder.Eq{q("op"): OpEqual})).
Find(&conds)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(conds), "records should exist")
conds = make([]Condition, 0)
err = testEngine.Where(builder.Like{"col_name", "col"}).Find(&conds)
err = testEngine.Where(builder.Like{q("col_name"), "col"}).Find(&conds)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(conds), "records should exist")
conds = make([]Condition, 0)
err = testEngine.Where(builder.Expr("col_name = ?", "col1")).Find(&conds)
err = testEngine.Where(builder.Expr(q("col_name")+" = ?", "col1")).Find(&conds)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(conds), "records should exist")
conds = make([]Condition, 0)
err = testEngine.Where(builder.In("col_name", "col1", "col2")).Find(&conds)
err = testEngine.Where(builder.In(q("col_name"), "col1", "col2")).Find(&conds)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(conds), "records should exist")
@ -91,8 +92,8 @@ func TestBuilder(t *testing.T) {
// complex condtions
var where = builder.NewCond()
if true {
where = where.And(builder.Eq{"col_name": "col1"})
where = where.Or(builder.And(builder.In("col_name", "col1", "col2"), builder.Expr("col_name = ?", "col1")))
where = where.And(builder.Eq{q("col_name"): "col1"})
where = where.Or(builder.And(builder.In(q("col_name"), "col1", "col2"), builder.Expr(q("col_name")+" = ?", "col1")))
}
conds = make([]Condition, 0)
@ -103,7 +104,7 @@ func TestBuilder(t *testing.T) {
func TestIn(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(Userinfo)))
assert.NoError(t, testEngine.Sync(new(Userinfo)))
cnt, err := testEngine.Insert([]Userinfo{
{
@ -202,7 +203,7 @@ func TestFindAndCount(t *testing.T) {
Name string
}
assert.NoError(t, testEngine.Sync2(new(FindAndCount)))
assert.NoError(t, testEngine.Sync(new(FindAndCount)))
_, err := testEngine.Insert([]FindAndCount{
{
@ -215,7 +216,7 @@ func TestFindAndCount(t *testing.T) {
assert.NoError(t, err)
var results []FindAndCount
sess := testEngine.Where("name = ?", "test1")
sess := testEngine.Where("`name` = ?", "test1")
conds := sess.Conds()
err = sess.Find(&results)
assert.NoError(t, err)

View File

@ -17,7 +17,7 @@ func TestCount(t *testing.T) {
type UserinfoCount struct {
Departname string
}
assert.NoError(t, testEngine.Sync2(new(UserinfoCount)))
assert.NoError(t, testEngine.Sync(new(UserinfoCount)))
colName := testEngine.GetColumnMapper().Obj2Table("Departname")
var cond builder.Cond = builder.Eq{
@ -63,7 +63,7 @@ func TestSQLCount(t *testing.T) {
assertSync(t, new(UserinfoCount2), new(UserinfoBooks))
total, err := testEngine.SQL("SELECT count(id) FROM " + testEngine.TableName("userinfo_count2", true)).
total, err := testEngine.SQL("SELECT count(`id`) FROM " + testEngine.Quote(testEngine.TableName("userinfo_count2", true))).
Count()
assert.NoError(t, err)
assert.EqualValues(t, 0, total)
@ -89,7 +89,7 @@ func TestCountWithOthers(t *testing.T) {
})
assert.NoError(t, err)
total, err := testEngine.OrderBy("id desc").Limit(1).Count(new(CountWithOthers))
total, err := testEngine.OrderBy("`id` desc").Limit(1).Count(new(CountWithOthers))
assert.NoError(t, err)
assert.EqualValues(t, 2, total)
}
@ -118,11 +118,11 @@ func TestWithTableName(t *testing.T) {
})
assert.NoError(t, err)
total, err := testEngine.OrderBy("id desc").Count(new(CountWithTableName))
total, err := testEngine.OrderBy("`id` desc").Count(new(CountWithTableName))
assert.NoError(t, err)
assert.EqualValues(t, 2, total)
total, err = testEngine.OrderBy("id desc").Count(CountWithTableName{})
total, err = testEngine.OrderBy("`id` desc").Count(CountWithTableName{})
assert.NoError(t, err)
assert.EqualValues(t, 2, total)
}
@ -146,7 +146,7 @@ func TestCountWithSelectCols(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 2, total)
total, err = testEngine.Select("count(id)").Count(CountWithTableName{})
total, err = testEngine.Select("count(`id`)").Count(CountWithTableName{})
assert.NoError(t, err)
assert.EqualValues(t, 2, total)
}
@ -166,7 +166,7 @@ func TestCountWithGroupBy(t *testing.T) {
})
assert.NoError(t, err)
cnt, err := testEngine.GroupBy("name").Count(new(CountWithTableName))
cnt, err := testEngine.GroupBy("`name`").Count(new(CountWithTableName))
assert.NoError(t, err)
assert.EqualValues(t, 2, cnt)
}

View File

@ -22,7 +22,7 @@ func TestDelete(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserinfoDelete)))
assert.NoError(t, testEngine.Sync(new(UserinfoDelete)))
session := testEngine.NewSession()
defer session.Close()
@ -213,7 +213,7 @@ func TestUnscopeDelete(t *testing.T) {
cnt, err = testEngine.ID(1).Delete(&s)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.EqualValues(t, nowUnix, s.DeletedAt.Unix())
assert.LessOrEqual(t, int(s.DeletedAt.Unix()-nowUnix), 1)
var s1 UnscopeDeleteStruct
has, err := testEngine.ID(1).Get(&s1)
@ -225,7 +225,7 @@ func TestUnscopeDelete(t *testing.T) {
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "test", s2.Name)
assert.EqualValues(t, nowUnix, s2.DeletedAt.Unix())
assert.LessOrEqual(t, int(s2.DeletedAt.Unix()-nowUnix), 1)
cnt, err = testEngine.ID(1).Unscoped().Delete(new(UnscopeDeleteStruct))
assert.NoError(t, err)
@ -250,7 +250,7 @@ func TestDelete2(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserinfoDelete2)))
assert.NoError(t, testEngine.Sync(new(UserinfoDelete2)))
user := UserinfoDelete2{}
cnt, err := testEngine.Insert(&user)

View File

@ -48,19 +48,19 @@ func TestExistStruct(t *testing.T) {
assert.NoError(t, err)
assert.False(t, has)
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
has, err = testEngine.Where("`name` = ?", "test1").Exist(&RecordExist{})
assert.NoError(t, err)
assert.True(t, has)
has, err = testEngine.Where("name = ?", "test2").Exist(&RecordExist{})
has, err = testEngine.Where("`name` = ?", "test2").Exist(&RecordExist{})
assert.NoError(t, err)
assert.False(t, has)
has, err = testEngine.SQL("select * from "+testEngine.TableName("record_exist", true)+" where name = ?", "test1").Exist()
has, err = testEngine.SQL("select * from "+testEngine.Quote(testEngine.TableName("record_exist", true))+" where `name` = ?", "test1").Exist()
assert.NoError(t, err)
assert.True(t, has)
has, err = testEngine.SQL("select * from "+testEngine.TableName("record_exist", true)+" where name = ?", "test2").Exist()
has, err = testEngine.SQL("select * from "+testEngine.Quote(testEngine.TableName("record_exist", true))+" where `name` = ?", "test2").Exist()
assert.NoError(t, err)
assert.False(t, has)
@ -68,11 +68,11 @@ func TestExistStruct(t *testing.T) {
assert.NoError(t, err)
assert.True(t, has)
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
has, err = testEngine.Table("record_exist").Where("`name` = ?", "test1").Exist()
assert.NoError(t, err)
assert.True(t, has)
has, err = testEngine.Table("record_exist").Where("name = ?", "test2").Exist()
has, err = testEngine.Table("record_exist").Where("`name` = ?", "test2").Exist()
assert.NoError(t, err)
assert.False(t, has)
@ -99,7 +99,7 @@ func TestExistStructForJoin(t *testing.T) {
Name string
}
assert.NoError(t, testEngine.Sync2(new(Number), new(OrderList), new(Player)))
assert.NoError(t, testEngine.Sync(new(Number), new(OrderList), new(Player)))
var ply Player
cnt, err := testEngine.Insert(&ply)
@ -124,43 +124,43 @@ func TestExistStructForJoin(t *testing.T) {
defer session.Close()
session.Table("number").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid").
Where("number.lid = ?", 1)
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("`number`.`lid` = ?", 1)
has, err := session.Exist()
assert.NoError(t, err)
assert.True(t, has)
session.Table("number").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid").
Where("number.lid = ?", 2)
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("`number`.`lid` = ?", 2)
has, err = session.Exist()
assert.NoError(t, err)
assert.False(t, has)
session.Table("number").
Select("order_list.id").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid").
Where("order_list.id = ?", 1)
Select("`order_list`.`id`").
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("`order_list`.`id` = ?", 1)
has, err = session.Exist()
assert.NoError(t, err)
assert.True(t, has)
session.Table("number").
Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid").
Where("player.id = ?", 2)
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("`player`.`id` = ?", 2)
has, err = session.Exist()
assert.NoError(t, err)
assert.False(t, has)
session.Table("number").
Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid")
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`")
has, err = session.Exist()
assert.NoError(t, err)
assert.True(t, has)
@ -174,15 +174,15 @@ func TestExistStructForJoin(t *testing.T) {
session.Table("number").
Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid").
Join("LEFT", "player", "player.id = order_list.eid")
Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`")
has, err = session.Exist()
assert.Error(t, err)
assert.False(t, has)
session.Table("number").
Select("player.id").
Join("LEFT", "player", "player.id = number.lid")
Join("LEFT", "player", "`player`.`id` = `number`.`lid`")
has, err = session.Exist()
assert.NoError(t, err)
assert.True(t, has)

View File

@ -33,7 +33,7 @@ func TestJoinLimit(t *testing.T) {
Name string
}
assert.NoError(t, testEngine.Sync2(new(Salary), new(CheckList), new(Empsetting)))
assert.NoError(t, testEngine.Sync(new(Salary), new(CheckList), new(Empsetting)))
var emp Empsetting
cnt, err := testEngine.Insert(&emp)
@ -56,8 +56,8 @@ func TestJoinLimit(t *testing.T) {
var salaries []Salary
err = testEngine.Table("salary").
Join("INNER", "check_list", "check_list.id = salary.lid").
Join("LEFT", "empsetting", "empsetting.id = check_list.eid").
Join("INNER", "check_list", "`check_list`.`id` = `salary`.`lid`").
Join("LEFT", "empsetting", "`empsetting`.`id` = `check_list`.`eid`").
Limit(10, 0).
Find(&salaries)
assert.NoError(t, err)
@ -69,10 +69,10 @@ func TestWhere(t *testing.T) {
assertSync(t, new(Userinfo))
users := make([]Userinfo, 0)
err := testEngine.Where("id > ?", 2).Find(&users)
err := testEngine.Where("`id` > ?", 2).Find(&users)
assert.NoError(t, err)
err = testEngine.Where("id > ?", 2).And("id < ?", 10).Find(&users)
err = testEngine.Where("`id` > ?", 2).And("`id` < ?", 10).Find(&users)
assert.NoError(t, err)
}
@ -121,54 +121,54 @@ func (TeamUser) TableName() string {
func TestFind3(t *testing.T) {
var teamUser = new(TeamUser)
assert.NoError(t, PrepareEngine())
err := testEngine.Sync2(new(Team), teamUser)
err := testEngine.Sync(new(Team), teamUser)
assert.NoError(t, err)
var teams []Team
err = testEngine.Cols("`team`.id").
Where("`team_user`.org_id=?", 1).
And("`team_user`.uid=?", 2).
Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
err = testEngine.Cols("`team`.`id`").
Where("`team_user`.`org_id`=?", 1).
And("`team_user`.`uid`=?", 2).
Join("INNER", "`team_user`", "`team_user`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
teams = make([]Team, 0)
err = testEngine.Cols("`team`.id").
Where("`team_user`.org_id=?", 1).
And("`team_user`.uid=?", 2).
Join("INNER", teamUser, "`team_user`.team_id=`team`.id").
Where("`team_user`.`org_id`=?", 1).
And("`team_user`.`uid`=?", 2).
Join("INNER", teamUser, "`team_user`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
teams = make([]Team, 0)
err = testEngine.Cols("`team`.id").
Where("`team_user`.org_id=?", 1).
And("`team_user`.uid=?", 2).
Join("INNER", []interface{}{teamUser}, "`team_user`.team_id=`team`.id").
err = testEngine.Cols("`team`.`id`").
Where("`team_user`.`org_id`=?", 1).
And("`team_user`.`uid`=?", 2).
Join("INNER", []interface{}{teamUser}, "`team_user`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
teams = make([]Team, 0)
err = testEngine.Cols("`team`.id").
Where("`tu`.org_id=?", 1).
And("`tu`.uid=?", 2).
Join("INNER", []string{"team_user", "tu"}, "`tu`.team_id=`team`.id").
err = testEngine.Cols("`team`.`id`").
Where("`tu`.`org_id`=?", 1).
And("`tu`.`uid`=?", 2).
Join("INNER", []string{"team_user", "tu"}, "`tu`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
teams = make([]Team, 0)
err = testEngine.Cols("`team`.id").
Where("`tu`.org_id=?", 1).
And("`tu`.uid=?", 2).
Join("INNER", []interface{}{"team_user", "tu"}, "`tu`.team_id=`team`.id").
err = testEngine.Cols("`team`.`id`").
Where("`tu`.`org_id`=?", 1).
And("`tu`.`uid`=?", 2).
Join("INNER", []interface{}{"team_user", "tu"}, "`tu`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
teams = make([]Team, 0)
err = testEngine.Cols("`team`.id").
Where("`tu`.org_id=?", 1).
And("`tu`.uid=?", 2).
Join("INNER", []interface{}{teamUser, "tu"}, "`tu`.team_id=`team`.id").
err = testEngine.Cols("`team`.`id`").
Where("`tu`.`org_id`=?", 1).
And("`tu`.`uid`=?", 2).
Join("INNER", []interface{}{teamUser, "tu"}, "`tu`.`team_id`=`team`.`id`").
Find(&teams)
assert.NoError(t, err)
}
@ -241,7 +241,7 @@ func TestOrder(t *testing.T) {
assertSync(t, new(Userinfo))
users := make([]Userinfo, 0)
err := testEngine.OrderBy("id desc").Find(&users)
err := testEngine.OrderBy("`id` desc").Find(&users)
assert.NoError(t, err)
users2 := make([]Userinfo, 0)
@ -254,7 +254,7 @@ func TestGroupBy(t *testing.T) {
assertSync(t, new(Userinfo))
users := make([]Userinfo, 0)
err := testEngine.GroupBy("id, username").Find(&users)
err := testEngine.GroupBy("`id`, `username`").Find(&users)
assert.NoError(t, err)
}
@ -263,7 +263,7 @@ func TestHaving(t *testing.T) {
assertSync(t, new(Userinfo))
users := make([]Userinfo, 0)
err := testEngine.GroupBy("username").Having("username='xlw'").Find(&users)
err := testEngine.GroupBy("`username`").Having("`username`='xlw'").Find(&users)
assert.NoError(t, err)
}
@ -499,7 +499,7 @@ func TestFindAndCountOneFunc(t *testing.T) {
assert.EqualValues(t, 2, cnt)
results = make([]FindAndCountStruct, 0, 1)
cnt, err = testEngine.Where("msg = ?", true).FindAndCount(&results)
cnt, err = testEngine.Where("`msg` = ?", true).FindAndCount(&results)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
assert.EqualValues(t, 1, cnt)
@ -549,21 +549,21 @@ func TestFindAndCountOneFunc(t *testing.T) {
}, results[0])
results = make([]FindAndCountStruct, 0, 1)
cnt, err = testEngine.Where("msg = ?", true).Select("id, content, msg").
cnt, err = testEngine.Where("`msg` = ?", true).Select("`id`, `content`, `msg`").
Limit(1).FindAndCount(&results)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
assert.EqualValues(t, 1, cnt)
results = make([]FindAndCountStruct, 0, 1)
cnt, err = testEngine.Where("msg = ?", true).Cols("id", "content", "msg").
cnt, err = testEngine.Where("`msg` = ?", true).Cols("id", "content", "msg").
Limit(1).FindAndCount(&results)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
assert.EqualValues(t, 1, cnt)
results = make([]FindAndCountStruct, 0, 1)
cnt, err = testEngine.Where("msg = ?", true).Desc("id").
cnt, err = testEngine.Where("`msg` = ?", true).Desc("id").
Limit(1).Cols("content").FindAndCount(&results)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
@ -649,7 +649,7 @@ func TestFindAndCount2(t *testing.T) {
cnt, err = testEngine.
Table(new(TestFindAndCountHotel)).
Alias("t").
Where("t.region like '6501%'").
Where("`t`.`region` like '6501%'").
Limit(10, 0).
FindAndCount(&hotels)
assert.NoError(t, err)
@ -690,7 +690,7 @@ func TestFindAndCountWithGroupBy(t *testing.T) {
Name string
}
assert.NoError(t, testEngine.Sync2(new(FindAndCountWithGroupBy)))
assert.NoError(t, testEngine.Sync(new(FindAndCountWithGroupBy)))
_, err := testEngine.Insert([]FindAndCountWithGroupBy{
{
@ -705,7 +705,37 @@ func TestFindAndCountWithGroupBy(t *testing.T) {
assert.NoError(t, err)
var results []FindAndCountWithGroupBy
cnt, err := testEngine.GroupBy("age").FindAndCount(&results)
cnt, err := testEngine.GroupBy("`age`").FindAndCount(&results)
assert.NoError(t, err)
assert.EqualValues(t, 2, cnt)
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))
@ -735,14 +765,14 @@ func TestFindMapStringId(t *testing.T) {
deviceMaps := make(map[string]*FindMapDevice, len(deviceIDs))
err = testEngine.
Where("status = ?", 1).
Where("`status` = ?", 1).
In("deviceid", deviceIDs).
Find(&deviceMaps)
assert.NoError(t, err)
deviceMaps2 := make(map[string]FindMapDevice, len(deviceIDs))
err = testEngine.
Where("status = ?", 1).
Where("`status` = ?", 1).
In("deviceid", deviceIDs).
Find(&deviceMaps2)
assert.NoError(t, err)
@ -919,17 +949,17 @@ func TestFindJoin(t *testing.T) {
assertSync(t, new(SceneItem), new(DeviceUserPrivrels), new(Order))
var scenes []SceneItem
err := testEngine.Join("LEFT OUTER", "device_user_privrels", "device_user_privrels.device_id=scene_item.device_id").
Where("scene_item.type=?", 3).Or("device_user_privrels.user_id=?", 339).Find(&scenes)
err := testEngine.Join("LEFT OUTER", "device_user_privrels", "`device_user_privrels`.`device_id`=`scene_item`.`device_id`").
Where("`scene_item`.`type`=?", 3).Or("`device_user_privrels`.`user_id`=?", 339).Find(&scenes)
assert.NoError(t, err)
scenes = make([]SceneItem, 0)
err = testEngine.Join("LEFT OUTER", new(DeviceUserPrivrels), "device_user_privrels.device_id=scene_item.device_id").
Where("scene_item.type=?", 3).Or("device_user_privrels.user_id=?", 339).Find(&scenes)
err = testEngine.Join("LEFT OUTER", new(DeviceUserPrivrels), "`device_user_privrels`.`device_id`=`scene_item`.`device_id`").
Where("`scene_item`.`type`=?", 3).Or("`device_user_privrels`.`user_id`=?", 339).Find(&scenes)
assert.NoError(t, err)
scenes = make([]SceneItem, 0)
err = testEngine.Join("INNER", "order", "`scene_item`.device_id=`order`.id").Find(&scenes)
err = testEngine.Join("INNER", "order", "`scene_item`.`device_id`=`order`.`id`").Find(&scenes)
assert.NoError(t, err)
}
@ -949,7 +979,7 @@ func TestJoinFindLimit(t *testing.T) {
assertSync(t, new(JoinFindLimit1), new(JoinFindLimit2))
var finds []JoinFindLimit1
err := testEngine.Join("INNER", new(JoinFindLimit2), "join_find_limit2.eid=join_find_limit1.id").
err := testEngine.Join("INNER", new(JoinFindLimit2), "`join_find_limit2`.`eid`=`join_find_limit1`.`id`").
Limit(10, 10).Find(&finds)
assert.NoError(t, err)
}
@ -981,9 +1011,9 @@ func TestMoreExtends(t *testing.T) {
assertSync(t, new(MoreExtendsUsers), new(MoreExtendsBooks))
var books []MoreExtendsBooksExtend
err := testEngine.Table("more_extends_books").Select("more_extends_books.*, more_extends_users.*").
Join("INNER", "more_extends_users", "more_extends_books.user_id = more_extends_users.id").
Where("more_extends_books.name LIKE ?", "abc").
err := testEngine.Table("more_extends_books").Select("`more_extends_books`.*, `more_extends_users`.*").
Join("INNER", "more_extends_users", "`more_extends_books`.`user_id` = `more_extends_users`.`id`").
Where("`more_extends_books`.`name` LIKE ?", "abc").
Limit(10, 10).
Find(&books)
assert.NoError(t, err)
@ -991,9 +1021,9 @@ func TestMoreExtends(t *testing.T) {
books = make([]MoreExtendsBooksExtend, 0, len(books))
err = testEngine.Table("more_extends_books").
Alias("m").
Select("m.*, more_extends_users.*").
Join("INNER", "more_extends_users", "m.user_id = more_extends_users.id").
Where("m.name LIKE ?", "abc").
Select("`m`.*, `more_extends_users`.*").
Join("INNER", "more_extends_users", "`m`.`user_id` = `more_extends_users`.`id`").
Where("`m`.`name` LIKE ?", "abc").
Limit(10, 10).
Find(&books)
assert.NoError(t, err)
@ -1038,11 +1068,11 @@ func TestUpdateFind(t *testing.T) {
}
_, err := session.Insert(&tuf)
assert.NoError(t, err)
_, err = session.Where("id = ?", tuf.Id).Update(&TestUpdateFind{})
_, err = session.Where("`id` = ?", tuf.Id).Update(&TestUpdateFind{})
assert.EqualError(t, xorm.ErrNoColumnsTobeUpdated, err.Error())
var tufs []TestUpdateFind
err = session.Where("id = ?", tuf.Id).Find(&tufs)
err = session.Where("`id` = ?", tuf.Id).Find(&tufs)
assert.NoError(t, err)
}

View File

@ -15,6 +15,7 @@ import (
"xorm.io/xorm"
"xorm.io/xorm/contexts"
"xorm.io/xorm/convert"
"xorm.io/xorm/dialects"
"xorm.io/xorm/schemas"
"github.com/shopspring/decimal"
@ -32,7 +33,7 @@ func TestGetVar(t *testing.T) {
Created time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(GetVar)))
assert.NoError(t, testEngine.Sync(new(GetVar)))
var data = GetVar{
Msg: "hi",
@ -55,15 +56,15 @@ func TestGetVar(t *testing.T) {
assert.Equal(t, 28, age)
var ageMax int
has, err = testEngine.SQL("SELECT max(age) FROM "+testEngine.TableName("get_var", true)+" WHERE `id` = ?", data.Id).Get(&ageMax)
has, err = testEngine.SQL("SELECT max(`age`) FROM "+testEngine.Quote(testEngine.TableName("get_var", true))+" WHERE `id` = ?", data.Id).Get(&ageMax)
assert.NoError(t, err)
assert.Equal(t, true, has)
assert.Equal(t, 28, ageMax)
var age2 int64
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age2)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -77,8 +78,8 @@ func TestGetVar(t *testing.T) {
var age4 int16
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age4)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -86,8 +87,8 @@ func TestGetVar(t *testing.T) {
var age5 int32
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age5)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -101,8 +102,8 @@ func TestGetVar(t *testing.T) {
var age7 int64
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age7)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -116,8 +117,8 @@ func TestGetVar(t *testing.T) {
var age9 int16
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age9)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -125,8 +126,8 @@ func TestGetVar(t *testing.T) {
var age10 int32
has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20).
And("age < ?", 30).
Where("`age` > ?", 20).
And("`age` < ?", 30).
Get(&age10)
assert.NoError(t, err)
assert.Equal(t, true, has)
@ -161,16 +162,16 @@ func TestGetVar(t *testing.T) {
var money2 float64
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
has, err = testEngine.SQL("SELECT TOP 1 money FROM " + testEngine.TableName("get_var", true)).Get(&money2)
has, err = testEngine.SQL("SELECT TOP 1 `money` FROM " + testEngine.Quote(testEngine.TableName("get_var", true))).Get(&money2)
} else {
has, err = testEngine.SQL("SELECT money FROM " + testEngine.TableName("get_var", true) + " LIMIT 1").Get(&money2)
has, err = testEngine.SQL("SELECT `money` FROM " + testEngine.Quote(testEngine.TableName("get_var", true)) + " LIMIT 1").Get(&money2)
}
assert.NoError(t, err)
assert.Equal(t, true, has)
assert.Equal(t, "1.5", fmt.Sprintf("%.1f", money2))
var money3 float64
has, err = testEngine.SQL("SELECT money FROM " + testEngine.TableName("get_var", true) + " WHERE money > 20").Get(&money3)
has, err = testEngine.SQL("SELECT `money` FROM " + testEngine.Quote(testEngine.TableName("get_var", true)) + " WHERE `money` > 20").Get(&money3)
assert.NoError(t, err)
assert.Equal(t, false, has)
@ -187,7 +188,7 @@ func TestGetVar(t *testing.T) {
// for mymysql driver, interface{} will be []byte, so ignore it currently
if testEngine.DriverName() != "mymysql" {
var valuesInter = make(map[string]interface{})
has, err = testEngine.Table("get_var").Where("id = ?", 1).Select("*").Get(&valuesInter)
has, err = testEngine.Table("get_var").Where("`id` = ?", 1).Select("*").Get(&valuesInter)
assert.NoError(t, err)
assert.Equal(t, true, has)
assert.Equal(t, 5, len(valuesInter))
@ -234,7 +235,7 @@ func TestGetStruct(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserinfoGet)))
assert.NoError(t, testEngine.Sync(new(UserinfoGet)))
session := testEngine.NewSession()
defer session.Close()
@ -243,7 +244,7 @@ func TestGetStruct(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
err = session.Begin()
assert.NoError(t, err)
_, err = session.Exec("SET IDENTITY_INSERT userinfo_get ON")
_, err = session.Exec("SET IDENTITY_INSERT `userinfo_get` ON")
assert.NoError(t, err)
}
cnt, err := session.Insert(&UserinfoGet{Uid: 2})
@ -265,7 +266,7 @@ func TestGetStruct(t *testing.T) {
Total int64
}
assert.NoError(t, testEngine.Sync2(&NoIdUser{}))
assert.NoError(t, testEngine.Sync(&NoIdUser{}))
userCol := testEngine.GetColumnMapper().Obj2Table("User")
_, err = testEngine.Where("`"+userCol+"` = ?", "xlw").Delete(&NoIdUser{})
@ -300,6 +301,11 @@ func TestGetSlice(t *testing.T) {
func TestGetMap(t *testing.T) {
assert.NoError(t, PrepareEngine())
if testEngine.Dialect().Features().AutoincrMode == dialects.SequenceAutoincrMode {
t.SkipNow()
return
}
type UserinfoMap struct {
Uid int `xorm:"pk autoincr"`
IsMan bool
@ -308,7 +314,7 @@ func TestGetMap(t *testing.T) {
assertSync(t, new(UserinfoMap))
tableName := testEngine.Quote(testEngine.TableName("userinfo_map", true))
_, err := testEngine.Exec(fmt.Sprintf("INSERT INTO %s (is_man) VALUES (NULL)", tableName))
_, err := testEngine.Exec(fmt.Sprintf("INSERT INTO %s (`is_man`) VALUES (NULL)", tableName))
assert.NoError(t, err)
var valuesString = make(map[string]string)
@ -479,7 +485,7 @@ func TestGetStructId(t *testing.T) {
//var id int64
var maxid maxidst
sql := "select max(id) as id from " + testEngine.TableName(&TestGetStruct{}, true)
sql := "select max(`id`) as id from " + testEngine.Quote(testEngine.TableName(&TestGetStruct{}, true))
has, err := testEngine.SQL(sql).Get(&maxid)
assert.NoError(t, err)
assert.True(t, has)
@ -570,7 +576,7 @@ func (MyGetCustomTableImpletation) TableName() string {
func TestGetCustomTableInterface(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Table(getCustomTableName).Sync2(new(MyGetCustomTableImpletation)))
assert.NoError(t, testEngine.Table(getCustomTableName).Sync(new(MyGetCustomTableImpletation)))
exist, err := testEngine.IsTableExist(getCustomTableName)
assert.NoError(t, err)
@ -597,73 +603,78 @@ func TestGetNullVar(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(TestGetNullVarStruct))
affected, err := testEngine.Exec("insert into " + testEngine.TableName(new(TestGetNullVarStruct), true) + " (name,age) values (null,null)")
if testEngine.Dialect().Features().AutoincrMode == dialects.SequenceAutoincrMode {
t.SkipNow()
return
}
affected, err := testEngine.Exec("insert into " + testEngine.Quote(testEngine.TableName(new(TestGetNullVarStruct), true)) + " (`name`,`age`) values (null,null)")
assert.NoError(t, err)
a, _ := affected.RowsAffected()
assert.EqualValues(t, 1, a)
var name string
has, err := testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("name").Get(&name)
has, err := testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("name").Get(&name)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "", name)
var age int
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age)
var age2 int8
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age2)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age2)
var age3 int16
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age3)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age3)
var age4 int32
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age4)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age4)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age4)
var age5 int64
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age5)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age5)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age5)
var age6 uint
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age6)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age6)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age6)
var age7 uint8
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age7)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age7)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age7)
var age8 int16
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age8)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age8)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age8)
var age9 int32
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age9)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age9)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age9)
var age10 int64
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("id = ?", 1).Cols("age").Get(&age10)
has, err = testEngine.Table(new(TestGetNullVarStruct)).Where("`id` = ?", 1).Cols("age").Get(&age10)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 0, age10)
@ -697,7 +708,7 @@ func TestCustomTypes(t *testing.T) {
assert.EqualValues(t, "test", name)
var age MyInt
has, err = testEngine.Table(new(TestCustomizeStruct)).ID(s.Id).Select("age").Get(&age)
has, err = testEngine.Table(new(TestCustomizeStruct)).ID(s.Id).Select("`age`").Get(&age)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 32, age)
@ -759,7 +770,7 @@ func TestGetBigFloat(t *testing.T) {
assert.NoError(t, err)
var m big.Float
has, err := testEngine.Table("get_big_float").Cols("money").Where("id=?", gf.Id).Get(&m)
has, err := testEngine.Table("get_big_float").Cols("money").Where("`id`=?", gf.Id).Get(&m)
assert.NoError(t, err)
assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String())
@ -785,7 +796,7 @@ func TestGetBigFloat(t *testing.T) {
assert.NoError(t, err)
var m2 big.Float
has, err := testEngine.Table("get_big_float2").Cols("money").Where("id=?", gf2.Id).Get(&m2)
has, err := testEngine.Table("get_big_float2").Cols("money").Where("`id`=?", gf2.Id).Get(&m2)
assert.NoError(t, err)
assert.True(t, has)
assert.True(t, m2.String() == gf2.Money.String(), "%v != %v", m2.String(), gf2.Money.String())
@ -825,7 +836,7 @@ func TestGetDecimal(t *testing.T) {
assert.NoError(t, err)
var m decimal.Decimal
has, err := testEngine.Table("get_decimal").Cols("money").Where("id=?", gf.Id).Get(&m)
has, err := testEngine.Table("get_decimal").Cols("money").Where("`id`=?", gf.Id).Get(&m)
assert.NoError(t, err)
assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String())
@ -850,7 +861,7 @@ func TestGetDecimal(t *testing.T) {
assert.NoError(t, err)
var m decimal.Decimal
has, err := testEngine.Table("get_decimal2").Cols("money").Where("id=?", gf.Id).Get(&m)
has, err := testEngine.Table("get_decimal2").Cols("money").Where("`id`=?", gf.Id).Get(&m)
assert.NoError(t, err)
assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String())
@ -879,3 +890,89 @@ func TestGetTime(t *testing.T) {
assert.True(t, has)
assert.EqualValues(t, gts.CreateTime.Format(time.RFC3339), gn.Format(time.RFC3339))
}
func TestGetVars(t *testing.T) {
type GetVars struct {
Id int64
Name string
Age int
}
assert.NoError(t, PrepareEngine())
assertSync(t, new(GetVars))
_, err := testEngine.Insert(&GetVars{
Name: "xlw",
Age: 42,
})
assert.NoError(t, err)
var name string
var age int
has, err := testEngine.Table(new(GetVars)).Cols("name", "age").Get(&name, &age)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "xlw", name)
assert.EqualValues(t, 42, age)
}
func TestGetWithPrepare(t *testing.T) {
type GetVarsWithPrepare struct {
Id int64
Name string
Age int
}
assert.NoError(t, PrepareEngine())
assertSync(t, new(GetVarsWithPrepare))
_, err := testEngine.Insert(&GetVarsWithPrepare{
Name: "xlw",
Age: 42,
})
assert.NoError(t, err)
var v1 GetVarsWithPrepare
has, err := testEngine.Prepare().ID(1).Get(&v1)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "xlw", v1.Name)
assert.EqualValues(t, 42, v1.Age)
sess := testEngine.NewSession()
defer sess.Close()
var v2 GetVarsWithPrepare
has, err = sess.Prepare().ID(1).Get(&v2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "xlw", v2.Name)
assert.EqualValues(t, 42, v2.Age)
var v3 GetVarsWithPrepare
has, err = sess.Prepare().ID(1).Get(&v3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "xlw", v3.Name)
assert.EqualValues(t, 42, v3.Age)
err = sess.Begin()
assert.NoError(t, err)
cnt, err := sess.Prepare().Insert(&GetVarsWithPrepare{
Name: "xlw2",
Age: 12,
})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
cnt, err = sess.Prepare().Insert(&GetVarsWithPrepare{
Name: "xlw3",
Age: 13,
})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
err = sess.Commit()
assert.NoError(t, err)
}

View File

@ -11,6 +11,7 @@ import (
"time"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
"github.com/stretchr/testify/assert"
)
@ -24,7 +25,7 @@ func TestInsertOne(t *testing.T) {
Created time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(Test)))
assert.NoError(t, testEngine.Sync(new(Test)))
data := Test{Msg: "hi"}
_, err := testEngine.InsertOne(data)
@ -38,7 +39,7 @@ func TestInsertMulti(t *testing.T) {
Name string `xorm:"varchar(255)"`
}
assert.NoError(t, testEngine.Sync2(new(TestMulti)))
assert.NoError(t, testEngine.Sync(new(TestMulti)))
num, err := insertMultiDatas(1,
append([]TestMulti{}, TestMulti{1, "test1"}, TestMulti{2, "test2"}, TestMulti{3, "test3"}))
@ -100,7 +101,7 @@ func callbackLooper(datas interface{}, step int, actionFunc func(interface{}) er
if err = actionFunc(tempInterface); err != nil {
return
}
processedLen = processedLen - step
processedLen -= step
}
return
}
@ -114,7 +115,7 @@ func TestInsertOneIfPkIsPoint(t *testing.T) {
Created *time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(TestPoint)))
assert.NoError(t, testEngine.Sync(new(TestPoint)))
msg := "hi"
data := TestPoint{Msg: &msg}
_, err := testEngine.InsertOne(&data)
@ -130,7 +131,7 @@ func TestInsertOneIfPkIsPointRename(t *testing.T) {
Created *time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(TestPoint2)))
assert.NoError(t, testEngine.Sync(new(TestPoint2)))
msg := "hi"
data := TestPoint2{Msg: &msg}
_, err := testEngine.InsertOne(&data)
@ -180,7 +181,7 @@ func TestInsertDefault(t *testing.T) {
}
di := new(DefaultInsert)
err := testEngine.Sync2(di)
err := testEngine.Sync(di)
assert.NoError(t, err)
var di2 = DefaultInsert{Name: "test"}
@ -191,8 +192,8 @@ func TestInsertDefault(t *testing.T) {
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, -1, di.Status)
assert.EqualValues(t, di2.Updated.Unix(), di.Updated.Unix())
assert.EqualValues(t, di2.Created.Unix(), di.Created.Unix())
assert.EqualValues(t, di2.Updated.Unix(), di.Updated.Unix(), di.Updated)
assert.EqualValues(t, di2.Created.Unix(), di.Created.Unix(), di.Created)
}
func TestInsertDefault2(t *testing.T) {
@ -206,7 +207,7 @@ func TestInsertDefault2(t *testing.T) {
}
di := new(DefaultInsert2)
err := testEngine.Sync2(di)
err := testEngine.Sync(di)
assert.NoError(t, err)
var di2 = DefaultInsert2{Name: "test"}
@ -257,7 +258,7 @@ func TestInsertCreated(t *testing.T) {
assert.NoError(t, PrepareEngine())
di := new(CreatedInsert)
err := testEngine.Sync2(di)
err := testEngine.Sync(di)
assert.NoError(t, err)
ci := &CreatedInsert{}
@ -270,7 +271,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci.Created.Unix(), di.Created.Unix())
di2 := new(CreatedInsert2)
err = testEngine.Sync2(di2)
err = testEngine.Sync(di2)
assert.NoError(t, err)
ci2 := &CreatedInsert2{}
@ -283,7 +284,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci2.Created, di2.Created)
di3 := new(CreatedInsert3)
err = testEngine.Sync2(di3)
err = testEngine.Sync(di3)
assert.NoError(t, err)
ci3 := &CreatedInsert3{}
@ -296,7 +297,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci3.Created, di3.Created)
di4 := new(CreatedInsert4)
err = testEngine.Sync2(di4)
err = testEngine.Sync(di4)
assert.NoError(t, err)
ci4 := &CreatedInsert4{}
@ -309,7 +310,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci4.Created, di4.Created)
di5 := new(CreatedInsert5)
err = testEngine.Sync2(di5)
err = testEngine.Sync(di5)
assert.NoError(t, err)
ci5 := &CreatedInsert5{}
@ -322,7 +323,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci5.Created.Unix(), di5.Created.Unix())
di6 := new(CreatedInsert6)
err = testEngine.Sync2(di6)
err = testEngine.Sync(di6)
assert.NoError(t, err)
oldTime := time.Now().Add(-time.Hour)
@ -336,6 +337,42 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci6.Created.Unix(), di6.Created.Unix())
}
func TestInsertTime(t *testing.T) {
type InsertTimeStruct struct {
Id int64
CreatedAt time.Time `xorm:"created"`
UpdatedAt time.Time `xorm:"updated"`
DeletedAt time.Time `xorm:"deleted"`
Stime time.Time
Etime time.Time
}
assert.NoError(t, PrepareEngine())
assertSync(t, new(InsertTimeStruct))
its := &InsertTimeStruct{
Stime: time.Now(),
Etime: time.Now(),
}
cnt, err := testEngine.Insert(its)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
var itsGet InsertTimeStruct
has, err := testEngine.ID(1).Get(&itsGet)
assert.NoError(t, err)
assert.True(t, has)
assert.False(t, itsGet.Stime.IsZero())
assert.False(t, itsGet.Etime.IsZero())
var itsFind []*InsertTimeStruct
err = testEngine.Find(&itsFind)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(itsFind))
assert.False(t, itsFind[0].Stime.IsZero())
assert.False(t, itsFind[0].Etime.IsZero())
}
type JSONTime time.Time
func (j JSONTime) format() string {
@ -389,7 +426,7 @@ func TestCreatedJsonTime(t *testing.T) {
assert.NoError(t, PrepareEngine())
di5 := new(MyJSONTime)
err := testEngine.Sync2(di5)
err := testEngine.Sync(di5)
assert.NoError(t, err)
ci5 := &MyJSONTime{}
@ -488,7 +525,7 @@ func TestInsertCreatedInt64(t *testing.T) {
Created int64 `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(TestCreatedInt64)))
assert.NoError(t, testEngine.Sync(new(TestCreatedInt64)))
data := TestCreatedInt64{Msg: "hi"}
now := time.Now()
@ -624,6 +661,11 @@ func TestAnonymousStruct(t *testing.T) {
}
func TestInsertMap(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
type InsertMap struct {
Id int64
Width uint32
@ -727,7 +769,7 @@ func TestInsertWhere(t *testing.T) {
}
inserted, err := testEngine.SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Where("repo_id=?", 1).
Where("`repo_id`=?", 1).
Insert(&i)
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
@ -740,7 +782,12 @@ func TestInsertWhere(t *testing.T) {
i.Index = 1
assert.EqualValues(t, i, j)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
inserted, err = testEngine.Table(new(InsertWhere)).Where("`repo_id`=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
@ -761,7 +808,7 @@ func TestInsertWhere(t *testing.T) {
assert.EqualValues(t, "trest2", j2.Name)
assert.EqualValues(t, 2, j2.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
inserted, err = testEngine.Table(new(InsertWhere)).Where("`repo_id`=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
SetExpr("repo_id", "1").
Insert(map[string]string{
@ -777,7 +824,7 @@ func TestInsertWhere(t *testing.T) {
assert.EqualValues(t, "trest3", j3.Name)
assert.EqualValues(t, 3, j3.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
inserted, err = testEngine.Table(new(InsertWhere)).Where("`repo_id`=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
@ -793,7 +840,7 @@ func TestInsertWhere(t *testing.T) {
assert.EqualValues(t, "10';delete * from insert_where; --", j4.Name)
assert.EqualValues(t, 4, j4.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
inserted, err = testEngine.Table(new(InsertWhere)).Where("`repo_id`=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
@ -846,6 +893,11 @@ func TestInsertExpr2(t *testing.T) {
assert.EqualValues(t, 1, ie2.RepoId)
assert.EqualValues(t, true, ie2.IsTag)
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
inserted, err = testEngine.Table(new(InsertExprsRelease)).
SetExpr("is_draft", true).
SetExpr("num_commits", 0).
@ -880,7 +932,7 @@ func TestMultipleInsertTableName(t *testing.T) {
assert.NoError(t, PrepareEngine())
tableName := `prd_nightly_rate_16`
assert.NoError(t, testEngine.Table(tableName).Sync2(new(NightlyRate)))
assert.NoError(t, testEngine.Table(tableName).Sync(new(NightlyRate)))
trans := testEngine.NewSession()
defer trans.Close()
@ -916,7 +968,7 @@ func TestInsertMultiWithOmit(t *testing.T) {
Omitted string `xorm:"varchar(255) 'omitted'"`
}
assert.NoError(t, testEngine.Sync2(new(TestMultiOmit)))
assert.NoError(t, testEngine.Sync(new(TestMultiOmit)))
l := []interface{}{
TestMultiOmit{Id: 1, Name: "1", Omitted: "1"},
@ -961,7 +1013,7 @@ func TestInsertTwice(t *testing.T) {
FieldB int
}
assert.NoError(t, testEngine.Sync2(new(InsertStructA), new(InsertStructB)))
assert.NoError(t, testEngine.Sync(new(InsertStructA), new(InsertStructB)))
var sliceA []InsertStructA // sliceA is empty
sliceB := []InsertStructB{
@ -992,7 +1044,7 @@ func TestInsertIntSlice(t *testing.T) {
NameIDs []int `xorm:"json notnull"`
}
assert.NoError(t, testEngine.Sync2(new(InsertIntSlice)))
assert.NoError(t, testEngine.Sync(new(InsertIntSlice)))
var v = InsertIntSlice{
NameIDs: []int{1, 2},
@ -1033,7 +1085,7 @@ func TestInsertDeleted(t *testing.T) {
DeletedAt time.Time `xorm:"'DELETED_AT' deleted notnull"`
}
// notnull tag will be ignored
err := testEngine.Sync2(new(InsertDeletedStructNotRight))
err := testEngine.Sync(new(InsertDeletedStructNotRight))
assert.NoError(t, err)
type InsertDeletedStruct struct {
@ -1041,7 +1093,7 @@ func TestInsertDeleted(t *testing.T) {
DeletedAt time.Time `xorm:"'DELETED_AT' deleted"`
}
assert.NoError(t, testEngine.Sync2(new(InsertDeletedStruct)))
assert.NoError(t, testEngine.Sync(new(InsertDeletedStruct)))
var v InsertDeletedStruct
_, err = testEngine.Insert(&v)
@ -1067,6 +1119,11 @@ func TestInsertDeleted(t *testing.T) {
}
func TestInsertMultipleMap(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
type InsertMultipleMap struct {
Id int64
Width uint32

View File

@ -18,7 +18,7 @@ func TestIterate(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserIterate)))
assert.NoError(t, testEngine.Sync(new(UserIterate)))
cnt, err := testEngine.Insert(&UserIterate{
IsMan: true,
@ -26,16 +26,27 @@ func TestIterate(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
cnt, err = testEngine.Insert(&UserIterate{
IsMan: false,
})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
cnt = 0
err = testEngine.Iterate(new(UserIterate), func(i int, bean interface{}) error {
user := bean.(*UserIterate)
assert.EqualValues(t, 1, user.Id)
assert.EqualValues(t, true, user.IsMan)
if cnt == 0 {
assert.EqualValues(t, 1, user.Id)
assert.EqualValues(t, true, user.IsMan)
} else {
assert.EqualValues(t, 2, user.Id)
assert.EqualValues(t, false, user.IsMan)
}
cnt++
return nil
})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.EqualValues(t, 2, cnt)
}
func TestBufferIterate(t *testing.T) {
@ -46,7 +57,7 @@ func TestBufferIterate(t *testing.T) {
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserBufferIterate)))
assert.NoError(t, testEngine.Sync(new(UserBufferIterate)))
var size = 20
for i := 0; i < size; i++ {
@ -91,7 +102,7 @@ func TestBufferIterate(t *testing.T) {
assert.EqualValues(t, 7, cnt)
cnt = 0
err = testEngine.Where("id <= 10").BufferSize(2).Iterate(new(UserBufferIterate), func(i int, bean interface{}) error {
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)

View File

@ -121,7 +121,7 @@ func TestInt16Id(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans))
beans2 := make(map[int16]Int16Id, 0)
beans2 := make(map[int16]Int16Id)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -154,7 +154,7 @@ func TestInt32Id(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans))
beans2 := make(map[int32]Int32Id, 0)
beans2 := make(map[int32]Int32Id)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -205,7 +205,7 @@ func TestUintId(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 3, len(beans))
beans2 := make(map[uint]UintId, 0)
beans2 := make(map[uint]UintId)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 3, len(beans2))
@ -239,7 +239,7 @@ func TestUint16Id(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans))
beans2 := make(map[uint16]Uint16Id, 0)
beans2 := make(map[uint16]Uint16Id)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -273,7 +273,7 @@ func TestUint32Id(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans))
beans2 := make(map[uint32]Uint32Id, 0)
beans2 := make(map[uint32]Uint32Id)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -310,7 +310,7 @@ func TestUint64Id(t *testing.T) {
assert.EqualValues(t, 1, len(beans))
assert.EqualValues(t, *bean, beans[0])
beans2 := make(map[uint64]Uint64Id, 0)
beans2 := make(map[uint64]Uint64Id)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -533,7 +533,7 @@ func TestMyIntId(t *testing.T) {
assert.EqualValues(t, 1, len(beans))
assert.EqualValues(t, *bean, beans[0])
beans2 := make(map[ID]MyIntPK, 0)
beans2 := make(map[ID]MyIntPK)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -570,7 +570,7 @@ func TestMyStringId(t *testing.T) {
assert.EqualValues(t, 1, len(beans))
assert.EqualValues(t, *bean, beans[0])
beans2 := make(map[StrID]MyStringPK, 0)
beans2 := make(map[StrID]MyStringPK)
err = testEngine.Find(&beans2)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(beans2))
@ -607,7 +607,7 @@ func TestCompositePK(t *testing.T) {
assert.NoError(t, err)
assertSync(t, new(TaskSolution))
assert.NoError(t, testEngine.Sync2(new(TaskSolution)))
assert.NoError(t, testEngine.Sync(new(TaskSolution)))
tables2, err := testEngine.DBMetas()
assert.NoError(t, err)

View File

@ -5,7 +5,6 @@
package integrations
import (
"fmt"
"strconv"
"testing"
"time"
@ -27,7 +26,7 @@ func TestQueryString(t *testing.T) {
Created time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(GetVar2)))
assert.NoError(t, testEngine.Sync(new(GetVar2)))
var data = GetVar2{
Msg: "hi",
@ -37,7 +36,7 @@ func TestQueryString(t *testing.T) {
_, err := testEngine.InsertOne(data)
assert.NoError(t, err)
records, err := testEngine.QueryString("select * from " + testEngine.TableName("get_var2", true))
records, err := testEngine.QueryString("select * from " + testEngine.Quote(testEngine.TableName("get_var2", true)))
assert.NoError(t, err)
assert.Equal(t, 1, len(records))
assert.Equal(t, 5, len(records[0]))
@ -55,7 +54,7 @@ func TestQueryString2(t *testing.T) {
Msg bool
}
assert.NoError(t, testEngine.Sync2(new(GetVar3)))
assert.NoError(t, testEngine.Sync(new(GetVar3)))
var data = GetVar3{
Msg: false,
@ -63,7 +62,7 @@ func TestQueryString2(t *testing.T) {
_, err := testEngine.Insert(data)
assert.NoError(t, err)
records, err := testEngine.QueryString("select * from " + testEngine.TableName("get_var3", true))
records, err := testEngine.QueryString("select * from " + testEngine.Quote(testEngine.TableName("get_var3", true)))
assert.NoError(t, err)
assert.Equal(t, 1, len(records))
assert.Equal(t, 2, len(records[0]))
@ -71,42 +70,6 @@ func TestQueryString2(t *testing.T) {
assert.True(t, "0" == records[0]["msg"] || "false" == records[0]["msg"])
}
func toString(i interface{}) string {
switch i.(type) {
case []byte:
return string(i.([]byte))
case string:
return i.(string)
}
return fmt.Sprintf("%v", i)
}
func toInt64(i interface{}) int64 {
switch i.(type) {
case []byte:
n, _ := strconv.ParseInt(string(i.([]byte)), 10, 64)
return n
case int:
return int64(i.(int))
case int64:
return i.(int64)
}
return 0
}
func toFloat64(i interface{}) float64 {
switch i.(type) {
case []byte:
n, _ := strconv.ParseFloat(string(i.([]byte)), 64)
return n
case float64:
return i.(float64)
case float32:
return float64(i.(float32))
}
return 0
}
func toBool(i interface{}) bool {
switch t := i.(type) {
case int32:
@ -128,7 +91,7 @@ func TestQueryInterface(t *testing.T) {
Created time.Time `xorm:"created"`
}
assert.NoError(t, testEngine.Sync2(new(GetVarInterface)))
assert.NoError(t, testEngine.Sync(new(GetVarInterface)))
var data = GetVarInterface{
Msg: "hi",
@ -138,7 +101,7 @@ func TestQueryInterface(t *testing.T) {
_, err := testEngine.InsertOne(data)
assert.NoError(t, err)
records, err := testEngine.QueryInterface("select * from " + testEngine.TableName("get_var_interface", true))
records, err := testEngine.QueryInterface("select * from " + testEngine.Quote(testEngine.TableName("get_var_interface", true)))
assert.NoError(t, err)
assert.Equal(t, 1, len(records))
assert.Equal(t, 5, len(records[0]))
@ -161,7 +124,7 @@ func TestQueryNoParams(t *testing.T) {
testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(QueryNoParams)))
assert.NoError(t, testEngine.Sync(new(QueryNoParams)))
var q = QueryNoParams{
Msg: "message",
@ -192,7 +155,7 @@ func TestQueryNoParams(t *testing.T) {
assert.NoError(t, err)
assertResult(t, results)
results, err = testEngine.SQL("select * from " + testEngine.TableName("query_no_params", true)).Query()
results, err = testEngine.SQL("select * from " + testEngine.Quote(testEngine.TableName("query_no_params", true))).Query()
assert.NoError(t, err)
assertResult(t, results)
}
@ -205,7 +168,7 @@ func TestQueryStringNoParam(t *testing.T) {
Msg bool
}
assert.NoError(t, testEngine.Sync2(new(GetVar4)))
assert.NoError(t, testEngine.Sync(new(GetVar4)))
var data = GetVar4{
Msg: false,
@ -223,7 +186,7 @@ func TestQueryStringNoParam(t *testing.T) {
assert.EqualValues(t, "0", records[0]["msg"])
}
records, err = testEngine.Table("get_var4").Where(builder.Eq{"id": 1}).QueryString()
records, err = testEngine.Table("get_var4").Where(builder.Eq{"`id`": 1}).QueryString()
assert.NoError(t, err)
assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, "1", records[0]["id"])
@ -242,7 +205,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
Msg bool
}
assert.NoError(t, testEngine.Sync2(new(GetVar6)))
assert.NoError(t, testEngine.Sync(new(GetVar6)))
var data = GetVar6{
Msg: false,
@ -260,7 +223,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
assert.EqualValues(t, "0", records[0][1])
}
records, err = testEngine.Table("get_var6").Where(builder.Eq{"id": 1}).QuerySliceString()
records, err = testEngine.Table("get_var6").Where(builder.Eq{"`id`": 1}).QuerySliceString()
assert.NoError(t, err)
assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, "1", records[0][0])
@ -279,7 +242,7 @@ func TestQueryInterfaceNoParam(t *testing.T) {
Msg bool
}
assert.NoError(t, testEngine.Sync2(new(GetVar5)))
assert.NoError(t, testEngine.Sync(new(GetVar5)))
var data = GetVar5{
Msg: false,
@ -293,7 +256,7 @@ func TestQueryInterfaceNoParam(t *testing.T) {
assert.EqualValues(t, 1, records[0]["id"])
assert.False(t, toBool(records[0]["msg"]))
records, err = testEngine.Table("get_var5").Where(builder.Eq{"id": 1}).QueryInterface()
records, err = testEngine.Table("get_var5").Where(builder.Eq{"`id`": 1}).QueryInterface()
assert.NoError(t, err)
assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, 1, records[0]["id"])
@ -313,7 +276,7 @@ func TestQueryWithBuilder(t *testing.T) {
testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(QueryWithBuilder)))
assert.NoError(t, testEngine.Sync(new(QueryWithBuilder)))
var q = QueryWithBuilder{
Msg: "message",
@ -340,7 +303,7 @@ func TestQueryWithBuilder(t *testing.T) {
assert.EqualValues(t, 3000, money)
}
results, err := testEngine.Query(builder.Select("*").From(testEngine.TableName("query_with_builder", true)))
results, err := testEngine.Query(builder.Select("*").From(testEngine.Quote(testEngine.TableName("query_with_builder", true))))
assert.NoError(t, err)
assertResult(t, results)
}
@ -362,7 +325,7 @@ func TestJoinWithSubQuery(t *testing.T) {
testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(JoinWithSubQuery1), new(JoinWithSubQueryDepart)))
assert.NoError(t, testEngine.Sync(new(JoinWithSubQuery1), new(JoinWithSubQueryDepart)))
var depart = JoinWithSubQueryDepart{
Name: "depart1",
@ -383,14 +346,14 @@ func TestJoinWithSubQuery(t *testing.T) {
tbName := testEngine.Quote(testEngine.TableName("join_with_sub_query_depart", true))
var querys []JoinWithSubQuery1
err = testEngine.Join("INNER", builder.Select("id").From(tbName),
"join_with_sub_query_depart.id = join_with_sub_query1.depart_id").Find(&querys)
err = testEngine.Join("INNER", builder.Select("`id`").From(tbName),
"`join_with_sub_query_depart`.`id` = `join_with_sub_query1`.`depart_id`").Find(&querys)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(querys))
assert.EqualValues(t, q, querys[0])
querys = make([]JoinWithSubQuery1, 0, 1)
err = testEngine.Join("INNER", "(SELECT id FROM "+tbName+") join_with_sub_query_depart", "join_with_sub_query_depart.id = join_with_sub_query1.depart_id").
err = testEngine.Join("INNER", "(SELECT `id` FROM "+tbName+") `a`", "`a`.`id` = `join_with_sub_query1`.`depart_id`").
Find(&querys)
assert.NoError(t, err)
assert.EqualValues(t, 1, len(querys))
@ -412,7 +375,7 @@ func TestQueryStringWithLimit(t *testing.T) {
Money float32
}
assert.NoError(t, testEngine.Sync2(new(QueryWithLimit)))
assert.NoError(t, testEngine.Sync(new(QueryWithLimit)))
data, err := testEngine.Table("query_with_limit").Limit(20, 20).QueryString()
assert.NoError(t, err)

View File

@ -20,15 +20,15 @@ func TestExecAndQuery(t *testing.T) {
Name string
}
assert.NoError(t, testEngine.Sync2(new(UserinfoQuery)))
assert.NoError(t, testEngine.Sync(new(UserinfoQuery)))
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_query`", true)+" (uid, name) VALUES (?, ?)", 1, "user")
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_query`", true)+" (`uid`, `name`) VALUES (?, ?)", 1, "user")
assert.NoError(t, err)
cnt, err := res.RowsAffected()
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
results, err := testEngine.Query("select * from " + testEngine.TableName("userinfo_query", true))
results, err := testEngine.Query("select * from " + testEngine.Quote(testEngine.TableName("userinfo_query", true)))
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
id, err := strconv.Atoi(string(results[0]["uid"]))
@ -46,21 +46,21 @@ func TestExecTime(t *testing.T) {
Created time.Time
}
assert.NoError(t, testEngine.Sync2(new(UserinfoExecTime)))
assert.NoError(t, testEngine.Sync(new(UserinfoExecTime)))
now := time.Now()
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_exec_time`", true)+" (uid, name, created) VALUES (?, ?, ?)", 1, "user", now)
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_exec_time`", true)+" (`uid`, `name`, `created`) VALUES (?, ?, ?)", 1, "user", now)
assert.NoError(t, err)
cnt, err := res.RowsAffected()
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
results, err := testEngine.QueryString("SELECT * FROM " + testEngine.TableName("`userinfo_exec_time`", true))
results, err := testEngine.QueryString("SELECT * FROM " + testEngine.Quote(testEngine.TableName("userinfo_exec_time", true)))
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), results[0]["created"])
var uet UserinfoExecTime
has, err := testEngine.Where("uid=?", 1).Get(&uet)
has, err := testEngine.Where("`uid`=?", 1).Get(&uet)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), uet.Created.Format("2006-01-02 15:04:05"))

View File

@ -173,7 +173,7 @@ func (s *SyncTable3) TableName() string {
func TestSyncTable(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable1)))
assert.NoError(t, testEngine.Sync(new(SyncTable1)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -183,7 +183,7 @@ func TestSyncTable(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name")))
assert.NoError(t, testEngine.Sync2(new(SyncTable2)))
assert.NoError(t, testEngine.Sync(new(SyncTable2)))
tables, err = testEngine.DBMetas()
assert.NoError(t, err)
@ -193,7 +193,7 @@ func TestSyncTable(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name")))
assert.NoError(t, testEngine.Sync2(new(SyncTable3)))
assert.NoError(t, testEngine.Sync(new(SyncTable3)))
tables, err = testEngine.DBMetas()
assert.NoError(t, err)
@ -207,7 +207,7 @@ func TestSyncTable(t *testing.T) {
func TestSyncTable2(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Table("sync_tablex").Sync2(new(SyncTable1)))
assert.NoError(t, testEngine.Table("sync_tablex").Sync(new(SyncTable1)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -220,7 +220,7 @@ func TestSyncTable2(t *testing.T) {
NewCol string
}
assert.NoError(t, testEngine.Table("sync_tablex").Sync2(new(SyncTable4)))
assert.NoError(t, testEngine.Table("sync_tablex").Sync(new(SyncTable4)))
tables, err = testEngine.DBMetas()
assert.NoError(t, err)
assert.EqualValues(t, 1, len(tables))
@ -241,7 +241,7 @@ func TestSyncTable3(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable5)))
assert.NoError(t, testEngine.Sync(new(SyncTable5)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -272,7 +272,7 @@ func TestSyncTable3(t *testing.T) {
}()
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable5)))
assert.NoError(t, testEngine.Sync(new(SyncTable5)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -294,9 +294,9 @@ func TestSyncTable4(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable6)))
assert.NoError(t, testEngine.Sync(new(SyncTable6)))
assert.NoError(t, testEngine.Sync2(new(SyncTable6)))
assert.NoError(t, testEngine.Sync(new(SyncTable6)))
}
func TestIsTableExist(t *testing.T) {
@ -328,14 +328,14 @@ func TestIsTableEmpty(t *testing.T) {
Created time.Time `xorm:"created"`
ILike int
PageView int
From_url string
From_url string // nolint
Pre_url string `xorm:"unique"` //pre view image's url
Uid int64
}
assert.NoError(t, testEngine.DropTables(&PictureEmpty{}, &NumericEmpty{}))
assert.NoError(t, testEngine.Sync2(new(PictureEmpty), new(NumericEmpty)))
assert.NoError(t, testEngine.Sync(new(PictureEmpty), new(NumericEmpty)))
isEmpty, err := testEngine.IsTableEmpty(&PictureEmpty{})
assert.NoError(t, err)
@ -393,7 +393,7 @@ func TestIndexAndUnique(t *testing.T) {
func TestMetaInfo(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(CustomTableName), new(IndexOrUnique)))
assert.NoError(t, testEngine.Sync(new(CustomTableName), new(IndexOrUnique)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -423,8 +423,8 @@ func TestSync2_1(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.DropTables("wx_test"))
assert.NoError(t, testEngine.Sync2(new(WxTest)))
assert.NoError(t, testEngine.Sync2(new(WxTest)))
assert.NoError(t, testEngine.Sync(new(WxTest)))
assert.NoError(t, testEngine.Sync(new(WxTest)))
}
func TestUnique_1(t *testing.T) {
@ -440,7 +440,7 @@ func TestUnique_1(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.DropTables("user_unique"))
assert.NoError(t, testEngine.Sync2(new(UserUnique)))
assert.NoError(t, testEngine.Sync(new(UserUnique)))
assert.NoError(t, testEngine.DropTables("user_unique"))
assert.NoError(t, testEngine.CreateTables(new(UserUnique)))
@ -459,7 +459,7 @@ func TestSync2_2(t *testing.T) {
for i := 0; i < 10; i++ {
tableName := fmt.Sprintf("test_sync2_index_%d", i)
tableNames[tableName] = true
assert.NoError(t, testEngine.Table(tableName).Sync2(new(TestSync2Index)))
assert.NoError(t, testEngine.Table(tableName).Sync(new(TestSync2Index)))
exist, err := testEngine.IsTableExist(tableName)
assert.NoError(t, err)
@ -484,7 +484,7 @@ func TestSync2_Default(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(TestSync2Default))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default)))
}
func TestSync2_Default2(t *testing.T) {
@ -497,9 +497,9 @@ func TestSync2_Default2(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(TestSync2Default2))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
@ -526,8 +526,9 @@ func TestModifyColum(t *testing.T) {
SQLType: schemas.SQLType{
Name: "VARCHAR",
},
Length: 16,
Nullable: false,
Length: 16,
Nullable: false,
DefaultIsEmpty: true,
})
_, err := testEngine.Exec(alterSQL)
assert.NoError(t, err)

View File

@ -23,7 +23,7 @@ func TestSum(t *testing.T) {
}
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SumStruct)))
assert.NoError(t, testEngine.Sync(new(SumStruct)))
var (
cases = []SumStruct{
@ -82,7 +82,7 @@ func (s SumStructWithTableName) TableName() string {
func TestSumWithTableName(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SumStructWithTableName)))
assert.NoError(t, testEngine.Sync(new(SumStructWithTableName)))
var (
cases = []SumStructWithTableName{
@ -146,7 +146,7 @@ func TestSumCustomColumn(t *testing.T) {
}
)
assert.NoError(t, testEngine.Sync2(new(SumStruct2)))
assert.NoError(t, testEngine.Sync(new(SumStruct2)))
cnt, err := testEngine.Insert(cases)
assert.NoError(t, err)

View File

@ -18,7 +18,7 @@ func TestClose(t *testing.T) {
sess1.Close()
assert.True(t, sess1.IsClosed())
sess2 := testEngine.Where("a = ?", 1)
sess2 := testEngine.Where("`a` = ?", 1)
sess2.Close()
assert.True(t, sess2.IsClosed())
}
@ -32,7 +32,7 @@ func TestNullFloatStruct(t *testing.T) {
}
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(MyNullFloatStruct)))
assert.NoError(t, testEngine.Sync(new(MyNullFloatStruct)))
_, err := testEngine.Insert(&MyNullFloatStruct{
Uuid: "111111",

View File

@ -37,7 +37,7 @@ func TestTransaction(t *testing.T) {
assert.NoError(t, err)
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 0).Update(&user2)
_, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err)
_, err = session.Delete(&user2)
@ -70,10 +70,10 @@ func TestCombineTransaction(t *testing.T) {
assert.NoError(t, err)
user2 := Userinfo{Username: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2)
_, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err)
_, err = session.Exec("delete from "+testEngine.TableName("userinfo", true)+" where username = ?", user2.Username)
_, err = session.Exec("delete from "+testEngine.Quote(testEngine.TableName("userinfo", true))+" where `username` = ?", user2.Username)
assert.NoError(t, err)
err = session.Commit()
@ -113,10 +113,10 @@ func TestCombineTransactionSameMapper(t *testing.T) {
assert.NoError(t, err)
user2 := Userinfo{Username: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2)
_, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err)
_, err = session.Exec("delete from "+testEngine.TableName("`Userinfo`", true)+" where `Username` = ?", user2.Username)
_, err = session.Exec("delete from "+testEngine.Quote(testEngine.TableName("Userinfo", true))+" where `Username` = ?", user2.Username)
assert.NoError(t, err)
err = session.Commit()
@ -144,7 +144,7 @@ func TestMultipleTransaction(t *testing.T) {
assert.NoError(t, err)
user2 := MultipleTransaction{Name: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2)
_, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err)
err = session.Commit()
@ -158,7 +158,7 @@ func TestMultipleTransaction(t *testing.T) {
err = session.Begin()
assert.NoError(t, err)
_, err = session.Where("id=?", m1.Id).Delete(new(MultipleTransaction))
_, err = session.Where("`id`=?", m1.Id).Delete(new(MultipleTransaction))
assert.NoError(t, err)
err = session.Commit()

View File

@ -27,7 +27,7 @@ func TestUpdateMap(t *testing.T) {
Age int
}
assert.NoError(t, testEngine.Sync2(new(UpdateTable)))
assert.NoError(t, testEngine.Sync(new(UpdateTable)))
var tb = UpdateTable{
Name: "test",
Age: 35,
@ -35,7 +35,7 @@ func TestUpdateMap(t *testing.T) {
_, err := testEngine.Insert(&tb)
assert.NoError(t, err)
cnt, err := testEngine.Table("update_table").Where("id = ?", tb.Id).Update(map[string]interface{}{
cnt, err := testEngine.Table("update_table").Where("`id` = ?", tb.Id).Update(map[string]interface{}{
"name": "test2",
"age": 36,
})
@ -78,7 +78,7 @@ func TestUpdateLimit(t *testing.T) {
Age int
}
assert.NoError(t, testEngine.Sync2(new(UpdateTable2)))
assert.NoError(t, testEngine.Sync(new(UpdateTable2)))
var tb = UpdateTable2{
Name: "test1",
Age: 35,
@ -93,7 +93,12 @@ func TestUpdateLimit(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
cnt, err = testEngine.OrderBy("name desc").Limit(1).Update(&UpdateTable2{
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
cnt, err = testEngine.OrderBy("`name` desc").Limit(1).Update(&UpdateTable2{
Age: 30,
})
assert.NoError(t, err)
@ -166,7 +171,7 @@ func TestForUpdate(t *testing.T) {
// use lock
fList := make([]ForUpdate, 0)
session1.ForUpdate()
session1.Where("id = ?", 1)
session1.Where("`id` = ?", 1)
err = session1.Find(&fList)
switch {
case err != nil:
@ -187,7 +192,7 @@ func TestForUpdate(t *testing.T) {
wg.Add(1)
go func() {
f2 := new(ForUpdate)
session2.Where("id = ?", 1).ForUpdate()
session2.Where("`id` = ?", 1).ForUpdate()
has, err := session2.Get(f2) // wait release lock
switch {
case err != nil:
@ -207,7 +212,7 @@ func TestForUpdate(t *testing.T) {
wg2.Add(1)
go func() {
f3 := new(ForUpdate)
session3.Where("id = ?", 1)
session3.Where("`id` = ?", 1)
has, err := session3.Get(f3) // wait release lock
switch {
case err != nil:
@ -225,15 +230,13 @@ func TestForUpdate(t *testing.T) {
f := new(ForUpdate)
f.Name = "updated by session1"
session1.Where("id = ?", 1)
session1.Update(f)
session1.Where("`id` = ?", 1)
_, err = session1.Update(f)
assert.NoError(t, err)
// release lock
err = session1.Commit()
if err != nil {
t.Error(err)
return
}
assert.NoError(t, err)
wg.Wait()
}
@ -248,7 +251,7 @@ func TestWithIn(t *testing.T) {
assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync(new(temp3)))
testEngine.Insert(&[]temp3{
_, err := testEngine.Insert(&[]temp3{
{
Name: "user1",
},
@ -259,6 +262,7 @@ func TestWithIn(t *testing.T) {
Name: "user1",
},
})
assert.NoError(t, err)
cnt, err := testEngine.In("Id", 1, 2, 3, 4).Update(&temp3{Name: "aa"}, &temp3{Name: "user1"})
assert.NoError(t, err)
@ -300,7 +304,7 @@ func TestUpdateMap2(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(UpdateMustCols))
_, err := testEngine.Table("update_must_cols").Where("id =?", 1).Update(map[string]interface{}{
_, err := testEngine.Table("update_must_cols").Where("`id` =?", 1).Update(map[string]interface{}{
"bool": true,
})
assert.NoError(t, err)
@ -313,6 +317,7 @@ func TestUpdate1(t *testing.T) {
_, err := testEngine.Insert(&Userinfo{
Username: "user1",
})
assert.NoError(t, err)
var ori Userinfo
has, err := testEngine.Get(&ori)
@ -345,11 +350,11 @@ func TestUpdate1(t *testing.T) {
userID := user.Uid
has, err := testEngine.ID(userID).
And("username = ?", user.Username).
And("height = ?", user.Height).
And("departname = ?", "").
And("detail_id = ?", 0).
And("is_man = ?", false).
And("`username` = ?", user.Username).
And("`height` = ?", user.Height).
And("`departname` = ?", "").
And("`detail_id` = ?", 0).
And("`is_man` = ?", false).
Get(&Userinfo{})
assert.NoError(t, err)
assert.True(t, has, "cannot insert properly")
@ -362,12 +367,12 @@ func TestUpdate1(t *testing.T) {
assert.EqualValues(t, 1, cnt, "update not returned 1")
has, err = testEngine.ID(userID).
And("username = ?", updatedUser.Username).
And("height IS NULL").
And("departname IS NULL").
And("is_man IS NULL").
And("created IS NULL").
And("detail_id = ?", 0).
And("`username` = ?", updatedUser.Username).
And("`height` IS NULL").
And("`departname` IS NULL").
And("`is_man` IS NULL").
And("`created` IS NULL").
And("`detail_id` = ?", 0).
Get(&Userinfo{})
assert.NoError(t, err)
assert.True(t, has, "cannot update with null properly")
@ -377,7 +382,7 @@ func TestUpdate1(t *testing.T) {
assert.EqualValues(t, 1, cnt, "delete not returned 1")
}
err = testEngine.StoreEngine("Innodb").Sync2(&Article{})
err = testEngine.StoreEngine("Innodb").Sync(&Article{})
assert.NoError(t, err)
defer func() {
@ -508,7 +513,7 @@ func TestUpdateUpdated(t *testing.T) {
assert.NoError(t, PrepareEngine())
di := new(UpdatedUpdate)
err := testEngine.Sync2(di)
err := testEngine.Sync(di)
assert.NoError(t, err)
_, err = testEngine.Insert(&UpdatedUpdate{})
@ -524,7 +529,7 @@ func TestUpdateUpdated(t *testing.T) {
assert.EqualValues(t, ci.Updated.Unix(), di.Updated.Unix())
di2 := new(UpdatedUpdate2)
err = testEngine.Sync2(di2)
err = testEngine.Sync(di2)
assert.NoError(t, err)
now := time.Now()
@ -551,7 +556,7 @@ func TestUpdateUpdated(t *testing.T) {
assert.True(t, ci2.Updated >= di21.Updated)
di3 := new(UpdatedUpdate3)
err = testEngine.Sync2(di3)
err = testEngine.Sync(di3)
assert.NoError(t, err)
_, err = testEngine.Insert(&UpdatedUpdate3{})
@ -567,7 +572,7 @@ func TestUpdateUpdated(t *testing.T) {
assert.EqualValues(t, ci3.Updated, di3.Updated)
di4 := new(UpdatedUpdate4)
err = testEngine.Sync2(di4)
err = testEngine.Sync(di4)
assert.NoError(t, err)
_, err = testEngine.Insert(&UpdatedUpdate4{})
@ -583,7 +588,7 @@ func TestUpdateUpdated(t *testing.T) {
assert.EqualValues(t, ci4.Updated, di4.Updated)
di5 := new(UpdatedUpdate5)
err = testEngine.Sync2(di5)
err = testEngine.Sync(di5)
assert.NoError(t, err)
_, err = testEngine.Insert(&UpdatedUpdate5{})
@ -825,7 +830,7 @@ func TestNewUpdate(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 0, af)
af, err = testEngine.Table(new(TbUserInfo)).Where("phone=?", "13126564922").Update(&changeUsr)
af, err = testEngine.Table(new(TbUserInfo)).Where("`phone`=?", "13126564922").Update(&changeUsr)
assert.NoError(t, err)
assert.EqualValues(t, 0, af)
}
@ -920,6 +925,7 @@ func TestDeletedUpdate(t *testing.T) {
var s1 DeletedUpdatedStruct
has, err := testEngine.ID(s.Id).Get(&s1)
assert.NoError(t, err)
assert.EqualValues(t, true, has)
cnt, err = testEngine.ID(s.Id).Delete(&DeletedUpdatedStruct{})
@ -936,6 +942,7 @@ func TestDeletedUpdate(t *testing.T) {
var s2 DeletedUpdatedStruct
has, err = testEngine.ID(s.Id).Get(&s2)
assert.NoError(t, err)
assert.EqualValues(t, true, has)
}
@ -1166,7 +1173,7 @@ func TestUpdateExprs(t *testing.T) {
})
assert.NoError(t, err)
_, err = testEngine.SetExpr("num_issues", "num_issues+1").AllCols().Update(&UpdateExprs{
_, err = testEngine.SetExpr("num_issues", "`num_issues`+1").AllCols().Update(&UpdateExprs{
NumIssues: 3,
Name: "lunny xiao",
})
@ -1197,7 +1204,7 @@ func TestUpdateAlias(t *testing.T) {
})
assert.NoError(t, err)
_, err = testEngine.Alias("ua").Where("ua.id = ?", 1).Update(&UpdateAlias{
_, err = testEngine.Alias("ua").Where("ua.`id` = ?", 1).Update(&UpdateAlias{
NumIssues: 2,
Name: "lunny xiao",
})
@ -1237,7 +1244,7 @@ func TestUpdateExprs2(t *testing.T) {
assert.EqualValues(t, 1, inserted)
updated, err := testEngine.
Where("repo_id = ? AND is_tag = ?", 1, false).
Where("`repo_id` = ? AND `is_tag` = ?", 1, false).
SetExpr("is_draft", true).
SetExpr("num_commits", 0).
SetExpr("sha1", "").
@ -1257,6 +1264,11 @@ func TestUpdateExprs2(t *testing.T) {
}
func TestUpdateMap3(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
assert.NoError(t, PrepareEngine())
type UpdateMapUser struct {
@ -1308,7 +1320,7 @@ func TestUpdateIgnoreOnlyFromDBFields(t *testing.T) {
assertGetRecord := func() *TestOnlyFromDBField {
var record TestOnlyFromDBField
has, err := testEngine.Where("id = ?", 1).Get(&record)
has, err := testEngine.Where("`id` = ?", 1).Get(&record)
assert.NoError(t, err)
assert.EqualValues(t, true, has)
assert.EqualValues(t, "", record.OnlyFromDBField)

View File

@ -458,7 +458,7 @@ func TestExtends5(t *testing.T) {
list := make([]Book, 0)
err = session.
Select(fmt.Sprintf(
"%s.%s, sc.%s AS %s, sc.%s AS %s, s.%s, s.%s",
"%s.%s, `sc`.%s AS %s, `sc`.%s AS %s, `s`.%s, `s`.%s",
quote(bookTableName),
quote("id"),
quote("Width"),
@ -472,12 +472,12 @@ func TestExtends5(t *testing.T) {
Join(
"LEFT",
sizeTableName+" AS `sc`",
bookTableName+".`SizeClosed`=sc.`id`",
bookTableName+".`SizeClosed`=`sc`.`id`",
).
Join(
"LEFT",
sizeTableName+" AS `s`",
bookTableName+".`Size`=s.`id`",
bookTableName+".`Size`=`s`.`id`",
).
Find(&list)
assert.NoError(t, err)
@ -673,7 +673,7 @@ func TestCreatedUpdated(t *testing.T) {
Updated time.Time `xorm:"updated"`
}
err := testEngine.Sync2(&CreatedUpdated{})
err := testEngine.Sync(&CreatedUpdated{})
assert.NoError(t, err)
c := &CreatedUpdated{Name: "test"}
@ -728,9 +728,9 @@ type Lowercase struct {
func TestLowerCase(t *testing.T) {
assert.NoError(t, PrepareEngine())
err := testEngine.Sync2(&Lowercase{})
err := testEngine.Sync(&Lowercase{})
assert.NoError(t, err)
_, err = testEngine.Where("id > 0").Delete(&Lowercase{})
_, err = testEngine.Where("`id` > 0").Delete(&Lowercase{})
assert.NoError(t, err)
_, err = testEngine.Insert(&Lowercase{ended: 1})
@ -827,7 +827,7 @@ func TestTagComment(t *testing.T) {
assert.True(t, cols[0].DefaultIsEmpty)
assert.EqualValues(t, "", cols[0].Default)
assert.NoError(t, testEngine.Sync2(new(TestComment1)))
assert.NoError(t, testEngine.Sync(new(TestComment1)))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
@ -851,7 +851,7 @@ func TestTagComment(t *testing.T) {
assert.True(t, cols[0].DefaultIsEmpty)
assert.EqualValues(t, "", cols[0].Default)
assert.NoError(t, testEngine.Sync2(new(TestComment2)))
assert.NoError(t, testEngine.Sync(new(TestComment2)))
tables, err = testEngine.DBMetas()
assert.NoError(t, err)
@ -1202,7 +1202,7 @@ func TestTagTime(t *testing.T) {
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, s.Created.UTC().Format("2006-01-02 15:04:05"),
strings.Replace(strings.Replace(tm, "T", " ", -1), "Z", "", -1))
strings.ReplaceAll(strings.ReplaceAll(tm, "T", " "), "Z", ""))
}
func TestTagAutoIncr(t *testing.T) {
@ -1287,7 +1287,7 @@ func TestVersion1(t *testing.T) {
assert.EqualValues(t, newVer.Ver, 2)
newVer = new(VersionS)
has, err = testEngine.ID(ver.Id).Get(newVer)
_, err = testEngine.ID(ver.Id).Get(newVer)
assert.NoError(t, err)
assert.EqualValues(t, newVer.Ver, 2)
}
@ -1345,7 +1345,7 @@ func TestVersion3(t *testing.T) {
assert.EqualValues(t, newVer.Ver, 2)
newVer = new(VersionUintS)
has, err = testEngine.ID(ver.Id).Get(newVer)
_, err = testEngine.ID(ver.Id).Get(newVer)
assert.NoError(t, err)
assert.EqualValues(t, newVer.Ver, 2)
}

View File

@ -51,7 +51,7 @@ func createEngine(dbType, connStr string) error {
if !*cluster {
switch schemas.DBType(strings.ToLower(dbType)) {
case schemas.MSSQL:
db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "master", -1))
db, err := sql.Open(dbType, strings.ReplaceAll(connStr, "xorm_test", "master"))
if err != nil {
return err
}
@ -61,7 +61,7 @@ func createEngine(dbType, connStr string) error {
db.Close()
*ignoreSelectUpdate = true
case schemas.POSTGRES:
db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "postgres", -1))
db, err := sql.Open(dbType, strings.ReplaceAll(connStr, "xorm_test", "postgres"))
if err != nil {
return err
}
@ -90,7 +90,7 @@ func createEngine(dbType, connStr string) error {
db.Close()
*ignoreSelectUpdate = true
case schemas.MYSQL:
db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "mysql", -1))
db, err := sql.Open(dbType, strings.ReplaceAll(connStr, "xorm_test", "mysql"))
if err != nil {
return err
}

View File

@ -324,7 +324,7 @@ func TestTimeUserDeleted(t *testing.T) {
fmt.Println("user2 str", user2.CreatedAtStr, user2.UpdatedAtStr)
var user3 UserDeleted
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
cnt, err = testEngine.Where("`id` = ?", "lunny").Delete(&user3)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.True(t, !utils.IsTimeZero(user3.DeletedAt))
@ -386,7 +386,7 @@ func TestTimeUserDeletedDiffLoc(t *testing.T) {
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
var user3 UserDeleted2
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
cnt, err = testEngine.Where("`id` = ?", "lunny").Delete(&user3)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.True(t, !utils.IsTimeZero(user3.DeletedAt))
@ -457,7 +457,7 @@ func TestCustomTimeUserDeleted(t *testing.T) {
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
var user3 UserDeleted3
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
cnt, err = testEngine.Where("`id` = ?", "lunny").Delete(&user3)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.True(t, !utils.IsTimeZero(time.Time(user3.DeletedAt)))
@ -519,7 +519,7 @@ func TestCustomTimeUserDeletedDiffLoc(t *testing.T) {
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
var user3 UserDeleted4
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
cnt, err = testEngine.Where("`id` = ?", "lunny").Delete(&user3)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.True(t, !utils.IsTimeZero(time.Time(user3.DeletedAt)))

View File

@ -15,7 +15,7 @@ import (
"github.com/stretchr/testify/assert"
)
type NullType struct {
type NullStruct struct {
Id int `xorm:"pk autoincr"`
Name sql.NullString
Age sql.NullInt64
@ -65,26 +65,26 @@ func (m CustomStruct) Value() (driver.Value, error) {
func TestCreateNullStructTable(t *testing.T) {
assert.NoError(t, PrepareEngine())
err := testEngine.CreateTables(new(NullType))
err := testEngine.CreateTables(new(NullStruct))
assert.NoError(t, err)
}
func TestDropNullStructTable(t *testing.T) {
assert.NoError(t, PrepareEngine())
err := testEngine.DropTables(new(NullType))
err := testEngine.DropTables(new(NullStruct))
assert.NoError(t, err)
}
func TestNullStructInsert(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
item1 := new(NullType)
item1 := new(NullStruct)
_, err := testEngine.Insert(item1)
assert.NoError(t, err)
assert.EqualValues(t, 1, item1.Id)
item := NullType{
item := NullStruct{
Name: sql.NullString{String: "haolei", Valid: true},
Age: sql.NullInt64{Int64: 34, Valid: true},
Height: sql.NullFloat64{Float64: 1.72, Valid: true},
@ -95,9 +95,9 @@ func TestNullStructInsert(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, 2, item.Id)
items := []NullType{}
items := []NullStruct{}
for i := 0; i < 5; i++ {
item := NullType{
item := NullStruct{
Name: sql.NullString{String: "haolei_" + fmt.Sprint(i+1), Valid: true},
Age: sql.NullInt64{Int64: 30 + int64(i), Valid: true},
Height: sql.NullFloat64{Float64: 1.5 + 1.1*float64(i), Valid: true},
@ -111,7 +111,7 @@ func TestNullStructInsert(t *testing.T) {
_, err = testEngine.Insert(&items)
assert.NoError(t, err)
items = make([]NullType, 0, 7)
items = make([]NullStruct, 0, 7)
err = testEngine.Find(&items)
assert.NoError(t, err)
assert.EqualValues(t, 7, len(items))
@ -119,9 +119,9 @@ func TestNullStructInsert(t *testing.T) {
func TestNullStructUpdate(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
_, err := testEngine.Insert([]NullType{
_, err := testEngine.Insert([]NullStruct{
{
Name: sql.NullString{
String: "name1",
@ -150,7 +150,7 @@ func TestNullStructUpdate(t *testing.T) {
assert.NoError(t, err)
if true { // 测试可插入NULL
item := new(NullType)
item := new(NullStruct)
item.Age = sql.NullInt64{Int64: 23, Valid: true}
item.Height = sql.NullFloat64{Float64: 0, Valid: false} // update to NULL
@ -160,7 +160,7 @@ func TestNullStructUpdate(t *testing.T) {
}
if true { // 测试In update
item := new(NullType)
item := new(NullStruct)
item.Age = sql.NullInt64{Int64: 23, Valid: true}
affected, err := testEngine.In("id", 3, 4).Cols("age", "height", "is_man").Update(item)
assert.NoError(t, err)
@ -168,17 +168,17 @@ func TestNullStructUpdate(t *testing.T) {
}
if true { // 测试where
item := new(NullType)
item := new(NullStruct)
item.Name = sql.NullString{String: "nullname", Valid: true}
item.IsMan = sql.NullBool{Bool: true, Valid: true}
item.Age = sql.NullInt64{Int64: 34, Valid: true}
_, err := testEngine.Where("age > ?", 34).Update(item)
_, err := testEngine.Where("`age` > ?", 34).Update(item)
assert.NoError(t, err)
}
if true { // 修改全部时,插入空值
item := &NullType{
item := &NullStruct{
Name: sql.NullString{String: "winxxp", Valid: true},
Age: sql.NullInt64{Int64: 30, Valid: true},
Height: sql.NullFloat64{Float64: 1.72, Valid: true},
@ -192,9 +192,9 @@ func TestNullStructUpdate(t *testing.T) {
func TestNullStructFind(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
_, err := testEngine.Insert([]NullType{
_, err := testEngine.Insert([]NullStruct{
{
Name: sql.NullString{
String: "name1",
@ -223,7 +223,7 @@ func TestNullStructFind(t *testing.T) {
assert.NoError(t, err)
if true {
item := new(NullType)
item := new(NullStruct)
has, err := testEngine.ID(1).Get(item)
assert.NoError(t, err)
assert.True(t, has)
@ -235,7 +235,7 @@ func TestNullStructFind(t *testing.T) {
}
if true {
item := new(NullType)
item := new(NullStruct)
item.Id = 2
has, err := testEngine.Get(item)
assert.NoError(t, err)
@ -243,13 +243,13 @@ func TestNullStructFind(t *testing.T) {
}
if true {
item := make([]NullType, 0)
item := make([]NullStruct, 0)
err := testEngine.ID(2).Find(&item)
assert.NoError(t, err)
}
if true {
item := make([]NullType, 0)
item := make([]NullStruct, 0)
err := testEngine.Asc("age").Find(&item)
assert.NoError(t, err)
}
@ -257,12 +257,12 @@ func TestNullStructFind(t *testing.T) {
func TestNullStructIterate(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
if true {
err := testEngine.Where("age IS NOT NULL").OrderBy("age").Iterate(new(NullType),
err := testEngine.Where("`age` IS NOT NULL").OrderBy("age").Iterate(new(NullStruct),
func(i int, bean interface{}) error {
nultype := bean.(*NullType)
nultype := bean.(*NullStruct)
fmt.Println(i, nultype)
return nil
})
@ -272,21 +272,21 @@ func TestNullStructIterate(t *testing.T) {
func TestNullStructCount(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
if true {
item := new(NullType)
_, err := testEngine.Where("age IS NOT NULL").Count(item)
item := new(NullStruct)
_, err := testEngine.Where("`age` IS NOT NULL").Count(item)
assert.NoError(t, err)
}
}
func TestNullStructRows(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
item := new(NullType)
rows, err := testEngine.Where("id > ?", 1).Rows(item)
item := new(NullStruct)
rows, err := testEngine.Where("`id` > ?", 1).Rows(item)
assert.NoError(t, err)
defer rows.Close()
@ -298,13 +298,13 @@ func TestNullStructRows(t *testing.T) {
func TestNullStructDelete(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(NullType))
assertSync(t, new(NullStruct))
item := new(NullType)
item := new(NullStruct)
_, err := testEngine.ID(1).Delete(item)
assert.NoError(t, err)
_, err = testEngine.Where("id > ?", 1).Delete(item)
_, err = testEngine.Where("`id` > ?", 1).Delete(item)
assert.NoError(t, err)
}

View File

@ -28,7 +28,7 @@ func TestArrayField(t *testing.T) {
Name [20]byte `xorm:"char(80)"`
}
assert.NoError(t, testEngine.Sync2(new(ArrayStruct)))
assert.NoError(t, testEngine.Sync(new(ArrayStruct)))
var as = ArrayStruct{
Name: [20]byte{
@ -90,7 +90,7 @@ func TestGetBytes(t *testing.T) {
Data []byte `xorm:"VARBINARY(250)"`
}
err := testEngine.Sync2(new(Varbinary))
err := testEngine.Sync(new(Varbinary))
assert.NoError(t, err)
cnt, err := testEngine.Insert(&Varbinary{
@ -193,7 +193,7 @@ func TestConversion(t *testing.T) {
c := new(ConvStruct)
assert.NoError(t, testEngine.DropTables(c))
assert.NoError(t, testEngine.Sync2(c))
assert.NoError(t, testEngine.Sync(c))
var s ConvString = "sssss"
c.Conv = "tttt"
@ -428,7 +428,7 @@ func TestUnsignedUint64(t *testing.T) {
assert.EqualValues(t, "INTEGER", tables[0].Columns()[0].SQLType.Name)
case schemas.MYSQL:
assert.EqualValues(t, "UNSIGNED BIGINT", tables[0].Columns()[0].SQLType.Name)
case schemas.POSTGRES:
case schemas.POSTGRES, schemas.DAMENG:
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
case schemas.MSSQL:
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
@ -472,9 +472,7 @@ func TestUnsignedUint32(t *testing.T) {
assert.EqualValues(t, "INTEGER", tables[0].Columns()[0].SQLType.Name)
case schemas.MYSQL:
assert.EqualValues(t, "UNSIGNED INT", tables[0].Columns()[0].SQLType.Name)
case schemas.POSTGRES:
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
case schemas.MSSQL:
case schemas.POSTGRES, schemas.MSSQL, schemas.DAMENG:
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
default:
assert.False(t, true, "Unsigned is not implemented")
@ -507,7 +505,7 @@ func TestUnsignedTinyInt(t *testing.T) {
assert.EqualValues(t, 1, len(tables[0].Columns()))
switch testEngine.Dialect().URI().DBType {
case schemas.SQLITE:
case schemas.SQLITE, schemas.DAMENG:
assert.EqualValues(t, "INTEGER", tables[0].Columns()[0].SQLType.Name)
case schemas.MYSQL:
assert.EqualValues(t, "UNSIGNED TINYINT", tables[0].Columns()[0].SQLType.Name)
@ -516,7 +514,7 @@ func TestUnsignedTinyInt(t *testing.T) {
case schemas.MSSQL:
assert.EqualValues(t, "INT", tables[0].Columns()[0].SQLType.Name)
default:
assert.False(t, true, "Unsigned is not implemented")
assert.False(t, true, fmt.Sprintf("Unsigned is not implemented, returned %s", tables[0].Columns()[0].SQLType.Name))
}
cnt, err := testEngine.Insert(&MyUnsignedTinyIntStruct{

View File

@ -37,7 +37,7 @@ type Interface interface {
Exist(bean ...interface{}) (bool, error)
Find(interface{}, ...interface{}) error
FindAndCount(interface{}, ...interface{}) (int64, error)
Get(interface{}) (bool, error)
Get(...interface{}) (bool, error)
GroupBy(keys string) *Session
ID(interface{}) *Session
In(string, ...interface{}) *Session
@ -99,6 +99,7 @@ type EngineInterface interface {
MapCacher(interface{}, caches.Cacher) error
NewSession() *Session
NoAutoTime() *Session
Prepare() *Session
Quote(string) string
SetCacher(string, caches.Cacher)
SetConnMaxLifetime(time.Duration)

View File

@ -10,6 +10,7 @@ import (
"strings"
"xorm.io/builder"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas"
)
@ -42,7 +43,19 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err
}
if len(colNames) <= 0 {
var hasInsertColumns = len(colNames) > 0
var needSeq = len(table.AutoIncrement) > 0 && (statement.dialect.URI().DBType == schemas.ORACLE || statement.dialect.URI().DBType == schemas.DAMENG)
if needSeq {
for _, col := range colNames {
if strings.EqualFold(col, table.AutoIncrement) {
needSeq = false
break
}
}
}
if !hasInsertColumns && statement.dialect.URI().DBType != schemas.ORACLE &&
statement.dialect.URI().DBType != schemas.DAMENG {
if statement.dialect.URI().DBType == schemas.MYSQL {
if _, err := buf.WriteString(" VALUES ()"); err != nil {
return "", nil, err
@ -60,6 +73,10 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err
}
if needSeq {
colNames = append(colNames, table.AutoIncrement)
}
if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames()...), ","); err != nil {
return "", nil, err
}
@ -80,13 +97,23 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err
}
if needSeq {
if len(args) > 0 {
if _, err := buf.WriteString(","); err != nil {
return "", nil, err
}
}
if _, err := buf.WriteString(utils.SeqName(tableName) + ".nextval"); err != nil {
return "", nil, err
}
}
if len(exprs) > 0 {
if _, err := buf.WriteString(","); err != nil {
return "", nil, err
}
}
if err := exprs.WriteArgs(buf); err != nil {
return "", nil, err
if err := exprs.WriteArgs(buf); err != nil {
return "", nil, err
}
}
if _, err := buf.WriteString(" FROM "); err != nil {
@ -113,6 +140,18 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err
}
// Insert tablename (id) Values(seq_tablename.nextval)
if needSeq {
if hasInsertColumns {
if _, err := buf.WriteString(","); err != nil {
return "", nil, err
}
}
if _, err := buf.WriteString(utils.SeqName(tableName) + ".nextval"); err != nil {
return "", nil, err
}
}
if len(exprs) > 0 {
if _, err := buf.WriteString(","); err != nil {
return "", nil, err

View File

@ -79,7 +79,9 @@ func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (stri
return statement.GenRawSQL(), statement.RawParams, nil
}
statement.SetRefBean(bean)
if err := statement.SetRefBean(bean); err != nil {
return "", nil, err
}
var sumStrs = make([]string, 0, len(columns))
for _, colName := range columns {
@ -111,7 +113,9 @@ func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{},
v := rValue(bean)
isStruct = v.Kind() == reflect.Struct
if isStruct {
statement.SetRefBean(bean)
if err := statement.SetRefBean(bean); err != nil {
return "", nil, err
}
}
}
@ -168,7 +172,9 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa
var condArgs []interface{}
var err error
if len(beans) > 0 {
statement.SetRefBean(beans[0])
if err := statement.SetRefBean(beans[0]); err != nil {
return "", nil, err
}
if err := statement.mergeConds(beans[0]); err != nil {
return "", nil, err
}
@ -203,14 +209,42 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa
return sqlStr, append(statement.joinArgs, condArgs...), nil
}
func (statement *Statement) fromBuilder() *strings.Builder {
var builder strings.Builder
var quote = statement.quote
var dialect = statement.dialect
builder.WriteString(" FROM ")
if dialect.URI().DBType == schemas.MSSQL && strings.Contains(statement.TableName(), "..") {
builder.WriteString(statement.TableName())
} else {
builder.WriteString(quote(statement.TableName()))
}
if statement.TableAlias != "" {
if dialect.URI().DBType == schemas.ORACLE {
builder.WriteString(" ")
} else {
builder.WriteString(" AS ")
}
builder.WriteString(quote(statement.TableAlias))
}
if statement.JoinStr != "" {
builder.WriteString(" ")
builder.WriteString(statement.JoinStr)
}
return &builder
}
func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderBy bool) (string, []interface{}, error) {
var (
distinct string
dialect = statement.dialect
quote = statement.quote
fromStr = " FROM "
fromStr = statement.fromBuilder().String()
top, mssqlCondi, whereStr string
)
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
distinct = "DISTINCT "
}
@ -220,24 +254,7 @@ func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderB
return "", nil, err
}
if len(condSQL) > 0 {
whereStr = " WHERE " + condSQL
}
if dialect.URI().DBType == schemas.MSSQL && strings.Contains(statement.TableName(), "..") {
fromStr += statement.TableName()
} else {
fromStr += quote(statement.TableName())
}
if statement.TableAlias != "" {
if dialect.URI().DBType == schemas.ORACLE {
fromStr += " " + quote(statement.TableAlias)
} else {
fromStr += " AS " + quote(statement.TableAlias)
}
}
if statement.JoinStr != "" {
fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
whereStr = fmt.Sprintf(" WHERE %s", condSQL)
}
pLimitN := statement.LimitN
@ -266,20 +283,20 @@ func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderB
}
if statement.needTableName() {
if len(statement.TableAlias) > 0 {
column = statement.TableAlias + "." + column
column = fmt.Sprintf("%s.%s", statement.TableAlias, column)
} else {
column = statement.TableName() + "." + column
column = fmt.Sprintf("%s.%s", statement.TableName(), column)
}
}
var orderStr string
if needOrderBy && len(statement.OrderStr) > 0 {
orderStr = " ORDER BY " + statement.OrderStr
orderStr = fmt.Sprintf(" ORDER BY %s", statement.OrderStr)
}
var groupStr string
if len(statement.GroupByStr) > 0 {
groupStr = " GROUP BY " + statement.GroupByStr
groupStr = fmt.Sprintf(" GROUP BY %s", statement.GroupByStr)
}
mssqlCondi = fmt.Sprintf("(%s NOT IN (SELECT TOP %d %s%s%s%s%s))",
column, statement.Start, column, fromStr, whereStr, orderStr, groupStr)
@ -311,13 +328,13 @@ func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderB
if pLimitN != nil {
fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", *pLimitN, statement.Start)
} else {
fmt.Fprintf(&buf, "LIMIT 0 OFFSET %v", statement.Start)
fmt.Fprintf(&buf, " LIMIT 0 OFFSET %v", statement.Start)
}
} else if pLimitN != nil {
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
@ -381,7 +398,7 @@ func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interfac
} else if statement.dialect.URI().DBType == schemas.ORACLE {
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) %s AND ROWNUM=1", tableName, joinStr, condSQL)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE %s LIMIT 1", tableName, joinStr, condSQL)
sqlStr = fmt.Sprintf("SELECT 1 FROM %s %s WHERE %s LIMIT 1", tableName, joinStr, condSQL)
}
args = condArgs
} else {
@ -390,7 +407,7 @@ func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interfac
} else if statement.dialect.URI().DBType == schemas.ORACLE {
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE ROWNUM=1", tableName, joinStr)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s %s LIMIT 1", tableName, joinStr)
sqlStr = fmt.Sprintf("SELECT 1 FROM %s %s LIMIT 1", tableName, joinStr)
}
args = []interface{}{}
}

View File

@ -308,7 +308,7 @@ func (statement *Statement) colName(col *schemas.Column, tableName string) strin
if len(statement.TableAlias) > 0 {
nm = statement.TableAlias
}
return statement.quote(nm) + "." + statement.quote(col.Name)
return fmt.Sprintf("%s.%s", statement.quote(nm), statement.quote(col.Name))
}
return statement.quote(col.Name)
}
@ -473,7 +473,7 @@ func (statement *Statement) Desc(colNames ...string) *Statement {
if i > 0 {
fmt.Fprint(&buf, ", ")
}
statement.dialect.Quoter().QuoteTo(&buf, col)
_ = statement.dialect.Quoter().QuoteTo(&buf, col)
fmt.Fprint(&buf, " DESC")
}
statement.OrderStr = buf.String()
@ -490,7 +490,7 @@ func (statement *Statement) Asc(colNames ...string) *Statement {
if i > 0 {
fmt.Fprint(&buf, ", ")
}
statement.dialect.Quoter().QuoteTo(&buf, col)
_ = statement.dialect.Quoter().QuoteTo(&buf, col)
fmt.Fprint(&buf, " ASC")
}
statement.OrderStr = buf.String()
@ -539,7 +539,7 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
aliasName = schemas.CommonQuoter.Trim(aliasName)
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), statement.quote(aliasName), statement.ReplaceQuote(condition))
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
case *builder.Builder:
subSQL, subQueryArgs, err := tp.ToSQL()
@ -552,14 +552,16 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
aliasName = schemas.CommonQuoter.Trim(aliasName)
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), statement.quote(aliasName), statement.ReplaceQuote(condition))
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
default:
tbName := dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tablename, true)
if !utils.IsSubQuery(tbName) {
var buf strings.Builder
statement.dialect.Quoter().QuoteTo(&buf, tbName)
_ = statement.dialect.Quoter().QuoteTo(&buf, tbName)
tbName = buf.String()
} else {
tbName = statement.ReplaceQuote(tbName)
}
fmt.Fprintf(&buf, "%s ON %v", tbName, statement.ReplaceQuote(condition))
}
@ -569,15 +571,6 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
return statement
}
// tbNameNoSchema get some table's table name
func (statement *Statement) tbNameNoSchema(table *schemas.Table) string {
if len(statement.AltTableName) > 0 {
return statement.AltTableName
}
return table.Name
}
// GroupBy generate "Group By keys" statement
func (statement *Statement) GroupBy(keys string) *Statement {
statement.GroupByStr = statement.ReplaceQuote(keys)
@ -642,14 +635,6 @@ func (statement *Statement) genColumnStr() string {
return buf.String()
}
// GenCreateTableSQL generated create table SQL
func (statement *Statement) GenCreateTableSQL() []string {
statement.RefTable.StoreEngine = statement.StoreEngine
statement.RefTable.Charset = statement.Charset
s, _ := statement.dialect.CreateTableSQL(statement.RefTable, statement.TableName())
return s
}
// GenIndexSQL generated create index SQL
func (statement *Statement) GenIndexSQL() []string {
var sqls []string
@ -863,9 +848,6 @@ func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
if !strings.Contains(err.Error(), "is not valid") {
//engine.logger.Warn(err)
}
continue
} else if fieldValuePtr == nil {
continue
@ -968,9 +950,9 @@ func (statement *Statement) convertSQLOrArgs(sqlOrArgs ...interface{}) (string,
if len(sqlOrArgs) > 1 {
var newArgs = make([]interface{}, 0, len(sqlOrArgs)-1)
for _, arg := range sqlOrArgs[1:] {
if v, ok := arg.(*time.Time); ok {
if v, ok := arg.(time.Time); ok {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(time.Time); ok {
} else if v, ok := arg.(*time.Time); ok && v != nil {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else {
newArgs = append(newArgs, arg)

View File

@ -5,6 +5,7 @@
package statements
import (
"os"
"reflect"
"strings"
"testing"
@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
panic("tags parser is nil")
}
m.Run()
os.Exit(0)
}
var colStrTests = []struct {
@ -77,6 +79,23 @@ func TestColumnsStringGeneration(t *testing.T) {
}
}
func TestConvertSQLOrArgs(t *testing.T) {
statement, err := createTestStatement()
assert.NoError(t, err)
// example orm struct
// type Table struct {
// ID int
// del *time.Time `xorm:"deleted"`
// }
args := []interface{}{
"INSERT `table` (`id`, `del`) VALUES (?, ?)", 1, (*time.Time)(nil),
}
// before fix, here will panic
_, _, err = statement.convertSQLOrArgs(args...)
assert.NoError(t, err)
}
func BenchmarkGetFlagForColumnWithICKey_ContainsKey(b *testing.B) {
b.StopTimer()

View File

@ -6,9 +6,15 @@ package utils
import (
"fmt"
"strings"
)
// IndexName returns index name
func IndexName(tableName, idxName string) string {
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
}
// SeqName returns sequence name for some table
func SeqName(tableName string) string {
return "SEQ_" + strings.ToUpper(tableName)
}

View File

@ -11,8 +11,8 @@ func SliceEq(left, right []string) bool {
if len(left) != len(right) {
return false
}
sort.Sort(sort.StringSlice(left))
sort.Sort(sort.StringSlice(right))
sort.Strings(left)
sort.Strings(right)
for i := 0; i < len(left); i++ {
if left[i] != right[i] {
return false
@ -20,3 +20,13 @@ func SliceEq(left, right []string) bool {
}
return true
}
// IndexSlice search c in slice s and return the index, return -1 if s don't contain c
func IndexSlice(s []string, c string) int {
for i, ss := range s {
if c == ss {
return i
}
}
return -1
}

View File

@ -130,56 +130,56 @@ func NewSimpleLogger3(out io.Writer, prefix string, flag int, l LogLevel) *Simpl
// Error implement ILogger
func (s *SimpleLogger) Error(v ...interface{}) {
if s.level <= LOG_ERR {
s.ERR.Output(2, fmt.Sprintln(v...))
_ = s.ERR.Output(2, fmt.Sprintln(v...))
}
}
// Errorf implement ILogger
func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
if s.level <= LOG_ERR {
s.ERR.Output(2, fmt.Sprintf(format, v...))
_ = s.ERR.Output(2, fmt.Sprintf(format, v...))
}
}
// Debug implement ILogger
func (s *SimpleLogger) Debug(v ...interface{}) {
if s.level <= LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprintln(v...))
_ = s.DEBUG.Output(2, fmt.Sprintln(v...))
}
}
// Debugf implement ILogger
func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
if s.level <= LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprintf(format, v...))
_ = s.DEBUG.Output(2, fmt.Sprintf(format, v...))
}
}
// Info implement ILogger
func (s *SimpleLogger) Info(v ...interface{}) {
if s.level <= LOG_INFO {
s.INFO.Output(2, fmt.Sprintln(v...))
_ = s.INFO.Output(2, fmt.Sprintln(v...))
}
}
// Infof implement ILogger
func (s *SimpleLogger) Infof(format string, v ...interface{}) {
if s.level <= LOG_INFO {
s.INFO.Output(2, fmt.Sprintf(format, v...))
_ = s.INFO.Output(2, fmt.Sprintf(format, v...))
}
}
// Warn implement ILogger
func (s *SimpleLogger) Warn(v ...interface{}) {
if s.level <= LOG_WARNING {
s.WARN.Output(2, fmt.Sprintln(v...))
_ = s.WARN.Output(2, fmt.Sprintln(v...))
}
}
// Warnf implement ILogger
func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
if s.level <= LOG_WARNING {
s.WARN.Output(2, fmt.Sprintf(format, v...))
_ = s.WARN.Output(2, fmt.Sprintf(format, v...))
}
}

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !windows && !nacl && !plan9
// +build !windows,!nacl,!plan9
package log
@ -26,42 +27,42 @@ func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
// Debug log content as Debug
func (s *SyslogLogger) Debug(v ...interface{}) {
s.w.Debug(fmt.Sprint(v...))
_ = s.w.Debug(fmt.Sprint(v...))
}
// Debugf log content as Debug and format
func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
s.w.Debug(fmt.Sprintf(format, v...))
_ = s.w.Debug(fmt.Sprintf(format, v...))
}
// Error log content as Error
func (s *SyslogLogger) Error(v ...interface{}) {
s.w.Err(fmt.Sprint(v...))
_ = s.w.Err(fmt.Sprint(v...))
}
// Errorf log content as Errorf and format
func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
s.w.Err(fmt.Sprintf(format, v...))
_ = s.w.Err(fmt.Sprintf(format, v...))
}
// Info log content as Info
func (s *SyslogLogger) Info(v ...interface{}) {
s.w.Info(fmt.Sprint(v...))
_ = s.w.Info(fmt.Sprint(v...))
}
// Infof log content as Infof and format
func (s *SyslogLogger) Infof(format string, v ...interface{}) {
s.w.Info(fmt.Sprintf(format, v...))
_ = s.w.Info(fmt.Sprintf(format, v...))
}
// Warn log content as Warn
func (s *SyslogLogger) Warn(v ...interface{}) {
s.w.Warning(fmt.Sprint(v...))
_ = s.w.Warning(fmt.Sprint(v...))
}
// Warnf log content as Warnf and format
func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
s.w.Warning(fmt.Sprintf(format, v...))
_ = s.w.Warning(fmt.Sprintf(format, v...))
}
// Level shows log level

View File

@ -203,7 +203,7 @@ func (m *Migrate) migrationDidRun(mig *Migration) (bool, error) {
func (m *Migrate) isFirstRun() bool {
row := m.db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s", m.options.TableName))
var count int
row.Scan(&count)
_ = row.Scan(&count)
return count == 0
}

View File

@ -31,7 +31,7 @@ var (
{
ID: "201608301400",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(&Person{})
return tx.Sync(&Person{})
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&Person{})
@ -40,7 +40,7 @@ var (
{
ID: "201608301430",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(&Pet{})
return tx.Sync(&Pet{})
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&Pet{})
@ -103,10 +103,10 @@ func TestInitSchema(t *testing.T) {
m := New(db, DefaultOptions, migrations)
m.InitSchema(func(tx *xorm.Engine) error {
if err := tx.Sync2(&Person{}); err != nil {
if err := tx.Sync(&Person{}); err != nil {
return err
}
return tx.Sync2(&Pet{})
return tx.Sync(&Pet{})
})
err = m.Migrate()
@ -142,6 +142,6 @@ func TestMissingID(t *testing.T) {
func tableCount(db *xorm.Engine, tableName string) (count int) {
row := db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName))
row.Scan(&count)
_ = row.Scan(&count)
return
}

View File

@ -14,9 +14,15 @@ type TableName interface {
TableName() string
}
type TableComment interface {
TableComment() string
}
var (
tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
tvCache sync.Map
tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
tpTableComment = reflect.TypeOf((*TableComment)(nil)).Elem()
tvCache sync.Map
tcCache sync.Map
)
// GetTableName returns table name
@ -55,3 +61,40 @@ func GetTableName(mapper Mapper, v reflect.Value) string {
return mapper.Obj2Table(v.Type().Name())
}
// GetTableComment returns table comment
func GetTableComment(v reflect.Value) string {
if v.Type().Implements(tpTableComment) {
return v.Interface().(TableComment).TableComment()
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
if v.Type().Implements(tpTableComment) {
return v.Interface().(TableComment).TableComment()
}
} else if v.CanAddr() {
v1 := v.Addr()
if v1.Type().Implements(tpTableComment) {
return v1.Interface().(TableComment).TableComment()
}
} else {
comment, ok := tcCache.Load(v.Type())
if ok {
if comment.(string) != "" {
return comment.(string)
}
} else {
v2 := reflect.New(v.Type())
if v2.Type().Implements(tpTableComment) {
tableComment := v2.Interface().(TableComment).TableComment()
tcCache.Store(v.Type(), tableComment)
return tableComment
}
tcCache.Store(v.Type(), "")
}
}
return ""
}

43
rows.go
View File

@ -11,7 +11,6 @@ import (
"xorm.io/builder"
"xorm.io/xorm/core"
"xorm.io/xorm/internal/utils"
)
// Rows rows wrapper a rows to
@ -41,7 +40,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
return nil, err
}
if len(session.statement.TableName()) <= 0 {
if len(session.statement.TableName()) == 0 {
return nil, ErrTableNotFound
}
@ -84,26 +83,41 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
// Next move cursor to next record, return false if end has reached
func (rows *Rows) Next() bool {
return rows.rows.Next()
if rows.rows != nil {
return rows.rows.Next()
}
return false
}
// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
func (rows *Rows) Err() error {
return rows.rows.Err()
if rows.rows != nil {
return rows.rows.Err()
}
return nil
}
// Scan row record to bean properties
func (rows *Rows) Scan(bean interface{}) error {
func (rows *Rows) Scan(beans ...interface{}) error {
if rows.Err() != nil {
return rows.Err()
}
if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
var bean = beans[0]
var tp = reflect.TypeOf(bean)
if tp.Kind() == reflect.Ptr {
tp = tp.Elem()
}
var beanKind = tp.Kind()
if err := rows.session.statement.SetRefBean(bean); err != nil {
return err
if len(beans) == 1 {
if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
}
if err := rows.session.statement.SetRefBean(bean); err != nil {
return err
}
}
fields, err := rows.rows.Columns()
@ -115,14 +129,7 @@ func (rows *Rows) Scan(bean interface{}) error {
return err
}
scanResults, err := rows.session.row2Slice(rows.rows, fields, types, bean)
if err != nil {
return err
}
dataStruct := utils.ReflectValue(bean)
_, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
if err != nil {
if err := rows.session.scan(rows.rows, rows.session.statement.RefTable, beanKind, beans, types, fields); err != nil {
return err
}
@ -139,5 +146,5 @@ func (rows *Rows) Close() error {
return rows.rows.Close()
}
return rows.Err()
return nil
}

291
scan.go
View File

@ -129,57 +129,6 @@ func genScanResultsByBean(bean interface{}) (interface{}, bool, error) {
}
}
func (engine *Engine) row2mapStr(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]string, error) {
var scanResults = make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var s sql.NullString
scanResults[i] = &s
}
if err := rows.Scan(scanResults...); err != nil {
return nil, err
}
result := make(map[string]string, len(fields))
for i, key := range fields {
s := scanResults[i].(*sql.NullString)
if s.String == "" {
result[key] = ""
continue
}
if schemas.TIME_TYPE == engine.dialect.ColumnTypeKind(types[i].DatabaseTypeName()) {
t, err := convert.String2Time(s.String, engine.DatabaseTZ, engine.TZLocation)
if err != nil {
return nil, err
}
result[key] = t.Format("2006-01-02 15:04:05")
} else {
result[key] = s.String
}
}
return result, nil
}
func row2mapBytes(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string][]byte, error) {
var scanResults = make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var s sql.NullString
scanResults[i] = &s
}
if err := rows.Scan(scanResults...); err != nil {
return nil, err
}
result := make(map[string][]byte, len(fields))
for ii, key := range fields {
s := scanResults[ii].(*sql.NullString)
result[key] = []byte(s.String)
}
return result, nil
}
func (engine *Engine) scanStringInterface(rows *core.Rows, fields []string, types []*sql.ColumnType) ([]interface{}, error) {
var scanResults = make([]interface{}, len(types))
for i := 0; i < len(types); i++ {
@ -259,41 +208,8 @@ func (engine *Engine) scanInterfaces(rows *core.Rows, fields []string, types []*
return scanResultContainers, nil
}
func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) {
scanResults, err := engine.scanStringInterface(rows, fields, types)
if err != nil {
return nil, err
}
var results = make([]string, 0, len(fields))
for i := 0; i < len(fields); i++ {
results = append(results, scanResults[i].(*sql.NullString).String)
}
return results, nil
}
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := row2mapBytes(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
////////////////////
// row -> map[string]interface{}
func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]interface{}, error) {
var resultsMap = make(map[string]interface{}, len(fields))
@ -318,3 +234,206 @@ func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType,
}
return resultsMap, nil
}
// ScanInterfaceMap scan result from *core.Rows and return a map
func (engine *Engine) ScanInterfaceMap(rows *core.Rows) (map[string]interface{}, error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
return engine.row2mapInterface(rows, types, fields)
}
// ScanInterfaceMaps scan results from *core.Rows and return a slice of map
func (engine *Engine) ScanInterfaceMaps(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := engine.row2mapInterface(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
////////////////////
// row -> map[string]string
func (engine *Engine) row2mapStr(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]string, error) {
var scanResults = make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var s sql.NullString
scanResults[i] = &s
}
if err := engine.driver.Scan(&dialects.ScanContext{
DBLocation: engine.DatabaseTZ,
UserLocation: engine.TZLocation,
}, rows, types, scanResults...); err != nil {
return nil, err
}
result := make(map[string]string, len(fields))
for i, key := range fields {
s := scanResults[i].(*sql.NullString)
if s.String == "" {
result[key] = ""
continue
}
if schemas.TIME_TYPE == engine.dialect.ColumnTypeKind(types[i].DatabaseTypeName()) {
t, err := convert.String2Time(s.String, engine.DatabaseTZ, engine.TZLocation)
if err != nil {
return nil, err
}
result[key] = t.Format("2006-01-02 15:04:05")
} else {
result[key] = s.String
}
}
return result, nil
}
// ScanStringMap scan results from *core.Rows and return a map
func (engine *Engine) ScanStringMap(rows *core.Rows) (map[string]string, error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
return engine.row2mapStr(rows, types, fields)
}
// ScanStringMaps scan results from *core.Rows and return a slice of map
func (engine *Engine) ScanStringMaps(rows *core.Rows) (resultsSlice []map[string]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := engine.row2mapStr(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
////////////////////
// row -> map[string][]byte
func convertMapStr2Bytes(m map[string]string) map[string][]byte {
var r = make(map[string][]byte, len(m))
for k, v := range m {
r[k] = []byte(v)
}
return r
}
func (engine *Engine) scanByteMaps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := engine.row2mapStr(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, convertMapStr2Bytes(result))
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
////////////////////
// row -> []string
func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) {
scanResults, err := engine.scanStringInterface(rows, fields, types)
if err != nil {
return nil, err
}
var results = make([]string, 0, len(fields))
for i := 0; i < len(fields); i++ {
results = append(results, scanResults[i].(*sql.NullString).String)
}
return results, nil
}
// ScanStringSlice scan results from *core.Rows and return a slice of one row
func (engine *Engine) ScanStringSlice(rows *core.Rows) ([]string, error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
return engine.row2sliceStr(rows, types, fields)
}
// ScanStringSlices scan results from *core.Rows and return a slice of all rows
func (engine *Engine) ScanStringSlices(rows *core.Rows) (resultsSlice [][]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
record, err := engine.row2sliceStr(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, record)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}

View File

@ -32,7 +32,7 @@ func NewIndex(name string, indexType int) *Index {
func (index *Index) XName(tableName string) string {
if !strings.HasPrefix(index.Name, "UQE_") &&
!strings.HasPrefix(index.Name, "IDX_") {
tableParts := strings.Split(strings.Replace(tableName, `"`, "", -1), ".")
tableParts := strings.Split(strings.ReplaceAll(tableName, `"`, ""), ".")
tableName = tableParts[len(tableParts)-1]
if index.Type == UniqueType {
return fmt.Sprintf("UQE_%v_%v", tableName, index.Name)

View File

@ -37,7 +37,7 @@ func (q Quoter) IsEmpty() bool {
// Quote quote a string
func (q Quoter) Quote(s string) string {
var buf strings.Builder
q.QuoteTo(&buf, s)
_ = q.QuoteTo(&buf, s)
return buf.String()
}
@ -64,7 +64,7 @@ func (q Quoter) Trim(s string) string {
// Join joins a slice with quoters
func (q Quoter) Join(a []string, sep string) string {
var b strings.Builder
q.JoinWrite(&b, a, sep)
_ = q.JoinWrite(&b, a, sep)
return b.String()
}
@ -86,7 +86,9 @@ func (q Quoter) JoinWrite(b *strings.Builder, a []string, sep string) error {
return err
}
}
q.QuoteTo(b, strings.TrimSpace(s))
if err := q.QuoteTo(b, strings.TrimSpace(s)); err != nil {
return err
}
}
return nil
}
@ -121,7 +123,7 @@ func findStart(value string, start int) int {
}
if (value[k] == 'A' || value[k] == 'a') && (value[k+1] == 'S' || value[k+1] == 's') {
k = k + 2
k += 2
}
for j := k; j < len(value); j++ {

View File

@ -45,7 +45,8 @@ func TestAlwaysQuoteTo(t *testing.T) {
for _, v := range kases {
t.Run(v.value, func(t *testing.T) {
buf := &strings.Builder{}
quoter.QuoteTo(buf, v.value)
err := quoter.QuoteTo(buf, v.value)
assert.NoError(t, err)
assert.EqualValues(t, v.expected, buf.String())
})
}
@ -54,10 +55,7 @@ func TestAlwaysQuoteTo(t *testing.T) {
func TestReversedQuoteTo(t *testing.T) {
var (
quoter = Quoter{'[', ']', func(s string) bool {
if s == "mytable" {
return true
}
return false
return s == "mytable"
}}
kases = []struct {
expected string
@ -118,7 +116,8 @@ func TestNoQuoteTo(t *testing.T) {
for _, v := range kases {
t.Run(v.value, func(t *testing.T) {
buf := &strings.Builder{}
quoter.QuoteTo(buf, v.value)
err := quoter.QuoteTo(buf, v.value)
assert.NoError(t, err)
assert.EqualValues(t, v.expected, buf.String())
})
}
@ -176,6 +175,10 @@ func TestReplace(t *testing.T) {
"UPDATE table SET `a` = ~ `a`, `b`='abc`'",
"UPDATE table SET [a] = ~ [a], [b]='abc`'",
},
{
"INSERT INTO `insert_where` (`height`,`name`,`repo_id`,`width`,`index`) SELECT $1,$2,$3,$4,coalesce(MAX(`index`),0)+1 FROM `insert_where` WHERE (`repo_id`=$5)",
"INSERT INTO [insert_where] ([height],[name],[repo_id],[width],[index]) SELECT $1,$2,$3,$4,coalesce(MAX([index]),0)+1 FROM [insert_where] WHERE ([repo_id]=$5)",
},
}
for _, kase := range kases {

View File

@ -22,6 +22,7 @@ const (
MYSQL DBType = "mysql"
MSSQL DBType = "mssql"
ORACLE DBType = "oracle"
DAMENG DBType = "dameng"
)
// SQLType represents SQL types
@ -105,12 +106,14 @@ var (
Integer = "INTEGER"
BigInt = "BIGINT"
UnsignedBigInt = "UNSIGNED BIGINT"
Number = "NUMBER"
Enum = "ENUM"
Set = "SET"
Char = "CHAR"
Varchar = "VARCHAR"
VARCHAR2 = "VARCHAR2"
NChar = "NCHAR"
NVarchar = "NVARCHAR"
TinyText = "TINYTEXT"
@ -174,6 +177,7 @@ var (
Integer: NUMERIC_TYPE,
BigInt: NUMERIC_TYPE,
UnsignedBigInt: NUMERIC_TYPE,
Number: NUMERIC_TYPE,
Enum: TEXT_TYPE,
Set: TEXT_TYPE,
@ -185,6 +189,7 @@ var (
Char: TEXT_TYPE,
NChar: TEXT_TYPE,
Varchar: TEXT_TYPE,
VARCHAR2: TEXT_TYPE,
NVarchar: TEXT_TYPE,
TinyText: TEXT_TYPE,
Text: TEXT_TYPE,
@ -327,6 +332,10 @@ func SQLType2Type(st SQLType) reflect.Type {
return IntType
case BigInt, BigSerial:
return Int64Type
case UnsignedBit, UnsignedTinyInt, UnsignedSmallInt, UnsignedMediumInt, UnsignedInt:
return UintType
case UnsignedBigInt:
return Uint64Type
case Float, Real:
return Float32Type
case Double:

View File

@ -79,7 +79,8 @@ type Session struct {
afterClosures []func(interface{})
afterProcessors []executedProcessor
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
txStmtCache map[uint32]*core.Stmt // for tx statement
lastSQL string
lastSQLArgs []interface{}
@ -123,13 +124,14 @@ func newSession(engine *Engine) *Session {
autoResetStatement: true,
prepareStmt: false,
afterInsertBeans: make(map[interface{}]*[]func(interface{}), 0),
afterUpdateBeans: make(map[interface{}]*[]func(interface{}), 0),
afterDeleteBeans: make(map[interface{}]*[]func(interface{}), 0),
afterInsertBeans: make(map[interface{}]*[]func(interface{})),
afterUpdateBeans: make(map[interface{}]*[]func(interface{})),
afterDeleteBeans: make(map[interface{}]*[]func(interface{})),
beforeClosures: make([]func(interface{}), 0),
afterClosures: make([]func(interface{}), 0),
afterProcessors: make([]executedProcessor, 0),
stmtCache: make(map[uint32]*core.Stmt),
txStmtCache: make(map[uint32]*core.Stmt),
lastSQL: "",
lastSQLArgs: make([]interface{}, 0),
@ -150,6 +152,12 @@ func (session *Session) Close() error {
}
}
for _, v := range session.txStmtCache {
if err := v.Close(); err != nil {
return err
}
}
if !session.isClosed {
// When Close be called, if session is a transaction and do not call
// Commit or Rollback, then call Rollback.
@ -160,6 +168,7 @@ func (session *Session) Close() error {
}
session.tx = nil
session.stmtCache = nil
session.txStmtCache = nil
session.isClosed = true
}
return nil
@ -174,6 +183,11 @@ func (session *Session) Engine() *Engine {
return session.engine
}
// Tx returns session tx
func (session *Session) Tx() *core.Tx {
return session.tx
}
func (session *Session) getQueryer() core.Queryer {
if session.tx != nil {
return session.tx
@ -195,6 +209,7 @@ func (session *Session) IsClosed() bool {
func (session *Session) resetStatement() {
if session.autoResetStatement {
session.statement.Reset()
session.prepareStmt = false
}
}
@ -365,7 +380,22 @@ func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt,
return
}
func (session *Session) getField(dataStruct *reflect.Value, table *schemas.Table, colName string, idx int) (*schemas.Column, *reflect.Value, error) {
func (session *Session) doPrepareTx(sqlStr string) (stmt *core.Stmt, err error) {
crc := crc32.ChecksumIEEE([]byte(sqlStr))
// TODO try hash(sqlStr+len(sqlStr))
var has bool
stmt, has = session.txStmtCache[crc]
if !has {
stmt, err = session.tx.PrepareContext(session.ctx, sqlStr)
if err != nil {
return nil, err
}
session.txStmtCache[crc] = stmt
}
return
}
func getField(dataStruct *reflect.Value, table *schemas.Table, colName string, idx int) (*schemas.Column, *reflect.Value, error) {
var col = table.GetColumnIdx(colName, idx)
if col == nil {
return nil, nil, ErrFieldIsNotExist{colName, table.Name}
@ -435,7 +465,7 @@ func (session *Session) row2Slice(rows *core.Rows, fields []string, types []*sql
return scanResults, nil
}
func (session *Session) setJSON(fieldValue *reflect.Value, fieldType reflect.Type, scanResult interface{}) error {
func setJSON(fieldValue *reflect.Value, fieldType reflect.Type, scanResult interface{}) error {
bs, ok := convert.AsBytes(scanResult)
if !ok {
return fmt.Errorf("unsupported database data type: %#v", scanResult)
@ -519,6 +549,9 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
if !ok {
return fmt.Errorf("cannot convert %#v as bytes", scanResult)
}
if data == nil {
return nil
}
return structConvert.FromDB(data)
}
}
@ -543,7 +576,7 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
fieldType := fieldValue.Type()
if col.IsJSON {
return session.setJSON(fieldValue, fieldType, scanResult)
return setJSON(fieldValue, fieldType, scanResult)
}
switch fieldType.Kind() {
@ -562,7 +595,7 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
}
return nil
case reflect.Complex64, reflect.Complex128:
return session.setJSON(fieldValue, fieldType, scanResult)
return setJSON(fieldValue, fieldType, scanResult)
case reflect.Slice, reflect.Array:
bs, ok := convert.AsBytes(scanResult)
if ok && fieldType.Elem().Kind() == reflect.Uint8 {
@ -671,18 +704,17 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
if idx, ok = tempMap[lKey]; !ok {
idx = 0
} else {
idx = idx + 1
idx++
}
tempMap[lKey] = idx
col, fieldValue, err := session.getField(dataStruct, table, colName, idx)
if err != nil {
if _, ok := err.(ErrFieldIsNotExist); ok {
continue
} else {
return nil, err
}
col, fieldValue, err := getField(dataStruct, table, colName, idx)
if _, ok := err.(ErrFieldIsNotExist); ok {
continue
} else if err != nil {
return nil, err
}
if fieldValue == nil {
continue
}
@ -725,6 +757,12 @@ func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
// Context sets the context on this session
func (session *Session) Context(ctx context.Context) *Session {
if session.ctx != nil {
ctx = context.WithValue(ctx, log.SessionIDKey, session.ctx.Value(log.SessionIDKey))
ctx = context.WithValue(ctx, log.SessionKey, session.ctx.Value(log.SessionKey))
ctx = context.WithValue(ctx, log.SessionShowSQLKey, session.ctx.Value(log.SessionShowSQLKey))
}
session.ctx = ctx
return session
}

View File

@ -40,7 +40,13 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
pkColumns := table.PKColumns()
ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
if err != nil {
resultsSlice, err := session.queryBytes(newsql, args...)
rows, err := session.queryRows(newsql, args...)
if err != nil {
return err
}
defer rows.Close()
resultsSlice, err := session.engine.ScanStringMaps(rows)
if err != nil {
return err
}
@ -53,9 +59,9 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
if v, ok := data[col.Name]; !ok {
return errors.New("no id")
} else if col.SQLType.IsText() {
pk = append(pk, string(v))
pk = append(pk, v)
} else if col.SQLType.IsNumeric() {
id, err = strconv.ParseInt(string(v), 10, 64)
id, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return err
}
@ -226,7 +232,7 @@ func (session *Session) Delete(beans ...interface{}) (int64, error) {
}
if cacher := session.engine.GetCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
_ = session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
}
session.statement.RefTable = table

View File

@ -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 != "" {
@ -71,7 +71,11 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
}
// session has stored the conditions so we use `unscoped` to avoid duplicated condition.
return session.Unscoped().Count(reflect.New(sliceElementType).Interface())
if sliceElementType.Kind() == reflect.Struct {
return session.Unscoped().Count(reflect.New(sliceElementType).Interface())
}
return session.Unscoped().Count()
}
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
@ -152,7 +156,6 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
if err != ErrCacheFailed {
return err
}
err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.engine.logger.Warnf("Cache Find Failed")
}
}
@ -251,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)
}

View File

@ -6,7 +6,6 @@ package xorm
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"math/big"
@ -28,11 +27,11 @@ var (
// Get retrieve one record from database, bean's non-empty fields
// will be as conditions
func (session *Session) Get(bean interface{}) (bool, error) {
func (session *Session) Get(beans ...interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
return session.get(bean)
return session.get(beans...)
}
func isPtrOfTime(v interface{}) bool {
@ -48,14 +47,17 @@ func isPtrOfTime(v interface{}) bool {
return el.Type().ConvertibleTo(schemas.TimeType)
}
func (session *Session) get(bean interface{}) (bool, error) {
func (session *Session) get(beans ...interface{}) (bool, error) {
defer session.resetStatement()
if session.statement.LastError != nil {
return false, session.statement.LastError
}
if len(beans) == 0 {
return false, errors.New("needs at least one parameter for get")
}
beanValue := reflect.ValueOf(bean)
beanValue := reflect.ValueOf(beans[0])
if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer to a value")
} else if beanValue.Elem().Kind() == reflect.Ptr {
@ -64,8 +66,9 @@ func (session *Session) get(bean interface{}) (bool, error) {
return false, ErrObjectIsNil
}
if beanValue.Elem().Kind() == reflect.Struct && !isPtrOfTime(bean) {
if err := session.statement.SetRefBean(bean); err != nil {
var isStruct = beanValue.Elem().Kind() == reflect.Struct && !isPtrOfTime(beans[0])
if isStruct {
if err := session.statement.SetRefBean(beans[0]); err != nil {
return false, err
}
}
@ -75,11 +78,11 @@ func (session *Session) get(bean interface{}) (bool, error) {
var err error
if session.statement.RawSQL == "" {
if len(session.statement.TableName()) <= 0 {
if len(session.statement.TableName()) == 0 {
return false, ErrTableNotFound
}
session.statement.Limit(1)
sqlStr, args, err = session.statement.GenGetSQL(bean)
sqlStr, args, err = session.statement.GenGetSQL(beans[0])
if err != nil {
return false, err
}
@ -90,10 +93,10 @@ func (session *Session) get(bean interface{}) (bool, error) {
table := session.statement.RefTable
if session.statement.ColumnMap.IsEmpty() && session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
if session.statement.ColumnMap.IsEmpty() && session.canCache() && isStruct {
if cacher := session.engine.GetCacher(session.statement.TableName()); cacher != nil &&
!session.statement.GetUnscoped() {
has, err := session.cacheGet(bean, sqlStr, args...)
has, err := session.cacheGet(beans[0], sqlStr, args...)
if err != ErrCacheFailed {
return has, err
}
@ -101,12 +104,12 @@ func (session *Session) get(bean interface{}) (bool, error) {
}
context := session.statement.Context
if context != nil {
if context != nil && isStruct {
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
if res != nil {
session.engine.logger.Debugf("hit context cache: %s", sqlStr)
structValue := reflect.Indirect(reflect.ValueOf(bean))
structValue := reflect.Indirect(reflect.ValueOf(beans[0]))
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
session.lastSQL = ""
session.lastSQLArgs = nil
@ -114,29 +117,18 @@ func (session *Session) get(bean interface{}) (bool, error) {
}
}
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, beans, sqlStr, args...)
if err != nil || !has {
return has, err
}
if context != nil {
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
if context != nil && isStruct {
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), beans[0])
}
return true, nil
}
var (
valuerTypePlaceHolder driver.Valuer
valuerType = reflect.TypeOf(&valuerTypePlaceHolder).Elem()
scannerTypePlaceHolder sql.Scanner
scannerType = reflect.TypeOf(&scannerTypePlaceHolder).Elem()
conversionTypePlaceHolder convert.Conversion
conversionType = reflect.TypeOf(&conversionTypePlaceHolder).Elem()
)
func isScannableStruct(bean interface{}, typeLen int) bool {
switch bean.(type) {
case *time.Time:
@ -151,7 +143,7 @@ func isScannableStruct(bean interface{}, typeLen int) bool {
return true
}
func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table, beans []interface{}, sqlStr string, args ...interface{}) (bool, error) {
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return false, err
@ -171,27 +163,51 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table,
if err != nil {
return true, err
}
switch beanKind {
case reflect.Struct:
if !isScannableStruct(bean, len(types)) {
break
}
return session.getStruct(rows, types, fields, table, bean)
case reflect.Slice:
return session.getSlice(rows, types, fields, bean)
case reflect.Map:
return session.getMap(rows, types, fields, bean)
}
return session.getVars(rows, types, fields, bean)
if err := session.scan(rows, table, beanKind, beans, types, fields); err != nil {
return true, err
}
rows.Close()
return true, session.executeProcessors()
}
func (session *Session) getSlice(rows *core.Rows, types []*sql.ColumnType, fields []string, bean interface{}) (bool, error) {
func (session *Session) scan(rows *core.Rows, table *schemas.Table, firstBeanKind reflect.Kind, beans []interface{}, types []*sql.ColumnType, fields []string) error {
if len(beans) == 1 {
bean := beans[0]
switch firstBeanKind {
case reflect.Struct:
if !isScannableStruct(bean, len(types)) {
break
}
scanResults, err := session.row2Slice(rows, fields, types, bean)
if err != nil {
return err
}
dataStruct := utils.ReflectValue(bean)
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
return err
case reflect.Slice:
return session.getSlice(rows, types, fields, bean)
case reflect.Map:
return session.getMap(rows, types, fields, bean)
}
}
if len(beans) != len(types) {
return fmt.Errorf("expected columns %d, but only %d variables", len(types), len(beans))
}
return session.engine.scan(rows, fields, types, beans...)
}
func (session *Session) getSlice(rows *core.Rows, types []*sql.ColumnType, fields []string, bean interface{}) error {
switch t := bean.(type) {
case *[]string:
res, err := session.engine.scanStringInterface(rows, fields, types)
if err != nil {
return true, err
return err
}
var needAppend = len(*t) == 0 // both support slice is empty or has been initlized
@ -202,17 +218,17 @@ func (session *Session) getSlice(rows *core.Rows, types []*sql.ColumnType, field
(*t)[i] = r.(*sql.NullString).String
}
}
return true, nil
return nil
case *[]interface{}:
scanResults, err := session.engine.scanInterfaces(rows, fields, types)
if err != nil {
return true, err
return err
}
var needAppend = len(*t) == 0
for ii := range fields {
s, err := convert.Interface2Interface(session.engine.DatabaseTZ, scanResults[ii])
if err != nil {
return true, err
return err
}
if needAppend {
*t = append(*t, s)
@ -220,67 +236,41 @@ func (session *Session) getSlice(rows *core.Rows, types []*sql.ColumnType, field
(*t)[ii] = s
}
}
return true, nil
return nil
default:
return true, fmt.Errorf("unspoorted slice type: %t", t)
return fmt.Errorf("unspoorted slice type: %t", t)
}
}
func (session *Session) getMap(rows *core.Rows, types []*sql.ColumnType, fields []string, bean interface{}) (bool, error) {
func (session *Session) getMap(rows *core.Rows, types []*sql.ColumnType, fields []string, bean interface{}) error {
switch t := bean.(type) {
case *map[string]string:
scanResults, err := session.engine.scanStringInterface(rows, fields, types)
if err != nil {
return true, err
return err
}
for ii, key := range fields {
(*t)[key] = scanResults[ii].(*sql.NullString).String
}
return true, nil
return nil
case *map[string]interface{}:
scanResults, err := session.engine.scanInterfaces(rows, fields, types)
if err != nil {
return true, err
return err
}
for ii, key := range fields {
s, err := convert.Interface2Interface(session.engine.DatabaseTZ, scanResults[ii])
if err != nil {
return true, err
return err
}
(*t)[key] = s
}
return true, nil
return nil
default:
return true, fmt.Errorf("unspoorted map type: %t", t)
return fmt.Errorf("unspoorted map type: %t", t)
}
}
func (session *Session) getVars(rows *core.Rows, types []*sql.ColumnType, fields []string, beans ...interface{}) (bool, error) {
if len(beans) != len(types) {
return false, fmt.Errorf("expected columns %d, but only %d variables", len(types), len(beans))
}
err := session.engine.scan(rows, fields, types, beans...)
return true, err
}
func (session *Session) getStruct(rows *core.Rows, types []*sql.ColumnType, fields []string, table *schemas.Table, bean interface{}) (bool, error) {
scanResults, err := session.row2Slice(rows, fields, types, bean)
if err != nil {
return false, err
}
// close it before convert data
rows.Close()
dataStruct := utils.ReflectValue(bean)
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
if err != nil {
return true, err
}
return true, session.executeProcessors()
}
func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) {
// if has no reftable, then don't use cache currently
if !session.canCache() {
@ -357,7 +347,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
cacheBean := cacher.GetBean(tableName, sid)
if cacheBean == nil {
cacheBean = bean
has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...)
has, err = session.nocacheGet(reflect.Struct, table, []interface{}{cacheBean}, sqlStr, args...)
if err != nil || !has {
return has, err
}

View File

@ -80,7 +80,7 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -90,7 +90,6 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
colNames []string
colMultiPlaces []string
args []interface{}
cols []*schemas.Column
)
for i := 0; i < size; i++ {
@ -123,6 +122,12 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
}
fieldValue := *ptrFieldValue
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) {
if session.engine.dialect.Features().AutoincrMode == dialects.SequenceAutoincrMode {
if i == 0 {
colNames = append(colNames, col.Name)
}
colPlaces = append(colPlaces, utils.SeqName(tableName)+".nextval")
}
continue
}
if col.MapType == schemas.ONLYFROMDB {
@ -137,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 {
@ -166,7 +178,6 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
if i == 0 {
colNames = append(colNames, col.Name)
cols = append(cols, col)
}
colPlaces = append(colPlaces, "?")
}
@ -197,7 +208,7 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
return 0, err
}
session.cacheInsert(tableName)
_ = session.cacheInsert(tableName)
lenAfterClosures := len(session.afterClosures)
for i := 0; i < size; i++ {
@ -251,7 +262,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
if err := session.statement.SetRefBean(bean); err != nil {
return 0, err
}
if len(session.statement.TableName()) <= 0 {
if len(session.statement.TableName()) == 0 {
return 0, ErrTableNotFound
}
@ -277,6 +288,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
if err != nil {
return 0, err
}
sqlStr = session.engine.dialect.Quoter().Replace(sqlStr)
handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.isAutoCommit {
@ -307,20 +319,53 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
// if there is auto increment column and driver don't support return it
if len(table.AutoIncrement) > 0 && !session.engine.driver.Features().SupportReturnInsertedID {
var sql = sqlStr
if session.engine.dialect.URI().DBType == schemas.ORACLE {
sql = "select seq_atable.currval from dual"
var sql string
var newArgs []interface{}
var needCommit bool
var id int64
if session.engine.dialect.URI().DBType == schemas.ORACLE || session.engine.dialect.URI().DBType == schemas.DAMENG {
if session.isAutoCommit { // if it's not in transaction
if err := session.Begin(); err != nil {
return 0, err
}
needCommit = true
}
_, err := session.exec(sqlStr, args...)
if err != nil {
return 0, err
}
i := utils.IndexSlice(colNames, table.AutoIncrement)
if i > -1 {
id, err = convert.AsInt64(args[i])
if err != nil {
return 0, err
}
} else {
sql = fmt.Sprintf("select %s.currval from dual", utils.SeqName(tableName))
}
} else {
sql = sqlStr
newArgs = args
}
rows, err := session.queryRows(sql, args...)
if err != nil {
return 0, err
if id == 0 {
err := session.queryRow(sql, newArgs...).Scan(&id)
if err != nil {
return 0, err
}
if needCommit {
if err := session.Commit(); err != nil {
return 0, err
}
}
if id == 0 {
return 0, errors.New("insert successfully but not returned id")
}
}
defer rows.Close()
defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName)
_ = session.cacheInsert(tableName)
if table.Version != "" && session.statement.CheckVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
@ -331,16 +376,6 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
}
}
var id int64
if !rows.Next() {
if rows.Err() != nil {
return 0, rows.Err()
}
return 0, errors.New("insert successfully but not returned id")
}
if err := rows.Scan(&id); err != nil {
return 1, err
}
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Errorf("%v", err)
@ -360,7 +395,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName)
_ = session.cacheInsert(tableName)
if table.Version != "" && session.statement.CheckVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
@ -400,6 +435,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
// InsertOne insert only one struct into database as a record.
// The in parameter bean must a struct or a point to struct. The return
// parameter is inserted and error
// Deprecated: Please use Insert directly
func (session *Session) InsertOne(bean interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
@ -507,7 +543,7 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -529,12 +565,12 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
}
func (session *Session) insertMultipleMapInterface(maps []map[string]interface{}) (int64, error) {
if len(maps) <= 0 {
if len(maps) == 0 {
return 0, ErrNoElementsOnSlice
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -565,7 +601,7 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -588,12 +624,12 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
}
func (session *Session) insertMultipleMapString(maps []map[string]string) (int64, error) {
if len(maps) <= 0 {
if len(maps) == 0 {
return 0, ErrNoElementsOnSlice
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -620,7 +656,7 @@ func (session *Session) insertMultipleMapString(maps []map[string]string) (int64
func (session *Session) insertMap(columns []string, args []interface{}) (int64, error) {
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -628,6 +664,7 @@ func (session *Session) insertMap(columns []string, args []interface{}) (int64,
if err != nil {
return 0, err
}
sql = session.engine.dialect.Quoter().Replace(sql)
if err := session.cacheInsert(tableName); err != nil {
return 0, err
@ -646,7 +683,7 @@ func (session *Session) insertMap(columns []string, args []interface{}) (int64,
func (session *Session) insertMultipleMap(columns []string, argss [][]interface{}) (int64, error) {
tableName := session.statement.TableName()
if len(tableName) <= 0 {
if len(tableName) == 0 {
return 0, ErrTableNotFound
}
@ -654,6 +691,7 @@ func (session *Session) insertMultipleMap(columns []string, argss [][]interface{
if err != nil {
return 0, err
}
sql = session.engine.dialect.Quoter().Replace(sql)
if err := session.cacheInsert(tableName); err != nil {
return 0, err

View File

@ -95,7 +95,7 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
break
}
start = start + slice.Elem().Len()
start += slice.Elem().Len()
if pLimitN != nil && start+bufferSize > *pLimitN {
bufferSize = *pLimitN - start
}

View File

@ -1,154 +0,0 @@
// Copyright 2017 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"xorm.io/xorm/core"
)
// Query runs a raw sql and return records as []map[string][]byte
func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
return session.queryBytes(sqlStr, args...)
}
func (session *Session) rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := session.engine.row2mapStr(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
func (session *Session) rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
record, err := session.engine.row2sliceStr(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, record)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
// QueryString runs a raw sql and return records as []map[string]string
func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.rows2Strings(rows)
}
// QuerySliceString runs a raw sql and return records as [][]string
func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.rows2SliceString(rows)
}
func (session *Session) rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := session.engine.row2mapInterface(rows, types, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return resultsSlice, nil
}
// QueryInterface runs a raw sql and return records as []map[string]interface{}
func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.rows2Interfaces(rows)
}

View File

@ -33,7 +33,7 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
if session.isAutoCommit {
var db *core.DB
if session.sessionType == groupSession && strings.EqualFold(sqlStr[:6], "select") {
if session.sessionType == groupSession && strings.EqualFold(strings.TrimSpace(sqlStr)[:6], "select") && !session.statement.IsForUpdate {
db = session.engine.engineGroup.Slave().DB()
} else {
db = session.DB()
@ -46,39 +46,106 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
return nil, err
}
rows, err := stmt.QueryContext(session.ctx, args...)
if err != nil {
return nil, err
}
return rows, nil
return stmt.QueryContext(session.ctx, args...)
}
rows, err := db.QueryContext(session.ctx, sqlStr, args...)
return db.QueryContext(session.ctx, sqlStr, args...)
}
if session.prepareStmt {
stmt, err := session.doPrepareTx(sqlStr)
if err != nil {
return nil, err
}
return rows, nil
return stmt.QueryContext(session.ctx, args...)
}
rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...)
if err != nil {
return nil, err
}
return rows, nil
return session.tx.QueryContext(session.ctx, sqlStr, args...)
}
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
return core.NewRow(session.queryRows(sqlStr, args...))
}
func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
// Query runs a raw sql and return records as []map[string][]byte
func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2maps(rows)
return session.engine.scanByteMaps(rows)
}
// QueryString runs a raw sql and return records as []map[string]string
func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.engine.ScanStringMaps(rows)
}
// QuerySliceString runs a raw sql and return records as [][]string
func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.engine.ScanStringSlices(rows)
}
// QueryInterface runs a raw sql and return records as []map[string]interface{}
func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return session.engine.ScanInterfaceMaps(rows)
}
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
@ -90,6 +157,13 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
session.lastSQLArgs = args
if !session.isAutoCommit {
if session.prepareStmt {
stmt, err := session.doPrepareTx(sqlStr)
if err != nil {
return nil, err
}
return stmt.ExecContext(session.ctx, args...)
}
return session.tx.ExecContext(session.ctx, sqlStr, args...)
}
@ -98,12 +172,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
if err != nil {
return nil, err
}
res, err := stmt.ExecContext(session.ctx, args...)
if err != nil {
return nil, err
}
return res, nil
return stmt.ExecContext(session.ctx, args...)
}
return session.DB().ExecContext(session.ctx, sqlStr, args...)

View File

@ -6,12 +6,14 @@ package xorm
import (
"bufio"
"context"
"database/sql"
"fmt"
"io"
"os"
"strings"
"xorm.io/xorm/dialects"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas"
)
@ -40,13 +42,28 @@ func (session *Session) createTable(bean interface{}) error {
return err
}
sqlStrs := session.statement.GenCreateTableSQL()
for _, s := range sqlStrs {
_, err := session.exec(s)
session.statement.RefTable.StoreEngine = session.statement.StoreEngine
session.statement.RefTable.Charset = session.statement.Charset
tableName := session.statement.TableName()
refTable := session.statement.RefTable
if refTable.AutoIncrement != "" && session.engine.dialect.Features().AutoincrMode == dialects.SequenceAutoincrMode {
sqlStr, err := session.engine.dialect.CreateSequenceSQL(context.Background(), session.engine.db, utils.SeqName(tableName))
if err != nil {
return err
}
if _, err := session.exec(sqlStr); err != nil {
return err
}
}
sqlStr, _, err := session.engine.dialect.CreateTableSQL(context.Background(), session.engine.db, refTable, tableName)
if err != nil {
return err
}
if _, err := session.exec(sqlStr); err != nil {
return err
}
return nil
}
@ -141,11 +158,32 @@ func (session *Session) dropTable(beanOrTableName interface{}) error {
checkIfExist = exist
}
if checkIfExist {
_, err := session.exec(sqlStr)
if !checkIfExist {
return nil
}
if _, err := session.exec(sqlStr); err != nil {
return err
}
return nil
if session.engine.dialect.Features().AutoincrMode == dialects.IncrAutoincrMode {
return nil
}
var seqName = utils.SeqName(tableName)
exist, err := session.engine.dialect.IsSequenceExist(session.ctx, session.getQueryer(), seqName)
if err != nil {
return err
}
if !exist {
return nil
}
sqlStr, err = session.engine.dialect.DropSequenceSQL(seqName)
if err != nil {
return err
}
_, err = session.exec(sqlStr)
return err
}
// IsTableExist if a table is exist
@ -185,24 +223,6 @@ func (session *Session) isTableEmpty(tableName string) (bool, error) {
return total == 0, nil
}
// find if index is exist according cols
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
indexes, err := session.engine.dialect.GetIndexes(session.getQueryer(), session.ctx, tableName)
if err != nil {
return false, err
}
for _, index := range indexes {
if utils.SliceEq(index.Cols, cols) {
if unique {
return index.Type == schemas.UniqueType, nil
}
return index.Type == schemas.IndexType, nil
}
}
return false, nil
}
func (session *Session) addColumn(colName string) error {
col := session.statement.RefTable.GetColumn(colName)
sql := session.engine.dialect.AddColumnSQL(session.statement.TableName(), col)
@ -225,7 +245,13 @@ func (session *Session) addUnique(tableName, uqeName string) error {
}
// Sync2 synchronize structs to database tables
// Depricated
func (session *Session) Sync2(beans ...interface{}) error {
return session.Sync(beans...)
}
// Sync synchronize structs to database tables
func (session *Session) Sync(beans ...interface{}) error {
engine := session.engine
if session.isAutoClose {
@ -350,6 +376,8 @@ func (session *Session) Sync2(beans ...interface{}) error {
_, err = session.exec(engine.dialect.ModifyColumnSQL(tbNameWithSchema, col))
}
}
} else if col.Comment != oriCol.Comment {
_, err = session.exec(engine.dialect.ModifyColumnSQL(tbNameWithSchema, col))
}
if col.Default != oriCol.Default {

View File

@ -70,12 +70,12 @@ func (session *Session) SumInt(bean interface{}, columnName string) (res int64,
// Sums call sum some columns. bean's non-empty fields are conditions.
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
var res = make([]float64, len(columnNames), len(columnNames))
var res = make([]float64, len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}
// SumsInt sum specify columns and return as []int64 instead of []float64
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
var res = make([]int64, len(columnNames), len(columnNames))
var res = make([]int64, len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}

View File

@ -75,7 +75,7 @@ func (session *Session) Commit() error {
}
cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
if len(*slices) > 0 {
*slices = make(map[interface{}]*[]func(interface{}), 0)
*slices = make(map[interface{}]*[]func(interface{}))
}
}
cleanUpFunc(&session.afterInsertBeans)

View File

@ -22,6 +22,7 @@ var (
ErrNoColumnsTobeUpdated = errors.New("no columns found to be updated")
)
//revive:disable
func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error {
if table == nil ||
session.tx != nil {
@ -39,7 +40,7 @@ func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr stri
var nStart int
if len(args) > 0 {
if strings.Index(sqlStr, "?") > -1 {
if strings.Contains(sqlStr, "?") {
nStart = strings.Count(oldhead, "?")
} else {
// only for pq, TODO: if any other databse?
@ -182,7 +183,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
return 0, err
}
if len(session.statement.TableName()) <= 0 {
if len(session.statement.TableName()) == 0 {
return 0, ErrTableNotFound
}
@ -278,7 +279,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
condBeanIsStruct := false
if len(condiBean) > 0 {
if c, ok := condiBean[0].(map[string]interface{}); ok {
autoCond = builder.Eq(c)
var eq = make(builder.Eq)
for k, v := range c {
eq[session.engine.Quote(k)] = v
}
autoCond = builder.Eq(eq)
} else {
ct := reflect.TypeOf(condiBean[0])
k := ct.Kind()
@ -338,7 +343,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
}
}
if len(colNames) <= 0 {
if len(colNames) == 0 {
return 0, ErrNoColumnsTobeUpdated
}
@ -352,7 +357,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
}
if st.OrderStr != "" {
condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
condSQL += fmt.Sprintf(" ORDER BY %v", st.OrderStr)
}
var tableName = session.statement.TableName()
@ -362,7 +367,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
limitValue := *st.LimitN
switch session.engine.dialect.URI().DBType {
case schemas.MYSQL:
condSQL = condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
condSQL += fmt.Sprintf(" LIMIT %d", limitValue)
case schemas.SQLITE:
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",

View File

@ -316,6 +316,7 @@ func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
table := schemas.NewEmptyTable()
table.Type = t
table.Name = names.GetTableName(parser.tableMapper, v)
table.Comment = names.GetTableComment(v)
for i := 0; i < t.NumField(); i++ {
col, err := parser.parseField(table, i, t.Field(i), v.Field(i))

View File

@ -26,6 +26,20 @@ func (p ParseTableName2) TableName() string {
return "p_parseTableName"
}
type ParseTableComment struct{}
type ParseTableComment1 struct{}
type ParseTableComment2 struct{}
func (p ParseTableComment1) TableComment() string {
return "p_parseTableComment1"
}
func (p *ParseTableComment2) TableComment() string {
return "p_parseTableComment2"
}
func TestParseTableName(t *testing.T) {
parser := NewParser(
"xorm",
@ -47,6 +61,36 @@ func TestParseTableName(t *testing.T) {
assert.EqualValues(t, "p_parseTableName", table.Name)
}
func TestParseTableComment(t *testing.T) {
parser := NewParser(
"xorm",
dialects.QueryDialect("mysql"),
names.SnakeMapper{},
names.SnakeMapper{},
caches.NewManager(),
)
table, err := parser.Parse(reflect.ValueOf(new(ParseTableComment)))
assert.NoError(t, err)
assert.EqualValues(t, "", table.Comment)
table, err = parser.Parse(reflect.ValueOf(new(ParseTableComment1)))
assert.NoError(t, err)
assert.EqualValues(t, "p_parseTableComment1", table.Comment)
table, err = parser.Parse(reflect.ValueOf(ParseTableComment1{}))
assert.NoError(t, err)
assert.EqualValues(t, "p_parseTableComment1", table.Comment)
table, err = parser.Parse(reflect.ValueOf(new(ParseTableComment2)))
assert.NoError(t, err)
assert.EqualValues(t, "p_parseTableComment2", table.Comment)
table, err = parser.Parse(reflect.ValueOf(ParseTableComment2{}))
assert.NoError(t, err)
assert.EqualValues(t, "p_parseTableComment2", table.Comment)
}
func TestUnexportField(t *testing.T) {
parser := NewParser(
"xorm",