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: TEST_MYSQL_PASSWORD:
commands: commands:
- make test-mysql - make test-mysql
- TEST_QUOTE_POLICY=reserved make test-mysql - TEST_QUOTE_POLICY=reserved make test-mysql-tls
volumes: volumes:
- name: cache - name: cache
@ -363,6 +363,41 @@ services:
commands: commands:
- /cockroach/cockroach start --insecure - /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 kind: pipeline
name: merge_coverage name: merge_coverage
@ -374,6 +409,7 @@ depends_on:
- test-mssql - test-mssql
- test-tidb - test-tidb
- test-cockroach - test-cockroach
#- test-dameng
trigger: trigger:
ref: ref:
- refs/heads/master - 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 ## Contributing to xorm
`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very `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, 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 or adding new functionality. There is no formal style guide, but
please conform to the style of existing code and general Go formatting please conform to the style of existing code and general Go formatting
conventions when submitting patches. conventions when submitting patches.
* [fork a repo](https://help.github.com/articles/fork-a-repo) * [fork the repo](https://gitea.com/repo/fork/2038)
* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request) * [creating a pull request ](https://docs.gitea.io/en-us/pull-request/)
### Language ### Language
@ -15,7 +15,7 @@ Since `xorm` is a world-wide open source project, please describe your issues or
### Sign your codes with comments ### Sign your codes with comments
``` ```
// !<you github id>! your comments // !<your gitea.com id>! your comments
e.g., e.g.,
@ -65,7 +65,7 @@ And if your branch is related with cache, you could also enable it via `TEST_CAC
### Patch review ### 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. proposed functionality.
### Bug reports ### Bug reports

View File

@ -43,6 +43,10 @@ TEST_TIDB_DBNAME ?= xorm_test
TEST_TIDB_USERNAME ?= root TEST_TIDB_USERNAME ?= root
TEST_TIDB_PASSWORD ?= TEST_TIDB_PASSWORD ?=
TEST_DAMENG_HOST ?= dameng:5236
TEST_DAMENG_USERNAME ?= SYSDBA
TEST_DAMENG_PASSWORD ?= SYSDBA
TEST_CACHE_ENABLE ?= false TEST_CACHE_ENABLE ?= false
TEST_QUOTE_POLICY ?= always TEST_QUOTE_POLICY ?= always
@ -94,8 +98,7 @@ help:
@echo " - build creates the entire project" @echo " - build creates the entire project"
@echo " - clean delete integration files and build files but not css and js files" @echo " - clean delete integration files and build files but not css and js files"
@echo " - fmt format the code" @echo " - fmt format the code"
@echo " - lint run code linter revive" @echo " - lint run code linter"
@echo " - misspell check if a word is written wrong"
@echo " - test run default unit test" @echo " - test run default unit test"
@echo " - test-cockroach run integration tests for cockroach" @echo " - test-cockroach run integration tests for cockroach"
@echo " - test-mysql run integration tests for mysql" @echo " - test-mysql run integration tests for mysql"
@ -107,28 +110,25 @@ help:
@echo " - vet examines Go source code and reports suspicious constructs" @echo " - vet examines Go source code and reports suspicious constructs"
.PHONY: lint .PHONY: lint
lint: revive lint: golangci-lint
.PHONY: revive .PHONY: golangci-lint
revive: golangci-lint: golangci-lint-check
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ golangci-lint run --timeout 10m
$(GO) get -u github.com/mgechev/revive; \
fi
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1
.PHONY: misspell .PHONY: golangci-lint-check
misspell: golangci-lint-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(GO) get -u github.com/client9/misspell/cmd/misspell; \ $(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 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 .PHONY: test
test: go-check 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)" \ -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 -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 .PNONY: test-postgres
test-postgres: go-check test-postgres: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ $(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" \ $(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 -quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
.PNONY: test-tidb .PNONY: test-tidb
test-tidb: go-check test-tidb: go-check
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \ $(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)" \ -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 -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 .PHONY: vet
vet: vet:
$(GO) vet $(shell $(GO) list ./...) $(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) 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 ```Go
type User struct { type User struct {
@ -87,7 +87,7 @@ type User struct {
Updated time.Time `xorm:"updated"` Updated time.Time `xorm:"updated"`
} }
err := engine.Sync2(new(User)) err := engine.Sync(new(User))
``` ```
* Create Engine Group * Create Engine Group
@ -141,6 +141,24 @@ affected, err := engine.Insert(&users)
affected, err := engine.Insert(&user1, &users) affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values () // INSERT INTO struct1 () values ()
// INSERT INTO struct2 () 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 * `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) has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ? // 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) var valuesMap = make(map[string]string)
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ? // 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 0, 100
// SELECT * FROM user Limit 101, 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}) rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user // SELECT * FROM user
defer rows.Close() 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. * `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 ```Go

View File

@ -84,7 +84,7 @@ type User struct {
Updated time.Time `xorm:"updated"` Updated time.Time `xorm:"updated"`
} }
err := engine.Sync2(new(User)) err := engine.Sync(new(User))
``` ```
* 创建Engine组 * 创建Engine组
@ -138,6 +138,24 @@ affected, err := engine.Insert(&users)
affected, err := engine.Insert(&user1, &users) affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values () // INSERT INTO struct1 () values ()
// INSERT INTO struct2 () 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` 查询单条记录 * `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) has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ? // 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) var valuesMap = make(map[string]string)
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ? // SELECT * FROM user WHERE id = ?
@ -209,7 +232,7 @@ type UserDetail struct {
} }
var users []UserDetail 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"). Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0). Where("user.name = ?", name).Limit(10, 0).
Find(&users) 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 0, 100
// SELECT * FROM user Limit 101, 100 // SELECT * FROM user Limit 101, 100
```
Rows 的用法类似 `sql.Rows`
```Go
rows, err := engine.Rows(&User{Name:name}) rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user // SELECT * FROM user
defer rows.Close() 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的字段 * `Update` 更新数据除非使用Cols,AllCols函数指明默认只更新非空和非0的字段
```Go ```Go

View File

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

View File

@ -56,7 +56,7 @@ func (m *LRUCacher) GC() {
var removedNum int var removedNum int
for e := m.idList.Front(); e != nil; { for e := m.idList.Front(); e != nil; {
if removedNum <= CacheGcMaxRemoved && if removedNum <= CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { time.Since(e.Value.(*idNode).lastVisit) > m.Expired {
removedNum++ removedNum++
next := e.Next() next := e.Next()
node := e.Value.(*idNode) node := e.Value.(*idNode)
@ -70,7 +70,7 @@ func (m *LRUCacher) GC() {
removedNum = 0 removedNum = 0
for e := m.sqlList.Front(); e != nil; { for e := m.sqlList.Front(); e != nil; {
if removedNum <= CacheGcMaxRemoved && if removedNum <= CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { time.Since(e.Value.(*sqlNode).lastVisit) > m.Expired {
removedNum++ removedNum++
next := e.Next() next := e.Next()
node := e.Value.(*sqlNode) node := e.Value.(*sqlNode)
@ -96,7 +96,7 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
} else { } else {
lastTime := el.Value.(*sqlNode).lastVisit lastTime := el.Value.(*sqlNode).lastVisit
// if expired, remove the node and return nil // 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) m.delIds(tableName, sql)
return nil return nil
} }
@ -122,7 +122,7 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
if el, ok := m.idIndex[tableName][id]; ok { if el, ok := m.idIndex[tableName][id]; ok {
lastTime := el.Value.(*idNode).lastVisit lastTime := el.Value.(*idNode).lastVisit
// if expired, remove the node and return nil // 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) m.delBean(tableName, id)
return nil return nil
} }
@ -145,7 +145,7 @@ func (m *LRUCacher) clearIds(tableName string) {
if tis, ok := m.sqlIndex[tableName]; ok { if tis, ok := m.sqlIndex[tableName]; ok {
for sql, v := range tis { for sql, v := range tis {
m.sqlList.Remove(v) m.sqlList.Remove(v)
m.store.Del(sql) _ = m.store.Del(sql)
} }
} }
m.sqlIndex[tableName] = make(map[string]*list.Element) m.sqlIndex[tableName] = make(map[string]*list.Element)
@ -163,7 +163,7 @@ func (m *LRUCacher) clearBeans(tableName string) {
for id, v := range tis { for id, v := range tis {
m.idList.Remove(v) m.idList.Remove(v)
tid := genID(tableName, id) tid := genID(tableName, id)
m.store.Del(tid) _ = m.store.Del(tid)
} }
} }
m.idIndex[tableName] = make(map[string]*list.Element) m.idIndex[tableName] = make(map[string]*list.Element)
@ -188,7 +188,7 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
} else { } else {
el.Value.(*sqlNode).lastVisit = time.Now() el.Value.(*sqlNode).lastVisit = time.Now()
} }
m.store.Put(sql, ids) _ = m.store.Put(sql, ids)
if m.sqlList.Len() > m.MaxElementSize { if m.sqlList.Len() > m.MaxElementSize {
e := m.sqlList.Front() e := m.sqlList.Front()
node := e.Value.(*sqlNode) node := e.Value.(*sqlNode)
@ -210,7 +210,7 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
el.Value.(*idNode).lastVisit = time.Now() 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 { if m.idList.Len() > m.MaxElementSize {
e := m.idList.Front() e := m.idList.Front()
node := e.Value.(*idNode) node := e.Value.(*idNode)
@ -226,7 +226,7 @@ func (m *LRUCacher) delIds(tableName, sql string) {
m.sqlList.Remove(el) m.sqlList.Remove(el)
} }
} }
m.store.Del(sql) _ = m.store.Del(sql)
} }
// DelIds deletes ids // DelIds deletes ids
@ -243,7 +243,7 @@ func (m *LRUCacher) delBean(tableName string, id string) {
m.idList.Remove(el) m.idList.Remove(el)
m.clearIds(tableName) m.clearIds(tableName)
} }
m.store.Del(tid) _ = m.store.Del(tid)
} }
// DelBean deletes beans in some table // DelBean deletes beans in some table
@ -265,10 +265,6 @@ type sqlNode struct {
lastVisit time.Time lastVisit time.Time
} }
func genSQLKey(sql string, args interface{}) string {
return fmt.Sprintf("%s-%v", sql, args)
}
func genID(prefix string, id string) string { func genID(prefix string, id string) string {
return fmt.Sprintf("%s-%s", prefix, id) 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.Ctx = ctx
c.Result = result c.Result = result
c.Err = err c.Err = err
c.ExecuteTime = time.Now().Sub(c.start) c.ExecuteTime = time.Since(c.start)
} }
// Hook represents a hook behaviour // 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) { switch d := dest.(type) {
case *string: case *string:
sv = reflect.ValueOf(src) var sv = reflect.ValueOf(src)
switch sv.Kind() { switch sv.Kind() {
case reflect.Bool, case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 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) dt = dt.In(convertedLocation)
return &dt, nil 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 { } else {
i, err := strconv.ParseInt(s, 10, 64) i, err := strconv.ParseInt(s, 10, 64)
if err == nil { if err == nil {

View File

@ -16,6 +16,7 @@ func TestString2Time(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
var kases = map[string]time.Time{ 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-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-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), "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} cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
db.reflectCache[typ] = cs db.reflectCache[typ] = cs
} else { } else {
cs.idx = cs.idx + 1 cs.idx++
} }
return cs.value.Index(cs.idx).Addr() return cs.value.Index(cs.idx).Addr()
} }

View File

@ -96,7 +96,7 @@ func BenchmarkOriQuery(b *testing.B) {
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
//fmt.Println(Id, Name, Title, Age, Alias, NickName) // fmt.Println(Id, Name, Title, Age, Alias, NickName)
} }
rows.Close() rows.Close()
} }
@ -245,13 +245,13 @@ func BenchmarkSliceInterfaceQuery(b *testing.B) {
b.Error(err) b.Error(err)
} }
b.Log(slice) b.Log(slice)
switch slice[1].(type) { switch st := slice[1].(type) {
case *string: case *string:
if *slice[1].(*string) != "xlw" { if *st != "xlw" {
b.Error(errors.New("name should be xlw")) b.Error(errors.New("name should be xlw"))
} }
case []byte: case []byte:
if string(slice[1].([]byte)) != "xlw" { if string(st) != "xlw" {
b.Error(errors.New("name should be xlw")) b.Error(errors.New("name should be xlw"))
} }
} }
@ -399,14 +399,14 @@ func BenchmarkMapInterfaceQuery(b *testing.B) {
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
switch m["name"].(type) { switch t := m["name"].(type) {
case string: case string:
if m["name"].(string) != "xlw" { if t != "xlw" {
b.Log(m) b.Log(m)
b.Error(errors.New("name should be xlw")) b.Error(errors.New("name should be xlw"))
} }
case []byte: case []byte:
if string(m["name"].([]byte)) != "xlw" { if string(t) != "xlw" {
b.Log(m) b.Log(m)
b.Error(errors.New("name should be xlw")) 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 _, vvv := range vvvs {
for j := 0; j < vvv.NumField(); j++ { for j := 0; j < vvv.NumField(); j++ {
newDest[i] = vvv.Field(j).Addr().Interface() 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 { if err != nil {
return nil, err return nil, err
} }
res, err := s.Stmt.ExecContext(ctx, args) res, err := s.Stmt.ExecContext(ctx, args...)
hookCtx.End(ctx, res, err) hookCtx.End(ctx, res, err)
if err := s.db.afterProcess(hookCtx); err != nil { if err := s.db.afterProcess(hookCtx); err != nil {
return nil, err 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 // Dialect represents a kind of database
type Dialect interface { type Dialect interface {
Init(*URI) error Init(*URI) error
URI() *URI URI() *URI
Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error)
Features() *DialectFeatures
SQLType(*schemas.Column) string SQLType(*schemas.Column) string
Alias(string) string // return what a sql type's alias of 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) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error)
IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, 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) 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) 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) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName string, colName string) (bool, error)
AddColumnSQL(tableName string, col *schemas.Column) string AddColumnSQL(tableName string, col *schemas.Column) string
@ -103,6 +119,59 @@ func (db *Base) URI() *URI {
return db.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 // DropTableSQL returns drop table SQL
func (db *Base) DropTableSQL(tableName string) (string, bool) { func (db *Base) DropTableSQL(tableName string) (string, bool) {
quote := db.dialect.Quoter().Quote 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 // AddColumnSQL returns a SQL to add a column
func (db *Base) AddColumnSQL(tableName string, col *schemas.Column) string { func (db *Base) AddColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, true) 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 // 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 // ModifyColumnSQL returns a SQL to modify SQL
func (db *Base) ModifyColumnSQL(tableName string, col *schemas.Column) string { func (db *Base) ModifyColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, false) 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 // ForUpdateSQL returns for updateSQL
@ -252,43 +321,41 @@ func ColumnString(dialect Dialect, col *schemas.Column, includePrimaryKey bool)
return "", err return "", err
} }
if err := bd.WriteByte(' '); err != nil {
return "", err
}
if includePrimaryKey && col.IsPrimaryKey { if includePrimaryKey && col.IsPrimaryKey {
if _, err := bd.WriteString("PRIMARY KEY "); err != nil { if _, err := bd.WriteString(" PRIMARY KEY"); err != nil {
return "", err return "", err
} }
if col.IsAutoIncrement { if col.IsAutoIncrement {
if _, err := bd.WriteString(dialect.AutoIncrStr()); err != nil {
return "", err
}
if err := bd.WriteByte(' '); err != nil { if err := bd.WriteByte(' '); err != nil {
return "", err return "", err
} }
if _, err := bd.WriteString(dialect.AutoIncrStr()); err != nil {
return "", err
}
} }
} }
if col.Default != "" { if !col.DefaultIsEmpty {
if _, err := bd.WriteString("DEFAULT "); err != nil { if _, err := bd.WriteString(" DEFAULT "); err != nil {
return "", err return "", err
} }
if _, err := bd.WriteString(col.Default); err != nil { if col.Default == "" {
return "", err if _, err := bd.WriteString("''"); err != nil {
} return "", err
if err := bd.WriteByte(' '); err != nil { }
return "", err } else {
if _, err := bd.WriteString(col.Default); err != nil {
return "", err
}
} }
} }
if col.Nullable { if col.Nullable {
if _, err := bd.WriteString("NULL "); err != nil { if _, err := bd.WriteString(" NULL"); err != nil {
return "", err return "", err
} }
} else { } else {
if _, err := bd.WriteString("NOT NULL "); err != nil { if _, err := bd.WriteString(" NOT NULL"); err != nil {
return "", err return "", err
} }
} }

View File

@ -282,6 +282,12 @@ func (db *mssql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Ve
}, nil }, nil
} }
func (db *mssql) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *mssql) SQLType(c *schemas.Column) string { func (db *mssql) SQLType(c *schemas.Column) string {
var res string var res string
switch t := c.SQLType.Name; t { 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 { func (db *mssql) ModifyColumnSQL(tableName string, col *schemas.Column) string {
s, _ := ColumnString(db.dialect, col, false) 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{}) { 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 return indexes, nil
} }
func (db *mssql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { func (db *mssql) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
var sql string
if tableName == "" { if tableName == "" {
tableName = table.Name 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) + " (" for i, colName := range table.ColumnsSeq() {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName) col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1) s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1)
sql += s b.WriteString(s)
sql = strings.TrimSpace(sql)
sql += ", " if i != len(table.ColumnsSeq())-1 {
b.WriteString(", ")
}
} }
if len(pkList) > 1 { if len(table.PrimaryKeys) > 1 {
sql += "PRIMARY KEY ( " b.WriteString(", PRIMARY KEY (")
sql += strings.Join(pkList, ",") b.WriteString(quoter.Join(table.PrimaryKeys, ","))
sql += " ), " b.WriteString(")")
} }
sql = sql[:len(sql)-2] + ")" b.WriteString(")")
sql += ";"
return []string{sql}, true return b.String(), true, nil
} }
func (db *mssql) ForUpdateSQL(query string) string { func (db *mssql) ForUpdateSQL(query string) string {

View File

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

View File

@ -539,6 +539,12 @@ func (db *oracle) Version(ctx context.Context, queryer core.Queryer) (*schemas.V
}, nil }, nil
} }
func (db *oracle) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: SequenceAutoincrMode,
}
}
func (db *oracle) SQLType(c *schemas.Column) string { func (db *oracle) SQLType(c *schemas.Column) string {
var res string var res string
switch t := c.SQLType.Name; t { 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 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 " var sql = "CREATE TABLE "
if tableName == "" { if tableName == "" {
tableName = table.Name tableName = table.Name
@ -629,7 +635,7 @@ func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]stri
} }
sql = sql[:len(sql)-2] + ")" sql = sql[:len(sql)-2] + ")"
return []string{sql}, false return sql, false, nil
} }
func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) { func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) {

View File

@ -941,6 +941,12 @@ func (db *postgres) SQLType(c *schemas.Column) string {
return res return res
} }
func (db *postgres) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *postgres) ColumnTypeKind(t string) int { func (db *postgres) ColumnTypeKind(t string) int {
switch strings.ToUpper(t) { switch strings.ToUpper(t) {
case "DATETIME", "TIMESTAMP": case "DATETIME", "TIMESTAMP":
@ -965,41 +971,6 @@ func (db *postgres) AutoIncrStr() string {
return "" 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{}) { func (db *postgres) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
if len(db.getSchema()) == 0 { if len(db.getSchema()) == 0 {
args := []interface{}{tableName, idxName} args := []interface{}{tableName, idxName}
@ -1020,13 +991,37 @@ func (db *postgres) IsTableExist(queryer core.Queryer, ctx context.Context, tabl
db.getSchema(), tableName) 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, ".") { if len(db.getSchema()) == 0 || strings.Contains(tableName, ".") {
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", addColumnSQL = fmt.Sprintf("ALTER TABLE %s ADD %s", quoter.Quote(tableName), s)
tableName, 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 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 { 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 + "'" col.Default = "'" + col.Default + "'"
} }
} else if col.SQLType.IsTime() { } 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 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" s := "SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1"
if len(db.getSchema()) != 0 { if len(db.getSchema()) != 0 {
args = append(args, db.getSchema()) args = append(args, db.getSchema())
s = s + " AND schemaname=$2" s += " AND schemaname=$2"
} }
rows, err := queryer.QueryContext(ctx, s, args...) 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 indexType = schemas.IndexType
} }
colNames = getIndexColName(indexdef) 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 var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
newIdxName := indexName[5+len(tableName):] newIdxName := indexName[5+len(tableName):]
@ -1331,6 +1337,26 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN
return indexes, nil 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 { func (db *postgres) Filters() []Filter {
return []Filter{&SeqFilter{Prefix: "$", Start: 1}} return []Filter{&SeqFilter{Prefix: "$", Start: 1}}
} }

View File

@ -184,6 +184,12 @@ func (db *sqlite3) Version(ctx context.Context, queryer core.Queryer) (*schemas.
}, nil }, nil
} }
func (db *sqlite3) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: IncrAutoincrMode,
}
}
func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) { func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) {
switch quotePolicy { switch quotePolicy {
case QuotePolicyNone: 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)) 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 { func (db *sqlite3) ForUpdateSQL(query string) string {
return query return query
} }

View File

@ -17,8 +17,7 @@ import (
func TableNameWithSchema(dialect Dialect, tableName string) string { func TableNameWithSchema(dialect Dialect, tableName string) string {
// Add schema name as prefix of table name. // Add schema name as prefix of table name.
// Only for postgres database. // Only for postgres database.
if dialect.URI().Schema != "" && if dialect.URI().Schema != "" && !strings.Contains(tableName, ".") {
strings.Index(tableName, ".") == -1 {
return fmt.Sprintf("%s.%s", dialect.URI().Schema, tableName) return fmt.Sprintf("%s.%s", dialect.URI().Schema, tableName)
} }
return tableName return tableName
@ -27,20 +26,18 @@ func TableNameWithSchema(dialect Dialect, tableName string) string {
// TableNameNoSchema returns table name with given tableName // TableNameNoSchema returns table name with given tableName
func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface{}) string { func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface{}) string {
quote := dialect.Quoter().Quote quote := dialect.Quoter().Quote
switch tableName.(type) { switch tt := tableName.(type) {
case []string: case []string:
t := tableName.([]string) if len(tt) > 1 {
if len(t) > 1 { return fmt.Sprintf("%v AS %v", quote(tt[0]), quote(tt[1]))
return fmt.Sprintf("%v AS %v", quote(t[0]), quote(t[1])) } else if len(tt) == 1 {
} else if len(t) == 1 { return quote(tt[0])
return quote(t[0])
} }
case []interface{}: case []interface{}:
t := tableName.([]interface{}) l := len(tt)
l := len(t)
var table string var table string
if l > 0 { if l > 0 {
f := t[0] f := tt[0]
switch f.(type) { switch f.(type) {
case string: case string:
table = f.(string) table = f.(string)
@ -57,7 +54,7 @@ func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface
} }
} }
if l > 1 { 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 { } else if l == 1 {
return quote(table) 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) has, err := engine.Table("user").Where("name = ?", name).Get(&id)
// SELECT id FROM user WHERE name = ? LIMIT 1 // 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 3. Query multiple records from database
var sliceOfStructs []Struct var sliceOfStructs []Struct
@ -97,6 +102,17 @@ another is Rows
err = rows.Scan(bean) 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 5. Update one or more records
affected, err := engine.ID(...).Update(&user) affected, err := engine.ID(...).Update(&user)

395
engine.go
View File

@ -7,12 +7,13 @@ package xorm
import ( import (
"context" "context"
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"reflect" "reflect"
"regexp"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
@ -248,11 +249,6 @@ func (engine *Engine) SQLType(c *schemas.Column) string {
return engine.dialect.SQLType(c) 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. // SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) { func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.DB().SetConnMaxLifetime(d) 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 // DumpTables dump specify tables to io.Writer
func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error { 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 { func formatBool(s bool, dstDialect dialects.Dialect) string {
if dstDialect.URI().DBType == schemas.MSSQL { if dstDialect.URI().DBType != schemas.POSTGRES {
switch s { if s {
case "true":
return "1" 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 // 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 var dstDialect dialects.Dialect
if len(tp) == 0 { if len(tp) == 0 {
dstDialect = engine.dialect dstDialect = engine.dialect
@ -471,9 +467,14 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
destURI := dialects.URI{ destURI := dialects.URI{
DBType: tp[0], DBType: tp[0],
DBName: uri.DBName, 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() cacherMgr := caches.NewManager()
dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper(), cacherMgr) 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 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 { for i, table := range tables {
dstTable := table dstTable := table
if table.Type != nil { 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 != "" { if dstDialect.URI().Schema != "" {
dstTableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, dstTable.Name) 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 originalTableName := table.Name
if engine.dialect.URI().Schema != "" { 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) if dstTable.AutoIncrement != "" && dstDialect.Features().AutoincrMode == dialects.SequenceAutoincrMode {
for _, s := range sqls { sqlstr, err := dstDialect.CreateSequenceSQL(ctx, engine.db, utils.SeqName(dstTableName))
_, err = io.WriteString(w, s+";\n") if err != nil {
return err
}
_, err = io.WriteString(w, sqlstr+";\n")
if err != nil { if err != nil {
return err 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 { if len(dstTable.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", dstTable.Name) 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() sess := engine.NewSession()
defer sess.Close() defer sess.Close()
for rows.Next() { 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 { if err != nil {
return err return err
} }
@ -563,36 +587,208 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
} }
for i, scanResult := range scanResults { for i, scanResult := range scanResults {
stp := schemas.SQLType{Name: types[i].DatabaseTypeName()} stp := schemas.SQLType{Name: types[i].DatabaseTypeName()}
if stp.IsNumeric() { s := scanResult.(*sql.NullString)
s := scanResult.(*sql.NullString) if !s.Valid {
if s.Valid { if _, err = io.WriteString(w, "NULL"); err != nil {
if _, err = io.WriteString(w, formatBool(s.String, dstDialect)); err != nil { return err
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
}
} }
} else { } else {
s := scanResult.(*sql.NullString) if table.Columns()[i].SQLType.IsBool() || stp.IsBool() || (dstDialect.URI().DBType == schemas.MSSQL && strings.EqualFold(stp.Name, schemas.Bit)) {
if s.Valid { val, err := strconv.ParseBool(s.String)
if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil { if err != nil {
return err 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 { } else {
if _, err = io.WriteString(w, "NULL"); err != nil { if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil {
return err return err
} }
} }
@ -923,104 +1119,13 @@ func (engine *Engine) UnMapType(t reflect.Type) {
func (engine *Engine) Sync(beans ...interface{}) error { func (engine *Engine) Sync(beans ...interface{}) error {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.Sync(beans...)
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
} }
// Sync2 synchronize structs to database tables // Sync2 synchronize structs to database tables
// Depricated
func (engine *Engine) Sync2(beans ...interface{}) error { func (engine *Engine) Sync2(beans ...interface{}) error {
s := engine.NewSession() return engine.Sync(beans...)
defer s.Close()
return s.Sync2(beans...)
} }
// CreateTables create tabls according bean // CreateTables create tabls according bean
@ -1036,7 +1141,7 @@ func (engine *Engine) CreateTables(beans ...interface{}) error {
for _, bean := range beans { for _, bean := range beans {
err = session.createTable(bean) err = session.createTable(bean)
if err != nil { if err != nil {
session.Rollback() _ = session.Rollback()
return err return err
} }
} }
@ -1056,7 +1161,7 @@ func (engine *Engine) DropTables(beans ...interface{}) error {
for _, bean := range beans { for _, bean := range beans {
err = session.dropTable(bean) err = session.dropTable(bean)
if err != nil { if err != nil {
session.Rollback() _ = session.Rollback()
return err 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 // Get retrieve one record from table, bean's non-empty fields
// are conditions // are conditions
func (engine *Engine) Get(bean interface{}) (bool, error) { func (engine *Engine) Get(beans ...interface{}) (bool, error) {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.Get(bean) return session.Get(beans...)
} }
// Exist returns true if the record exist otherwise return false // 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 go 1.13
require ( require (
gitee.com/travelliu/dm v1.8.11192
github.com/denisenkom/go-mssqldb v0.10.0 github.com/denisenkom/go-mssqldb v0.10.0
github.com/go-sql-driver/mysql v1.6.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/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/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/shopspring/decimal v1.2.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/ziutek/mymysql v1.5.4 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 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= 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 h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= 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/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/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 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 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 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/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.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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 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 h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 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/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.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 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/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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.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/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/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 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.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.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.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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 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 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 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-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.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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 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.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/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.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= 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-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-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-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-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-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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= 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= 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 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= 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/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.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 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= 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.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.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.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/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/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.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 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w= modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE=
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A= 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 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= 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.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI= 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 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= 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.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 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= 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= 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) cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher) testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox))) assert.NoError(t, testEngine.Sync(new(MailBox)))
var inserts = []*MailBox{ var inserts = []*MailBox{
{ {
@ -62,7 +62,8 @@ func TestCacheFind(t *testing.T) {
} }
boxes = make([]MailBox, 0, 2) 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)) assert.EqualValues(t, 2, len(boxes))
for i, box := range boxes { for i, box := range boxes {
assert.Equal(t, inserts[i].Id, box.Id) assert.Equal(t, inserts[i].Id, box.Id)
@ -77,7 +78,8 @@ func TestCacheFind(t *testing.T) {
} }
boxes2 := make([]MailBox4, 0, 2) 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)) assert.EqualValues(t, 2, len(boxes2))
for i, box := range boxes2 { for i, box := range boxes2 {
assert.Equal(t, inserts[i].Id, box.Id) 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) cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher) testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox2))) assert.NoError(t, testEngine.Sync(new(MailBox2)))
var inserts = []*MailBox2{ var inserts = []*MailBox2{
{ {
@ -152,7 +154,7 @@ func TestCacheGet(t *testing.T) {
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000) cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
testEngine.SetDefaultCacher(cacher) testEngine.SetDefaultCacher(cacher)
assert.NoError(t, testEngine.Sync2(new(MailBox3))) assert.NoError(t, testEngine.Sync(new(MailBox3)))
var inserts = []*MailBox3{ var inserts = []*MailBox3{
{ {
@ -164,14 +166,14 @@ func TestCacheGet(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
var box1 MailBox3 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, "user1", box1.Username) assert.EqualValues(t, "user1", box1.Username)
assert.EqualValues(t, "pass1", box1.Password) assert.EqualValues(t, "pass1", box1.Password)
var box2 MailBox3 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, "user1", box2.Username) 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"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
_ "gitee.com/travelliu/dm"
_ "github.com/denisenkom/go-mssqldb" _ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
_ "github.com/jackc/pgx/v4/stdlib" _ "github.com/jackc/pgx/v4/stdlib"
@ -52,17 +53,18 @@ func TestAutoTransaction(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(TestTx))) assert.NoError(t, testEngine.Sync(new(TestTx)))
engine := testEngine.(*xorm.Engine) engine := testEngine.(*xorm.Engine)
// will success // 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"}) _, err := session.Insert(TestTx{Msg: "hi"})
assert.NoError(t, err) assert.NoError(t, err)
return nil, nil return nil, nil
}) })
assert.NoError(t, err)
has, err := engine.Exist(&TestTx{Msg: "hi"}) has, err := engine.Exist(&TestTx{Msg: "hi"})
assert.NoError(t, err) assert.NoError(t, err)
@ -86,7 +88,7 @@ func assertSync(t *testing.T, beans ...interface{}) {
for _, bean := range beans { for _, bean := range beans {
t.Run(testEngine.TableName(bean, true), func(t *testing.T) { t.Run(testEngine.TableName(bean, true), func(t *testing.T) {
assert.NoError(t, testEngine.DropTables(bean)) 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) { func TestDumpTables(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
type TestDumpTableStruct struct { type TestDumpTableStruct struct {
Id int64 Id int64
Data []byte `xorm:"BLOB"`
Name string Name string
IsMan bool IsMan bool
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
@ -146,13 +151,18 @@ func TestDumpTables(t *testing.T) {
assertSync(t, new(TestDumpTableStruct)) assertSync(t, new(TestDumpTableStruct))
testEngine.Insert([]TestDumpTableStruct{ _, err := testEngine.Insert([]TestDumpTableStruct{
{Name: "1", IsMan: true}, {Name: "1", IsMan: true},
{Name: "2\n"}, {Name: "2\n", Data: []byte{'\000', '\001', '\002'}},
{Name: "3;"}, {Name: "3;", Data: []byte("0x000102")},
{Name: "4\n;\n''"}, {Name: "4\n;\n''", Data: []byte("Help")},
{Name: "5'\n"}, {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) fp := fmt.Sprintf("%v-table.sql", testEngine.Dialect().URI().DBType)
os.Remove(fp) os.Remove(fp)
@ -169,7 +179,7 @@ func TestDumpTables(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, sess.Commit()) 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) name := fmt.Sprintf("dump_%v-table.sql", tp)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, name, tp)) 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 Name string
} }
assert.NoError(b, testEngine.Sync2(new(BenchmarkGetVars))) assert.NoError(b, testEngine.Sync(new(BenchmarkGetVars)))
var v = BenchmarkGetVars{ var v = BenchmarkGetVars{
Name: "myname", Name: "myname",
@ -32,7 +32,7 @@ func BenchmarkGetVars(b *testing.B) {
b.StartTimer() b.StartTimer()
var myname string var myname string
for i := 0; i < b.N; i++ { 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() b.StopTimer()
myname = "" myname = ""
assert.True(b, has) assert.True(b, has)
@ -52,7 +52,7 @@ func BenchmarkGetStruct(b *testing.B) {
Name string Name string
} }
assert.NoError(b, testEngine.Sync2(new(BenchmarkGetStruct))) assert.NoError(b, testEngine.Sync(new(BenchmarkGetStruct)))
var v = BenchmarkGetStruct{ var v = BenchmarkGetStruct{
Name: "myname", Name: "myname",
@ -84,7 +84,7 @@ func BenchmarkFindStruct(b *testing.B) {
Name string Name string
} }
assert.NoError(b, testEngine.Sync2(new(BenchmarkFindStruct))) assert.NoError(b, testEngine.Sync(new(BenchmarkFindStruct)))
var v = BenchmarkFindStruct{ var v = BenchmarkFindStruct{
Name: "myname", Name: "myname",
@ -92,8 +92,8 @@ func BenchmarkFindStruct(b *testing.B) {
_, err := testEngine.Insert(&v) _, err := testEngine.Insert(&v)
assert.NoError(b, err) assert.NoError(b, err)
b.StartTimer()
var mynames = make([]BenchmarkFindStruct, 0, 1) var mynames = make([]BenchmarkFindStruct, 0, 1)
b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
err := testEngine.Find(&mynames) err := testEngine.Find(&mynames)
b.StopTimer() b.StopTimer()

View File

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

View File

@ -18,7 +18,7 @@ func TestRows(t *testing.T) {
IsMan bool IsMan bool
} }
assert.NoError(t, testEngine.Sync2(new(UserRows))) assert.NoError(t, testEngine.Sync(new(UserRows)))
cnt, err := testEngine.Insert(&UserRows{ cnt, err := testEngine.Insert(&UserRows{
IsMan: true, IsMan: true,
@ -94,7 +94,7 @@ func TestRowsMyTableName(t *testing.T) {
var tableName = "user_rows_my_table_name" 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{ cnt, err := testEngine.Table(tableName).Insert(&UserRowsMyTable{
IsMan: true, IsMan: true,
@ -141,7 +141,7 @@ func (UserRowsSpecTable) TableName() string {
func TestRowsSpecTableName(t *testing.T) { func TestRowsSpecTableName(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(UserRowsSpecTable))) assert.NoError(t, testEngine.Sync(new(UserRowsSpecTable)))
cnt, err := testEngine.Insert(&UserRowsSpecTable{ cnt, err := testEngine.Insert(&UserRowsSpecTable{
IsMan: true, IsMan: true,
@ -160,5 +160,49 @@ func TestRowsSpecTableName(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
cnt++ cnt++
} }
assert.NoError(t, rows.Err())
assert.EqualValues(t, 1, cnt) 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 Title string
} }
assert.NoError(t, testEngine.Sync2(new(UserExprIssue))) assert.NoError(t, testEngine.Sync(new(UserExprIssue)))
var issue = UserExprIssue{ var issue = UserExprIssue{
Title: "my issue", Title: "my issue",
@ -36,7 +36,7 @@ func TestSetExpr(t *testing.T) {
Show bool Show bool
} }
assert.NoError(t, testEngine.Sync2(new(UserExpr))) assert.NoError(t, testEngine.Sync(new(UserExpr)))
cnt, err = testEngine.Insert(&UserExpr{ cnt, err = testEngine.Insert(&UserExpr{
Show: true, Show: true,
@ -45,7 +45,7 @@ func TestSetExpr(t *testing.T) {
assert.EqualValues(t, 1, cnt) assert.EqualValues(t, 1, cnt)
var not = "NOT" var not = "NOT"
if testEngine.Dialect().URI().DBType == schemas.MSSQL { if testEngine.Dialect().URI().DBType == schemas.MSSQL || testEngine.Dialect().URI().DBType == schemas.DAMENG {
not = "~" not = "~"
} }
cnt, err = testEngine.SetExpr("show", not+" `show`").ID(1).Update(new(UserExpr)) 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) tableName := testEngine.TableName(new(UserExprIssue), true)
cnt, err = testEngine.SetExpr("issue_id", cnt, err = testEngine.SetExpr("issue_id",
builder.Select("id"). builder.Select("`id`").
From(tableName). From(testEngine.Quote(tableName)).
Where(builder.Eq{"id": issue.Id})). Where(builder.Eq{"`id`": issue.Id})).
ID(1). ID(1).
Update(new(UserExpr)) Update(new(UserExpr))
assert.NoError(t, err) assert.NoError(t, err)

View File

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

View File

@ -17,7 +17,7 @@ func TestCount(t *testing.T) {
type UserinfoCount struct { type UserinfoCount struct {
Departname string Departname string
} }
assert.NoError(t, testEngine.Sync2(new(UserinfoCount))) assert.NoError(t, testEngine.Sync(new(UserinfoCount)))
colName := testEngine.GetColumnMapper().Obj2Table("Departname") colName := testEngine.GetColumnMapper().Obj2Table("Departname")
var cond builder.Cond = builder.Eq{ var cond builder.Cond = builder.Eq{
@ -63,7 +63,7 @@ func TestSQLCount(t *testing.T) {
assertSync(t, new(UserinfoCount2), new(UserinfoBooks)) 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() Count()
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 0, total) assert.EqualValues(t, 0, total)
@ -89,7 +89,7 @@ func TestCountWithOthers(t *testing.T) {
}) })
assert.NoError(t, err) 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.NoError(t, err)
assert.EqualValues(t, 2, total) assert.EqualValues(t, 2, total)
} }
@ -118,11 +118,11 @@ func TestWithTableName(t *testing.T) {
}) })
assert.NoError(t, err) 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.NoError(t, err)
assert.EqualValues(t, 2, total) 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.NoError(t, err)
assert.EqualValues(t, 2, total) assert.EqualValues(t, 2, total)
} }
@ -146,7 +146,7 @@ func TestCountWithSelectCols(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 2, total) 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.NoError(t, err)
assert.EqualValues(t, 2, total) assert.EqualValues(t, 2, total)
} }
@ -166,7 +166,7 @@ func TestCountWithGroupBy(t *testing.T) {
}) })
assert.NoError(t, err) 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.NoError(t, err)
assert.EqualValues(t, 2, cnt) assert.EqualValues(t, 2, cnt)
} }

View File

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

View File

@ -48,19 +48,19 @@ func TestExistStruct(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, has) 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.NoError(t, err)
assert.True(t, has) 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.NoError(t, err)
assert.False(t, has) 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.NoError(t, err)
assert.True(t, has) 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.NoError(t, err)
assert.False(t, has) assert.False(t, has)
@ -68,11 +68,11 @@ func TestExistStruct(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) 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.NoError(t, err)
assert.True(t, has) 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.NoError(t, err)
assert.False(t, has) assert.False(t, has)
@ -99,7 +99,7 @@ func TestExistStructForJoin(t *testing.T) {
Name string 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 var ply Player
cnt, err := testEngine.Insert(&ply) cnt, err := testEngine.Insert(&ply)
@ -124,43 +124,43 @@ func TestExistStructForJoin(t *testing.T) {
defer session.Close() defer session.Close()
session.Table("number"). session.Table("number").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid"). Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("number.lid = ?", 1) Where("`number`.`lid` = ?", 1)
has, err := session.Exist() has, err := session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
session.Table("number"). session.Table("number").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid"). Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("number.lid = ?", 2) Where("`number`.`lid` = ?", 2)
has, err = session.Exist() has, err = session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, has) assert.False(t, has)
session.Table("number"). session.Table("number").
Select("order_list.id"). Select("`order_list`.`id`").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid"). Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("order_list.id = ?", 1) Where("`order_list`.`id` = ?", 1)
has, err = session.Exist() has, err = session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
session.Table("number"). session.Table("number").
Select("player.id"). Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid"). Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`").
Where("player.id = ?", 2) Where("`player`.`id` = ?", 2)
has, err = session.Exist() has, err = session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, has) assert.False(t, has)
session.Table("number"). session.Table("number").
Select("player.id"). Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid") Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`")
has, err = session.Exist() has, err = session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
@ -174,15 +174,15 @@ func TestExistStructForJoin(t *testing.T) {
session.Table("number"). session.Table("number").
Select("player.id"). Select("player.id").
Join("INNER", "order_list", "order_list.id = number.lid"). Join("INNER", "order_list", "`order_list`.`id` = `number`.`lid`").
Join("LEFT", "player", "player.id = order_list.eid") Join("LEFT", "player", "`player`.`id` = `order_list`.`eid`")
has, err = session.Exist() has, err = session.Exist()
assert.Error(t, err) assert.Error(t, err)
assert.False(t, has) assert.False(t, has)
session.Table("number"). session.Table("number").
Select("player.id"). Select("player.id").
Join("LEFT", "player", "player.id = number.lid") Join("LEFT", "player", "`player`.`id` = `number`.`lid`")
has, err = session.Exist() has, err = session.Exist()
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)

View File

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

View File

@ -15,6 +15,7 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
"xorm.io/xorm/contexts" "xorm.io/xorm/contexts"
"xorm.io/xorm/convert" "xorm.io/xorm/convert"
"xorm.io/xorm/dialects"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
@ -32,7 +33,7 @@ func TestGetVar(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(GetVar))) assert.NoError(t, testEngine.Sync(new(GetVar)))
var data = GetVar{ var data = GetVar{
Msg: "hi", Msg: "hi",
@ -55,15 +56,15 @@ func TestGetVar(t *testing.T) {
assert.Equal(t, 28, age) assert.Equal(t, 28, age)
var ageMax int 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.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
assert.Equal(t, 28, ageMax) assert.Equal(t, 28, ageMax)
var age2 int64 var age2 int64
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age2) Get(&age2)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -77,8 +78,8 @@ func TestGetVar(t *testing.T) {
var age4 int16 var age4 int16
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age4) Get(&age4)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -86,8 +87,8 @@ func TestGetVar(t *testing.T) {
var age5 int32 var age5 int32
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age5) Get(&age5)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -101,8 +102,8 @@ func TestGetVar(t *testing.T) {
var age7 int64 var age7 int64
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age7) Get(&age7)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -116,8 +117,8 @@ func TestGetVar(t *testing.T) {
var age9 int16 var age9 int16
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age9) Get(&age9)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -125,8 +126,8 @@ func TestGetVar(t *testing.T) {
var age10 int32 var age10 int32
has, err = testEngine.Table("get_var").Cols("age"). has, err = testEngine.Table("get_var").Cols("age").
Where("age > ?", 20). Where("`age` > ?", 20).
And("age < ?", 30). And("`age` < ?", 30).
Get(&age10) Get(&age10)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
@ -161,16 +162,16 @@ func TestGetVar(t *testing.T) {
var money2 float64 var money2 float64
if testEngine.Dialect().URI().DBType == schemas.MSSQL { 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 { } 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.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
assert.Equal(t, "1.5", fmt.Sprintf("%.1f", money2)) assert.Equal(t, "1.5", fmt.Sprintf("%.1f", money2))
var money3 float64 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.NoError(t, err)
assert.Equal(t, false, has) 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 // for mymysql driver, interface{} will be []byte, so ignore it currently
if testEngine.DriverName() != "mymysql" { if testEngine.DriverName() != "mymysql" {
var valuesInter = make(map[string]interface{}) 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.NoError(t, err)
assert.Equal(t, true, has) assert.Equal(t, true, has)
assert.Equal(t, 5, len(valuesInter)) assert.Equal(t, 5, len(valuesInter))
@ -234,7 +235,7 @@ func TestGetStruct(t *testing.T) {
IsMan bool IsMan bool
} }
assert.NoError(t, testEngine.Sync2(new(UserinfoGet))) assert.NoError(t, testEngine.Sync(new(UserinfoGet)))
session := testEngine.NewSession() session := testEngine.NewSession()
defer session.Close() defer session.Close()
@ -243,7 +244,7 @@ func TestGetStruct(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.MSSQL { if testEngine.Dialect().URI().DBType == schemas.MSSQL {
err = session.Begin() err = session.Begin()
assert.NoError(t, err) 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) assert.NoError(t, err)
} }
cnt, err := session.Insert(&UserinfoGet{Uid: 2}) cnt, err := session.Insert(&UserinfoGet{Uid: 2})
@ -265,7 +266,7 @@ func TestGetStruct(t *testing.T) {
Total int64 Total int64
} }
assert.NoError(t, testEngine.Sync2(&NoIdUser{})) assert.NoError(t, testEngine.Sync(&NoIdUser{}))
userCol := testEngine.GetColumnMapper().Obj2Table("User") userCol := testEngine.GetColumnMapper().Obj2Table("User")
_, err = testEngine.Where("`"+userCol+"` = ?", "xlw").Delete(&NoIdUser{}) _, err = testEngine.Where("`"+userCol+"` = ?", "xlw").Delete(&NoIdUser{})
@ -300,6 +301,11 @@ func TestGetSlice(t *testing.T) {
func TestGetMap(t *testing.T) { func TestGetMap(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
if testEngine.Dialect().Features().AutoincrMode == dialects.SequenceAutoincrMode {
t.SkipNow()
return
}
type UserinfoMap struct { type UserinfoMap struct {
Uid int `xorm:"pk autoincr"` Uid int `xorm:"pk autoincr"`
IsMan bool IsMan bool
@ -308,7 +314,7 @@ func TestGetMap(t *testing.T) {
assertSync(t, new(UserinfoMap)) assertSync(t, new(UserinfoMap))
tableName := testEngine.Quote(testEngine.TableName("userinfo_map", true)) 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) assert.NoError(t, err)
var valuesString = make(map[string]string) var valuesString = make(map[string]string)
@ -479,7 +485,7 @@ func TestGetStructId(t *testing.T) {
//var id int64 //var id int64
var maxid maxidst 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) has, err := testEngine.SQL(sql).Get(&maxid)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
@ -570,7 +576,7 @@ func (MyGetCustomTableImpletation) TableName() string {
func TestGetCustomTableInterface(t *testing.T) { func TestGetCustomTableInterface(t *testing.T) {
assert.NoError(t, PrepareEngine()) 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) exist, err := testEngine.IsTableExist(getCustomTableName)
assert.NoError(t, err) assert.NoError(t, err)
@ -597,73 +603,78 @@ func TestGetNullVar(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assertSync(t, new(TestGetNullVarStruct)) 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) assert.NoError(t, err)
a, _ := affected.RowsAffected() a, _ := affected.RowsAffected()
assert.EqualValues(t, 1, a) assert.EqualValues(t, 1, a)
var name string 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, "", name) assert.EqualValues(t, "", name)
var age int 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age) assert.EqualValues(t, 0, age)
var age2 int8 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age2) assert.EqualValues(t, 0, age2)
var age3 int16 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age3) assert.EqualValues(t, 0, age3)
var age4 int32 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age4) assert.EqualValues(t, 0, age4)
var age5 int64 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age5) assert.EqualValues(t, 0, age5)
var age6 uint 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age6) assert.EqualValues(t, 0, age6)
var age7 uint8 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age7) assert.EqualValues(t, 0, age7)
var age8 int16 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age8) assert.EqualValues(t, 0, age8)
var age9 int32 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age9) assert.EqualValues(t, 0, age9)
var age10 int64 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 0, age10) assert.EqualValues(t, 0, age10)
@ -697,7 +708,7 @@ func TestCustomTypes(t *testing.T) {
assert.EqualValues(t, "test", name) assert.EqualValues(t, "test", name)
var age MyInt 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, 32, age) assert.EqualValues(t, 32, age)
@ -759,7 +770,7 @@ func TestGetBigFloat(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
var m big.Float 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String()) 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) assert.NoError(t, err)
var m2 big.Float 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.True(t, m2.String() == gf2.Money.String(), "%v != %v", m2.String(), gf2.Money.String()) 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) assert.NoError(t, err)
var m decimal.Decimal 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String()) 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) assert.NoError(t, err)
var m decimal.Decimal 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.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.True(t, m.String() == gf.Money.String(), "%v != %v", m.String(), gf.Money.String()) 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.True(t, has)
assert.EqualValues(t, gts.CreateTime.Format(time.RFC3339), gn.Format(time.RFC3339)) 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" "time"
"xorm.io/xorm" "xorm.io/xorm"
"xorm.io/xorm/schemas"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -24,7 +25,7 @@ func TestInsertOne(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(Test))) assert.NoError(t, testEngine.Sync(new(Test)))
data := Test{Msg: "hi"} data := Test{Msg: "hi"}
_, err := testEngine.InsertOne(data) _, err := testEngine.InsertOne(data)
@ -38,7 +39,7 @@ func TestInsertMulti(t *testing.T) {
Name string `xorm:"varchar(255)"` Name string `xorm:"varchar(255)"`
} }
assert.NoError(t, testEngine.Sync2(new(TestMulti))) assert.NoError(t, testEngine.Sync(new(TestMulti)))
num, err := insertMultiDatas(1, num, err := insertMultiDatas(1,
append([]TestMulti{}, TestMulti{1, "test1"}, TestMulti{2, "test2"}, TestMulti{3, "test3"})) 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 { if err = actionFunc(tempInterface); err != nil {
return return
} }
processedLen = processedLen - step processedLen -= step
} }
return return
} }
@ -114,7 +115,7 @@ func TestInsertOneIfPkIsPoint(t *testing.T) {
Created *time.Time `xorm:"created"` Created *time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(TestPoint))) assert.NoError(t, testEngine.Sync(new(TestPoint)))
msg := "hi" msg := "hi"
data := TestPoint{Msg: &msg} data := TestPoint{Msg: &msg}
_, err := testEngine.InsertOne(&data) _, err := testEngine.InsertOne(&data)
@ -130,7 +131,7 @@ func TestInsertOneIfPkIsPointRename(t *testing.T) {
Created *time.Time `xorm:"created"` Created *time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(TestPoint2))) assert.NoError(t, testEngine.Sync(new(TestPoint2)))
msg := "hi" msg := "hi"
data := TestPoint2{Msg: &msg} data := TestPoint2{Msg: &msg}
_, err := testEngine.InsertOne(&data) _, err := testEngine.InsertOne(&data)
@ -180,7 +181,7 @@ func TestInsertDefault(t *testing.T) {
} }
di := new(DefaultInsert) di := new(DefaultInsert)
err := testEngine.Sync2(di) err := testEngine.Sync(di)
assert.NoError(t, err) assert.NoError(t, err)
var di2 = DefaultInsert{Name: "test"} var di2 = DefaultInsert{Name: "test"}
@ -191,8 +192,8 @@ func TestInsertDefault(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, -1, di.Status) assert.EqualValues(t, -1, di.Status)
assert.EqualValues(t, di2.Updated.Unix(), di.Updated.Unix()) assert.EqualValues(t, di2.Updated.Unix(), di.Updated.Unix(), di.Updated)
assert.EqualValues(t, di2.Created.Unix(), di.Created.Unix()) assert.EqualValues(t, di2.Created.Unix(), di.Created.Unix(), di.Created)
} }
func TestInsertDefault2(t *testing.T) { func TestInsertDefault2(t *testing.T) {
@ -206,7 +207,7 @@ func TestInsertDefault2(t *testing.T) {
} }
di := new(DefaultInsert2) di := new(DefaultInsert2)
err := testEngine.Sync2(di) err := testEngine.Sync(di)
assert.NoError(t, err) assert.NoError(t, err)
var di2 = DefaultInsert2{Name: "test"} var di2 = DefaultInsert2{Name: "test"}
@ -257,7 +258,7 @@ func TestInsertCreated(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
di := new(CreatedInsert) di := new(CreatedInsert)
err := testEngine.Sync2(di) err := testEngine.Sync(di)
assert.NoError(t, err) assert.NoError(t, err)
ci := &CreatedInsert{} ci := &CreatedInsert{}
@ -270,7 +271,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci.Created.Unix(), di.Created.Unix()) assert.EqualValues(t, ci.Created.Unix(), di.Created.Unix())
di2 := new(CreatedInsert2) di2 := new(CreatedInsert2)
err = testEngine.Sync2(di2) err = testEngine.Sync(di2)
assert.NoError(t, err) assert.NoError(t, err)
ci2 := &CreatedInsert2{} ci2 := &CreatedInsert2{}
@ -283,7 +284,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci2.Created, di2.Created) assert.EqualValues(t, ci2.Created, di2.Created)
di3 := new(CreatedInsert3) di3 := new(CreatedInsert3)
err = testEngine.Sync2(di3) err = testEngine.Sync(di3)
assert.NoError(t, err) assert.NoError(t, err)
ci3 := &CreatedInsert3{} ci3 := &CreatedInsert3{}
@ -296,7 +297,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci3.Created, di3.Created) assert.EqualValues(t, ci3.Created, di3.Created)
di4 := new(CreatedInsert4) di4 := new(CreatedInsert4)
err = testEngine.Sync2(di4) err = testEngine.Sync(di4)
assert.NoError(t, err) assert.NoError(t, err)
ci4 := &CreatedInsert4{} ci4 := &CreatedInsert4{}
@ -309,7 +310,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci4.Created, di4.Created) assert.EqualValues(t, ci4.Created, di4.Created)
di5 := new(CreatedInsert5) di5 := new(CreatedInsert5)
err = testEngine.Sync2(di5) err = testEngine.Sync(di5)
assert.NoError(t, err) assert.NoError(t, err)
ci5 := &CreatedInsert5{} ci5 := &CreatedInsert5{}
@ -322,7 +323,7 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci5.Created.Unix(), di5.Created.Unix()) assert.EqualValues(t, ci5.Created.Unix(), di5.Created.Unix())
di6 := new(CreatedInsert6) di6 := new(CreatedInsert6)
err = testEngine.Sync2(di6) err = testEngine.Sync(di6)
assert.NoError(t, err) assert.NoError(t, err)
oldTime := time.Now().Add(-time.Hour) oldTime := time.Now().Add(-time.Hour)
@ -336,6 +337,42 @@ func TestInsertCreated(t *testing.T) {
assert.EqualValues(t, ci6.Created.Unix(), di6.Created.Unix()) 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 type JSONTime time.Time
func (j JSONTime) format() string { func (j JSONTime) format() string {
@ -389,7 +426,7 @@ func TestCreatedJsonTime(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
di5 := new(MyJSONTime) di5 := new(MyJSONTime)
err := testEngine.Sync2(di5) err := testEngine.Sync(di5)
assert.NoError(t, err) assert.NoError(t, err)
ci5 := &MyJSONTime{} ci5 := &MyJSONTime{}
@ -488,7 +525,7 @@ func TestInsertCreatedInt64(t *testing.T) {
Created int64 `xorm:"created"` Created int64 `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(TestCreatedInt64))) assert.NoError(t, testEngine.Sync(new(TestCreatedInt64)))
data := TestCreatedInt64{Msg: "hi"} data := TestCreatedInt64{Msg: "hi"}
now := time.Now() now := time.Now()
@ -624,6 +661,11 @@ func TestAnonymousStruct(t *testing.T) {
} }
func TestInsertMap(t *testing.T) { func TestInsertMap(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
type InsertMap struct { type InsertMap struct {
Id int64 Id int64
Width uint32 Width uint32
@ -727,7 +769,7 @@ func TestInsertWhere(t *testing.T) {
} }
inserted, err := testEngine.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). inserted, err := testEngine.SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Where("repo_id=?", 1). Where("`repo_id`=?", 1).
Insert(&i) Insert(&i)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, inserted) assert.EqualValues(t, 1, inserted)
@ -740,7 +782,12 @@ func TestInsertWhere(t *testing.T) {
i.Index = 1 i.Index = 1
assert.EqualValues(t, i, j) 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"). SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{ Insert(map[string]interface{}{
"repo_id": 1, "repo_id": 1,
@ -761,7 +808,7 @@ func TestInsertWhere(t *testing.T) {
assert.EqualValues(t, "trest2", j2.Name) assert.EqualValues(t, "trest2", j2.Name)
assert.EqualValues(t, 2, j2.Index) 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("`index`", "coalesce(MAX(`index`),0)+1").
SetExpr("repo_id", "1"). SetExpr("repo_id", "1").
Insert(map[string]string{ Insert(map[string]string{
@ -777,7 +824,7 @@ func TestInsertWhere(t *testing.T) {
assert.EqualValues(t, "trest3", j3.Name) assert.EqualValues(t, "trest3", j3.Name)
assert.EqualValues(t, 3, j3.Index) 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"). SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{ Insert(map[string]interface{}{
"repo_id": 1, "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, "10';delete * from insert_where; --", j4.Name)
assert.EqualValues(t, 4, j4.Index) 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"). SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{ Insert(map[string]interface{}{
"repo_id": 1, "repo_id": 1,
@ -846,6 +893,11 @@ func TestInsertExpr2(t *testing.T) {
assert.EqualValues(t, 1, ie2.RepoId) assert.EqualValues(t, 1, ie2.RepoId)
assert.EqualValues(t, true, ie2.IsTag) assert.EqualValues(t, true, ie2.IsTag)
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
inserted, err = testEngine.Table(new(InsertExprsRelease)). inserted, err = testEngine.Table(new(InsertExprsRelease)).
SetExpr("is_draft", true). SetExpr("is_draft", true).
SetExpr("num_commits", 0). SetExpr("num_commits", 0).
@ -880,7 +932,7 @@ func TestMultipleInsertTableName(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
tableName := `prd_nightly_rate_16` 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() trans := testEngine.NewSession()
defer trans.Close() defer trans.Close()
@ -916,7 +968,7 @@ func TestInsertMultiWithOmit(t *testing.T) {
Omitted string `xorm:"varchar(255) 'omitted'"` Omitted string `xorm:"varchar(255) 'omitted'"`
} }
assert.NoError(t, testEngine.Sync2(new(TestMultiOmit))) assert.NoError(t, testEngine.Sync(new(TestMultiOmit)))
l := []interface{}{ l := []interface{}{
TestMultiOmit{Id: 1, Name: "1", Omitted: "1"}, TestMultiOmit{Id: 1, Name: "1", Omitted: "1"},
@ -961,7 +1013,7 @@ func TestInsertTwice(t *testing.T) {
FieldB int 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 var sliceA []InsertStructA // sliceA is empty
sliceB := []InsertStructB{ sliceB := []InsertStructB{
@ -992,7 +1044,7 @@ func TestInsertIntSlice(t *testing.T) {
NameIDs []int `xorm:"json notnull"` NameIDs []int `xorm:"json notnull"`
} }
assert.NoError(t, testEngine.Sync2(new(InsertIntSlice))) assert.NoError(t, testEngine.Sync(new(InsertIntSlice)))
var v = InsertIntSlice{ var v = InsertIntSlice{
NameIDs: []int{1, 2}, NameIDs: []int{1, 2},
@ -1033,7 +1085,7 @@ func TestInsertDeleted(t *testing.T) {
DeletedAt time.Time `xorm:"'DELETED_AT' deleted notnull"` DeletedAt time.Time `xorm:"'DELETED_AT' deleted notnull"`
} }
// notnull tag will be ignored // notnull tag will be ignored
err := testEngine.Sync2(new(InsertDeletedStructNotRight)) err := testEngine.Sync(new(InsertDeletedStructNotRight))
assert.NoError(t, err) assert.NoError(t, err)
type InsertDeletedStruct struct { type InsertDeletedStruct struct {
@ -1041,7 +1093,7 @@ func TestInsertDeleted(t *testing.T) {
DeletedAt time.Time `xorm:"'DELETED_AT' deleted"` DeletedAt time.Time `xorm:"'DELETED_AT' deleted"`
} }
assert.NoError(t, testEngine.Sync2(new(InsertDeletedStruct))) assert.NoError(t, testEngine.Sync(new(InsertDeletedStruct)))
var v InsertDeletedStruct var v InsertDeletedStruct
_, err = testEngine.Insert(&v) _, err = testEngine.Insert(&v)
@ -1067,6 +1119,11 @@ func TestInsertDeleted(t *testing.T) {
} }
func TestInsertMultipleMap(t *testing.T) { func TestInsertMultipleMap(t *testing.T) {
if testEngine.Dialect().URI().DBType == schemas.DAMENG {
t.SkipNow()
return
}
type InsertMultipleMap struct { type InsertMultipleMap struct {
Id int64 Id int64
Width uint32 Width uint32

View File

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

View File

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

View File

@ -5,7 +5,6 @@
package integrations package integrations
import ( import (
"fmt"
"strconv" "strconv"
"testing" "testing"
"time" "time"
@ -27,7 +26,7 @@ func TestQueryString(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(GetVar2))) assert.NoError(t, testEngine.Sync(new(GetVar2)))
var data = GetVar2{ var data = GetVar2{
Msg: "hi", Msg: "hi",
@ -37,7 +36,7 @@ func TestQueryString(t *testing.T) {
_, err := testEngine.InsertOne(data) _, err := testEngine.InsertOne(data)
assert.NoError(t, err) 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.NoError(t, err)
assert.Equal(t, 1, len(records)) assert.Equal(t, 1, len(records))
assert.Equal(t, 5, len(records[0])) assert.Equal(t, 5, len(records[0]))
@ -55,7 +54,7 @@ func TestQueryString2(t *testing.T) {
Msg bool Msg bool
} }
assert.NoError(t, testEngine.Sync2(new(GetVar3))) assert.NoError(t, testEngine.Sync(new(GetVar3)))
var data = GetVar3{ var data = GetVar3{
Msg: false, Msg: false,
@ -63,7 +62,7 @@ func TestQueryString2(t *testing.T) {
_, err := testEngine.Insert(data) _, err := testEngine.Insert(data)
assert.NoError(t, err) 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.NoError(t, err)
assert.Equal(t, 1, len(records)) assert.Equal(t, 1, len(records))
assert.Equal(t, 2, len(records[0])) 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"]) 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 { func toBool(i interface{}) bool {
switch t := i.(type) { switch t := i.(type) {
case int32: case int32:
@ -128,7 +91,7 @@ func TestQueryInterface(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
assert.NoError(t, testEngine.Sync2(new(GetVarInterface))) assert.NoError(t, testEngine.Sync(new(GetVarInterface)))
var data = GetVarInterface{ var data = GetVarInterface{
Msg: "hi", Msg: "hi",
@ -138,7 +101,7 @@ func TestQueryInterface(t *testing.T) {
_, err := testEngine.InsertOne(data) _, err := testEngine.InsertOne(data)
assert.NoError(t, err) 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.NoError(t, err)
assert.Equal(t, 1, len(records)) assert.Equal(t, 1, len(records))
assert.Equal(t, 5, len(records[0])) assert.Equal(t, 5, len(records[0]))
@ -161,7 +124,7 @@ func TestQueryNoParams(t *testing.T) {
testEngine.ShowSQL(true) testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(QueryNoParams))) assert.NoError(t, testEngine.Sync(new(QueryNoParams)))
var q = QueryNoParams{ var q = QueryNoParams{
Msg: "message", Msg: "message",
@ -192,7 +155,7 @@ func TestQueryNoParams(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assertResult(t, results) 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) assert.NoError(t, err)
assertResult(t, results) assertResult(t, results)
} }
@ -205,7 +168,7 @@ func TestQueryStringNoParam(t *testing.T) {
Msg bool Msg bool
} }
assert.NoError(t, testEngine.Sync2(new(GetVar4))) assert.NoError(t, testEngine.Sync(new(GetVar4)))
var data = GetVar4{ var data = GetVar4{
Msg: false, Msg: false,
@ -223,7 +186,7 @@ func TestQueryStringNoParam(t *testing.T) {
assert.EqualValues(t, "0", records[0]["msg"]) 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.NoError(t, err)
assert.EqualValues(t, 1, len(records)) assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, "1", records[0]["id"]) assert.EqualValues(t, "1", records[0]["id"])
@ -242,7 +205,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
Msg bool Msg bool
} }
assert.NoError(t, testEngine.Sync2(new(GetVar6))) assert.NoError(t, testEngine.Sync(new(GetVar6)))
var data = GetVar6{ var data = GetVar6{
Msg: false, Msg: false,
@ -260,7 +223,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
assert.EqualValues(t, "0", records[0][1]) 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.NoError(t, err)
assert.EqualValues(t, 1, len(records)) assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, "1", records[0][0]) assert.EqualValues(t, "1", records[0][0])
@ -279,7 +242,7 @@ func TestQueryInterfaceNoParam(t *testing.T) {
Msg bool Msg bool
} }
assert.NoError(t, testEngine.Sync2(new(GetVar5))) assert.NoError(t, testEngine.Sync(new(GetVar5)))
var data = GetVar5{ var data = GetVar5{
Msg: false, Msg: false,
@ -293,7 +256,7 @@ func TestQueryInterfaceNoParam(t *testing.T) {
assert.EqualValues(t, 1, records[0]["id"]) assert.EqualValues(t, 1, records[0]["id"])
assert.False(t, toBool(records[0]["msg"])) 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.NoError(t, err)
assert.EqualValues(t, 1, len(records)) assert.EqualValues(t, 1, len(records))
assert.EqualValues(t, 1, records[0]["id"]) assert.EqualValues(t, 1, records[0]["id"])
@ -313,7 +276,7 @@ func TestQueryWithBuilder(t *testing.T) {
testEngine.ShowSQL(true) testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(QueryWithBuilder))) assert.NoError(t, testEngine.Sync(new(QueryWithBuilder)))
var q = QueryWithBuilder{ var q = QueryWithBuilder{
Msg: "message", Msg: "message",
@ -340,7 +303,7 @@ func TestQueryWithBuilder(t *testing.T) {
assert.EqualValues(t, 3000, money) 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) assert.NoError(t, err)
assertResult(t, results) assertResult(t, results)
} }
@ -362,7 +325,7 @@ func TestJoinWithSubQuery(t *testing.T) {
testEngine.ShowSQL(true) testEngine.ShowSQL(true)
assert.NoError(t, testEngine.Sync2(new(JoinWithSubQuery1), new(JoinWithSubQueryDepart))) assert.NoError(t, testEngine.Sync(new(JoinWithSubQuery1), new(JoinWithSubQueryDepart)))
var depart = JoinWithSubQueryDepart{ var depart = JoinWithSubQueryDepart{
Name: "depart1", Name: "depart1",
@ -383,14 +346,14 @@ func TestJoinWithSubQuery(t *testing.T) {
tbName := testEngine.Quote(testEngine.TableName("join_with_sub_query_depart", true)) tbName := testEngine.Quote(testEngine.TableName("join_with_sub_query_depart", true))
var querys []JoinWithSubQuery1 var querys []JoinWithSubQuery1
err = testEngine.Join("INNER", builder.Select("id").From(tbName), err = testEngine.Join("INNER", builder.Select("`id`").From(tbName),
"join_with_sub_query_depart.id = join_with_sub_query1.depart_id").Find(&querys) "`join_with_sub_query_depart`.`id` = `join_with_sub_query1`.`depart_id`").Find(&querys)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, len(querys)) assert.EqualValues(t, 1, len(querys))
assert.EqualValues(t, q, querys[0]) assert.EqualValues(t, q, querys[0])
querys = make([]JoinWithSubQuery1, 0, 1) 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) Find(&querys)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, len(querys)) assert.EqualValues(t, 1, len(querys))
@ -412,7 +375,7 @@ func TestQueryStringWithLimit(t *testing.T) {
Money float32 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() data, err := testEngine.Table("query_with_limit").Limit(20, 20).QueryString()
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -20,15 +20,15 @@ func TestExecAndQuery(t *testing.T) {
Name string 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) assert.NoError(t, err)
cnt, err := res.RowsAffected() cnt, err := res.RowsAffected()
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, cnt) 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.NoError(t, err)
assert.EqualValues(t, 1, len(results)) assert.EqualValues(t, 1, len(results))
id, err := strconv.Atoi(string(results[0]["uid"])) id, err := strconv.Atoi(string(results[0]["uid"]))
@ -46,21 +46,21 @@ func TestExecTime(t *testing.T) {
Created time.Time Created time.Time
} }
assert.NoError(t, testEngine.Sync2(new(UserinfoExecTime))) assert.NoError(t, testEngine.Sync(new(UserinfoExecTime)))
now := time.Now() 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) assert.NoError(t, err)
cnt, err := res.RowsAffected() cnt, err := res.RowsAffected()
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, cnt) 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.NoError(t, err)
assert.EqualValues(t, 1, len(results)) assert.EqualValues(t, 1, len(results))
assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), results[0]["created"]) assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), results[0]["created"])
var uet UserinfoExecTime var uet UserinfoExecTime
has, err := testEngine.Where("uid=?", 1).Get(&uet) has, err := testEngine.Where("`uid`=?", 1).Get(&uet)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) 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")) 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) { func TestSyncTable(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable1))) assert.NoError(t, testEngine.Sync(new(SyncTable1)))
tables, err := testEngine.DBMetas() tables, err := testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -183,7 +183,7 @@ func TestSyncTable(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name"))) 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() tables, err = testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -193,7 +193,7 @@ func TestSyncTable(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name"))) 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() tables, err = testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -207,7 +207,7 @@ func TestSyncTable(t *testing.T) {
func TestSyncTable2(t *testing.T) { func TestSyncTable2(t *testing.T) {
assert.NoError(t, PrepareEngine()) 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() tables, err := testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -220,7 +220,7 @@ func TestSyncTable2(t *testing.T) {
NewCol string 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() tables, err = testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, len(tables)) assert.EqualValues(t, 1, len(tables))
@ -241,7 +241,7 @@ func TestSyncTable3(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable5))) assert.NoError(t, testEngine.Sync(new(SyncTable5)))
tables, err := testEngine.DBMetas() tables, err := testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -272,7 +272,7 @@ func TestSyncTable3(t *testing.T) {
}() }()
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.Sync2(new(SyncTable5))) assert.NoError(t, testEngine.Sync(new(SyncTable5)))
tables, err := testEngine.DBMetas() tables, err := testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -294,9 +294,9 @@ func TestSyncTable4(t *testing.T) {
assert.NoError(t, PrepareEngine()) 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) { func TestIsTableExist(t *testing.T) {
@ -328,14 +328,14 @@ func TestIsTableEmpty(t *testing.T) {
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
ILike int ILike int
PageView int PageView int
From_url string From_url string // nolint
Pre_url string `xorm:"unique"` //pre view image's url Pre_url string `xorm:"unique"` //pre view image's url
Uid int64 Uid int64
} }
assert.NoError(t, testEngine.DropTables(&PictureEmpty{}, &NumericEmpty{})) 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{}) isEmpty, err := testEngine.IsTableEmpty(&PictureEmpty{})
assert.NoError(t, err) assert.NoError(t, err)
@ -393,7 +393,7 @@ func TestIndexAndUnique(t *testing.T) {
func TestMetaInfo(t *testing.T) { func TestMetaInfo(t *testing.T) {
assert.NoError(t, PrepareEngine()) 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() tables, err := testEngine.DBMetas()
assert.NoError(t, err) assert.NoError(t, err)
@ -423,8 +423,8 @@ func TestSync2_1(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.DropTables("wx_test")) assert.NoError(t, testEngine.DropTables("wx_test"))
assert.NoError(t, testEngine.Sync2(new(WxTest))) assert.NoError(t, testEngine.Sync(new(WxTest)))
assert.NoError(t, testEngine.Sync2(new(WxTest))) assert.NoError(t, testEngine.Sync(new(WxTest)))
} }
func TestUnique_1(t *testing.T) { func TestUnique_1(t *testing.T) {
@ -440,7 +440,7 @@ func TestUnique_1(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assert.NoError(t, testEngine.DropTables("user_unique")) 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.DropTables("user_unique"))
assert.NoError(t, testEngine.CreateTables(new(UserUnique))) assert.NoError(t, testEngine.CreateTables(new(UserUnique)))
@ -459,7 +459,7 @@ func TestSync2_2(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
tableName := fmt.Sprintf("test_sync2_index_%d", i) tableName := fmt.Sprintf("test_sync2_index_%d", i)
tableNames[tableName] = true 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) exist, err := testEngine.IsTableExist(tableName)
assert.NoError(t, err) assert.NoError(t, err)
@ -484,7 +484,7 @@ func TestSync2_Default(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assertSync(t, new(TestSync2Default)) assertSync(t, new(TestSync2Default))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default))) assert.NoError(t, testEngine.Sync(new(TestSync2Default)))
} }
func TestSync2_Default2(t *testing.T) { func TestSync2_Default2(t *testing.T) {
@ -497,9 +497,9 @@ func TestSync2_Default2(t *testing.T) {
assert.NoError(t, PrepareEngine()) assert.NoError(t, PrepareEngine())
assertSync(t, new(TestSync2Default2)) assertSync(t, new(TestSync2Default2))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default2))) assert.NoError(t, testEngine.Sync(new(TestSync2Default2)))
assert.NoError(t, testEngine.Sync2(new(TestSync2Default2))) assert.NoError(t, testEngine.Sync(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{ SQLType: schemas.SQLType{
Name: "VARCHAR", Name: "VARCHAR",
}, },
Length: 16, Length: 16,
Nullable: false, Nullable: false,
DefaultIsEmpty: true,
}) })
_, err := testEngine.Exec(alterSQL) _, err := testEngine.Exec(alterSQL)
assert.NoError(t, err) assert.NoError(t, err)

View File

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

View File

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

View File

@ -37,7 +37,7 @@ func TestTransaction(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
user2 := Userinfo{Username: "yyy"} user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 0).Update(&user2) _, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err) assert.NoError(t, err)
_, err = session.Delete(&user2) _, err = session.Delete(&user2)
@ -70,10 +70,10 @@ func TestCombineTransaction(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
user2 := Userinfo{Username: "zzz"} user2 := Userinfo{Username: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2) _, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err) 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) assert.NoError(t, err)
err = session.Commit() err = session.Commit()
@ -113,10 +113,10 @@ func TestCombineTransactionSameMapper(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
user2 := Userinfo{Username: "zzz"} user2 := Userinfo{Username: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2) _, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err) 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) assert.NoError(t, err)
err = session.Commit() err = session.Commit()
@ -144,7 +144,7 @@ func TestMultipleTransaction(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
user2 := MultipleTransaction{Name: "zzz"} user2 := MultipleTransaction{Name: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2) _, err = session.Where("`id` = ?", 0).Update(&user2)
assert.NoError(t, err) assert.NoError(t, err)
err = session.Commit() err = session.Commit()
@ -158,7 +158,7 @@ func TestMultipleTransaction(t *testing.T) {
err = session.Begin() err = session.Begin()
assert.NoError(t, err) 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) assert.NoError(t, err)
err = session.Commit() err = session.Commit()

View File

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

View File

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

View File

@ -51,7 +51,7 @@ func createEngine(dbType, connStr string) error {
if !*cluster { if !*cluster {
switch schemas.DBType(strings.ToLower(dbType)) { switch schemas.DBType(strings.ToLower(dbType)) {
case schemas.MSSQL: 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 { if err != nil {
return err return err
} }
@ -61,7 +61,7 @@ func createEngine(dbType, connStr string) error {
db.Close() db.Close()
*ignoreSelectUpdate = true *ignoreSelectUpdate = true
case schemas.POSTGRES: 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 { if err != nil {
return err return err
} }
@ -90,7 +90,7 @@ func createEngine(dbType, connStr string) error {
db.Close() db.Close()
*ignoreSelectUpdate = true *ignoreSelectUpdate = true
case schemas.MYSQL: 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 { if err != nil {
return err return err
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
@ -42,7 +43,19 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err 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 statement.dialect.URI().DBType == schemas.MYSQL {
if _, err := buf.WriteString(" VALUES ()"); err != nil { if _, err := buf.WriteString(" VALUES ()"); err != nil {
return "", nil, err return "", nil, err
@ -60,6 +73,10 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err return "", nil, err
} }
if needSeq {
colNames = append(colNames, table.AutoIncrement)
}
if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames()...), ","); err != nil { if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames()...), ","); err != nil {
return "", nil, err return "", nil, err
} }
@ -80,13 +97,23 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err 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 len(exprs) > 0 {
if _, err := buf.WriteString(","); err != nil { if _, err := buf.WriteString(","); err != nil {
return "", nil, err return "", nil, err
} }
} if err := exprs.WriteArgs(buf); err != nil {
if err := exprs.WriteArgs(buf); err != nil { return "", nil, err
return "", nil, err }
} }
if _, err := buf.WriteString(" FROM "); err != nil { if _, err := buf.WriteString(" FROM "); err != nil {
@ -113,6 +140,18 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
return "", nil, err 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 len(exprs) > 0 {
if _, err := buf.WriteString(","); err != nil { if _, err := buf.WriteString(","); err != nil {
return "", nil, err return "", nil, err

View File

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

View File

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

View File

@ -5,6 +5,7 @@
package statements package statements
import ( import (
"os"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
panic("tags parser is nil") panic("tags parser is nil")
} }
m.Run() m.Run()
os.Exit(0)
} }
var colStrTests = []struct { 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) { func BenchmarkGetFlagForColumnWithICKey_ContainsKey(b *testing.B) {
b.StopTimer() b.StopTimer()

View File

@ -6,9 +6,15 @@ package utils
import ( import (
"fmt" "fmt"
"strings"
) )
// IndexName returns index name // IndexName returns index name
func IndexName(tableName, idxName string) string { func IndexName(tableName, idxName string) string {
return fmt.Sprintf("IDX_%v_%v", tableName, idxName) 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) { if len(left) != len(right) {
return false return false
} }
sort.Sort(sort.StringSlice(left)) sort.Strings(left)
sort.Sort(sort.StringSlice(right)) sort.Strings(right)
for i := 0; i < len(left); i++ { for i := 0; i < len(left); i++ {
if left[i] != right[i] { if left[i] != right[i] {
return false return false
@ -20,3 +20,13 @@ func SliceEq(left, right []string) bool {
} }
return true 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 // Error implement ILogger
func (s *SimpleLogger) Error(v ...interface{}) { func (s *SimpleLogger) Error(v ...interface{}) {
if s.level <= LOG_ERR { if s.level <= LOG_ERR {
s.ERR.Output(2, fmt.Sprintln(v...)) _ = s.ERR.Output(2, fmt.Sprintln(v...))
} }
} }
// Errorf implement ILogger // Errorf implement ILogger
func (s *SimpleLogger) Errorf(format string, v ...interface{}) { func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
if s.level <= LOG_ERR { if s.level <= LOG_ERR {
s.ERR.Output(2, fmt.Sprintf(format, v...)) _ = s.ERR.Output(2, fmt.Sprintf(format, v...))
} }
} }
// Debug implement ILogger // Debug implement ILogger
func (s *SimpleLogger) Debug(v ...interface{}) { func (s *SimpleLogger) Debug(v ...interface{}) {
if s.level <= LOG_DEBUG { if s.level <= LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprintln(v...)) _ = s.DEBUG.Output(2, fmt.Sprintln(v...))
} }
} }
// Debugf implement ILogger // Debugf implement ILogger
func (s *SimpleLogger) Debugf(format string, v ...interface{}) { func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
if s.level <= LOG_DEBUG { if s.level <= LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprintf(format, v...)) _ = s.DEBUG.Output(2, fmt.Sprintf(format, v...))
} }
} }
// Info implement ILogger // Info implement ILogger
func (s *SimpleLogger) Info(v ...interface{}) { func (s *SimpleLogger) Info(v ...interface{}) {
if s.level <= LOG_INFO { if s.level <= LOG_INFO {
s.INFO.Output(2, fmt.Sprintln(v...)) _ = s.INFO.Output(2, fmt.Sprintln(v...))
} }
} }
// Infof implement ILogger // Infof implement ILogger
func (s *SimpleLogger) Infof(format string, v ...interface{}) { func (s *SimpleLogger) Infof(format string, v ...interface{}) {
if s.level <= LOG_INFO { if s.level <= LOG_INFO {
s.INFO.Output(2, fmt.Sprintf(format, v...)) _ = s.INFO.Output(2, fmt.Sprintf(format, v...))
} }
} }
// Warn implement ILogger // Warn implement ILogger
func (s *SimpleLogger) Warn(v ...interface{}) { func (s *SimpleLogger) Warn(v ...interface{}) {
if s.level <= LOG_WARNING { if s.level <= LOG_WARNING {
s.WARN.Output(2, fmt.Sprintln(v...)) _ = s.WARN.Output(2, fmt.Sprintln(v...))
} }
} }
// Warnf implement ILogger // Warnf implement ILogger
func (s *SimpleLogger) Warnf(format string, v ...interface{}) { func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
if s.level <= LOG_WARNING { 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !windows && !nacl && !plan9
// +build !windows,!nacl,!plan9 // +build !windows,!nacl,!plan9
package log package log
@ -26,42 +27,42 @@ func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
// Debug log content as Debug // Debug log content as Debug
func (s *SyslogLogger) Debug(v ...interface{}) { 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 // Debugf log content as Debug and format
func (s *SyslogLogger) Debugf(format string, v ...interface{}) { 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 // Error log content as Error
func (s *SyslogLogger) Error(v ...interface{}) { 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 // Errorf log content as Errorf and format
func (s *SyslogLogger) Errorf(format string, v ...interface{}) { 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 // Info log content as Info
func (s *SyslogLogger) Info(v ...interface{}) { 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 // Infof log content as Infof and format
func (s *SyslogLogger) Infof(format string, v ...interface{}) { 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 // Warn log content as Warn
func (s *SyslogLogger) Warn(v ...interface{}) { 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 // Warnf log content as Warnf and format
func (s *SyslogLogger) Warnf(format string, v ...interface{}) { 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 // Level shows log level

View File

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

View File

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

View File

@ -14,9 +14,15 @@ type TableName interface {
TableName() string TableName() string
} }
type TableComment interface {
TableComment() string
}
var ( var (
tpTableName = reflect.TypeOf((*TableName)(nil)).Elem() tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
tvCache sync.Map tpTableComment = reflect.TypeOf((*TableComment)(nil)).Elem()
tvCache sync.Map
tcCache sync.Map
) )
// GetTableName returns table name // GetTableName returns table name
@ -55,3 +61,40 @@ func GetTableName(mapper Mapper, v reflect.Value) string {
return mapper.Obj2Table(v.Type().Name()) 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/builder"
"xorm.io/xorm/core" "xorm.io/xorm/core"
"xorm.io/xorm/internal/utils"
) )
// Rows rows wrapper a rows to // Rows rows wrapper a rows to
@ -41,7 +40,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
return nil, err return nil, err
} }
if len(session.statement.TableName()) <= 0 { if len(session.statement.TableName()) == 0 {
return nil, ErrTableNotFound 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 // Next move cursor to next record, return false if end has reached
func (rows *Rows) Next() bool { 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. // 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 { 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 // Scan row record to bean properties
func (rows *Rows) Scan(bean interface{}) error { func (rows *Rows) Scan(beans ...interface{}) error {
if rows.Err() != nil { if rows.Err() != nil {
return rows.Err() return rows.Err()
} }
if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType { var bean = beans[0]
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType) 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 { if len(beans) == 1 {
return err 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() fields, err := rows.rows.Columns()
@ -115,14 +129,7 @@ func (rows *Rows) Scan(bean interface{}) error {
return err return err
} }
scanResults, err := rows.session.row2Slice(rows.rows, fields, types, bean) if err := rows.session.scan(rows.rows, rows.session.statement.RefTable, beanKind, beans, types, fields); err != nil {
if err != nil {
return err
}
dataStruct := utils.ReflectValue(bean)
_, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
if err != nil {
return err return err
} }
@ -139,5 +146,5 @@ func (rows *Rows) Close() error {
return rows.rows.Close() 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) { func (engine *Engine) scanStringInterface(rows *core.Rows, fields []string, types []*sql.ColumnType) ([]interface{}, error) {
var scanResults = make([]interface{}, len(types)) var scanResults = make([]interface{}, len(types))
for i := 0; i < len(types); i++ { for i := 0; i < len(types); i++ {
@ -259,41 +208,8 @@ func (engine *Engine) scanInterfaces(rows *core.Rows, fields []string, types []*
return scanResultContainers, nil return scanResultContainers, nil
} }
func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) { ////////////////////
scanResults, err := engine.scanStringInterface(rows, fields, types) // row -> map[string]interface{}
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
}
func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]interface{}, error) { func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]interface{}, error) {
var resultsMap = make(map[string]interface{}, len(fields)) 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 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 { func (index *Index) XName(tableName string) string {
if !strings.HasPrefix(index.Name, "UQE_") && if !strings.HasPrefix(index.Name, "UQE_") &&
!strings.HasPrefix(index.Name, "IDX_") { !strings.HasPrefix(index.Name, "IDX_") {
tableParts := strings.Split(strings.Replace(tableName, `"`, "", -1), ".") tableParts := strings.Split(strings.ReplaceAll(tableName, `"`, ""), ".")
tableName = tableParts[len(tableParts)-1] tableName = tableParts[len(tableParts)-1]
if index.Type == UniqueType { if index.Type == UniqueType {
return fmt.Sprintf("UQE_%v_%v", tableName, index.Name) return fmt.Sprintf("UQE_%v_%v", tableName, index.Name)

View File

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

View File

@ -45,7 +45,8 @@ func TestAlwaysQuoteTo(t *testing.T) {
for _, v := range kases { for _, v := range kases {
t.Run(v.value, func(t *testing.T) { t.Run(v.value, func(t *testing.T) {
buf := &strings.Builder{} 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()) assert.EqualValues(t, v.expected, buf.String())
}) })
} }
@ -54,10 +55,7 @@ func TestAlwaysQuoteTo(t *testing.T) {
func TestReversedQuoteTo(t *testing.T) { func TestReversedQuoteTo(t *testing.T) {
var ( var (
quoter = Quoter{'[', ']', func(s string) bool { quoter = Quoter{'[', ']', func(s string) bool {
if s == "mytable" { return s == "mytable"
return true
}
return false
}} }}
kases = []struct { kases = []struct {
expected string expected string
@ -118,7 +116,8 @@ func TestNoQuoteTo(t *testing.T) {
for _, v := range kases { for _, v := range kases {
t.Run(v.value, func(t *testing.T) { t.Run(v.value, func(t *testing.T) {
buf := &strings.Builder{} 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()) 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`'",
"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 { for _, kase := range kases {

View File

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

View File

@ -79,7 +79,8 @@ type Session struct {
afterClosures []func(interface{}) afterClosures []func(interface{})
afterProcessors []executedProcessor 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 lastSQL string
lastSQLArgs []interface{} lastSQLArgs []interface{}
@ -123,13 +124,14 @@ func newSession(engine *Engine) *Session {
autoResetStatement: true, autoResetStatement: true,
prepareStmt: false, prepareStmt: false,
afterInsertBeans: make(map[interface{}]*[]func(interface{}), 0), afterInsertBeans: make(map[interface{}]*[]func(interface{})),
afterUpdateBeans: make(map[interface{}]*[]func(interface{}), 0), afterUpdateBeans: make(map[interface{}]*[]func(interface{})),
afterDeleteBeans: make(map[interface{}]*[]func(interface{}), 0), afterDeleteBeans: make(map[interface{}]*[]func(interface{})),
beforeClosures: make([]func(interface{}), 0), beforeClosures: make([]func(interface{}), 0),
afterClosures: make([]func(interface{}), 0), afterClosures: make([]func(interface{}), 0),
afterProcessors: make([]executedProcessor, 0), afterProcessors: make([]executedProcessor, 0),
stmtCache: make(map[uint32]*core.Stmt), stmtCache: make(map[uint32]*core.Stmt),
txStmtCache: make(map[uint32]*core.Stmt),
lastSQL: "", lastSQL: "",
lastSQLArgs: make([]interface{}, 0), 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 { if !session.isClosed {
// When Close be called, if session is a transaction and do not call // When Close be called, if session is a transaction and do not call
// Commit or Rollback, then call Rollback. // Commit or Rollback, then call Rollback.
@ -160,6 +168,7 @@ func (session *Session) Close() error {
} }
session.tx = nil session.tx = nil
session.stmtCache = nil session.stmtCache = nil
session.txStmtCache = nil
session.isClosed = true session.isClosed = true
} }
return nil return nil
@ -174,6 +183,11 @@ func (session *Session) Engine() *Engine {
return session.engine return session.engine
} }
// Tx returns session tx
func (session *Session) Tx() *core.Tx {
return session.tx
}
func (session *Session) getQueryer() core.Queryer { func (session *Session) getQueryer() core.Queryer {
if session.tx != nil { if session.tx != nil {
return session.tx return session.tx
@ -195,6 +209,7 @@ func (session *Session) IsClosed() bool {
func (session *Session) resetStatement() { func (session *Session) resetStatement() {
if session.autoResetStatement { if session.autoResetStatement {
session.statement.Reset() session.statement.Reset()
session.prepareStmt = false
} }
} }
@ -365,7 +380,22 @@ func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt,
return 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) var col = table.GetColumnIdx(colName, idx)
if col == nil { if col == nil {
return nil, nil, ErrFieldIsNotExist{colName, table.Name} 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 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) bs, ok := convert.AsBytes(scanResult)
if !ok { if !ok {
return fmt.Errorf("unsupported database data type: %#v", scanResult) return fmt.Errorf("unsupported database data type: %#v", scanResult)
@ -519,6 +549,9 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
if !ok { if !ok {
return fmt.Errorf("cannot convert %#v as bytes", scanResult) return fmt.Errorf("cannot convert %#v as bytes", scanResult)
} }
if data == nil {
return nil
}
return structConvert.FromDB(data) return structConvert.FromDB(data)
} }
} }
@ -543,7 +576,7 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
fieldType := fieldValue.Type() fieldType := fieldValue.Type()
if col.IsJSON { if col.IsJSON {
return session.setJSON(fieldValue, fieldType, scanResult) return setJSON(fieldValue, fieldType, scanResult)
} }
switch fieldType.Kind() { switch fieldType.Kind() {
@ -562,7 +595,7 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
} }
return nil return nil
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
return session.setJSON(fieldValue, fieldType, scanResult) return setJSON(fieldValue, fieldType, scanResult)
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
bs, ok := convert.AsBytes(scanResult) bs, ok := convert.AsBytes(scanResult)
if ok && fieldType.Elem().Kind() == reflect.Uint8 { 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 { if idx, ok = tempMap[lKey]; !ok {
idx = 0 idx = 0
} else { } else {
idx = idx + 1 idx++
} }
tempMap[lKey] = idx tempMap[lKey] = idx
col, fieldValue, err := session.getField(dataStruct, table, colName, idx) col, fieldValue, err := getField(dataStruct, table, colName, idx)
if err != nil { if _, ok := err.(ErrFieldIsNotExist); ok {
if _, ok := err.(ErrFieldIsNotExist); ok { continue
continue } else if err != nil {
} else { return nil, err
return nil, err
}
} }
if fieldValue == nil { if fieldValue == nil {
continue continue
} }
@ -725,6 +757,12 @@ func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
// Context sets the context on this session // Context sets the context on this session
func (session *Session) Context(ctx context.Context) *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 session.ctx = ctx
return session return session
} }

View File

@ -40,7 +40,13 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
pkColumns := table.PKColumns() pkColumns := table.PKColumns()
ids, err := caches.GetCacheSql(cacher, tableName, newsql, args) ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
if err != nil { 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 { if err != nil {
return err return err
} }
@ -53,9 +59,9 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
if v, ok := data[col.Name]; !ok { if v, ok := data[col.Name]; !ok {
return errors.New("no id") return errors.New("no id")
} else if col.SQLType.IsText() { } else if col.SQLType.IsText() {
pk = append(pk, string(v)) pk = append(pk, v)
} else if col.SQLType.IsNumeric() { } else if col.SQLType.IsNumeric() {
id, err = strconv.ParseInt(string(v), 10, 64) id, err = strconv.ParseInt(v, 10, 64)
if err != nil { if err != nil {
return err 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 { 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 session.statement.RefTable = table

View File

@ -57,7 +57,7 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
if session.statement.SelectStr != "" { if session.statement.SelectStr != "" {
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{} session.statement.ColumnMap = []string{}
} }
if session.statement.OrderStr != "" { 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. // 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 { func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
@ -152,7 +156,6 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
if err != ErrCacheFailed { if err != ErrCacheFailed {
return err return err
} }
err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.engine.logger.Warnf("Cache Find Failed") session.engine.logger.Warnf("Cache Find Failed")
} }
} }
@ -251,9 +254,9 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect
switch elemType.Kind() { switch elemType.Kind() {
case reflect.Slice: case reflect.Slice:
err = rows.ScanSlice(bean) err = session.getSlice(rows, types, fields, bean)
case reflect.Map: case reflect.Map:
err = rows.ScanMap(bean) err = session.getMap(rows, types, fields, bean)
default: default:
err = rows.Scan(bean) err = rows.Scan(bean)
} }

View File

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

View File

@ -80,7 +80,7 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
} }
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -90,7 +90,6 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
colNames []string colNames []string
colMultiPlaces []string colMultiPlaces []string
args []interface{} args []interface{}
cols []*schemas.Column
) )
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
@ -123,6 +122,12 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
} }
fieldValue := *ptrFieldValue fieldValue := *ptrFieldValue
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) { 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 continue
} }
if col.MapType == schemas.ONLYFROMDB { 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) { if len(session.statement.ColumnMap) > 0 && !session.statement.ColumnMap.Contain(col.Name) {
continue 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 { if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t, err := session.engine.nowTime(col) val, t, err := session.engine.nowTime(col)
if err != nil { if err != nil {
@ -166,7 +178,6 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
if i == 0 { if i == 0 {
colNames = append(colNames, col.Name) colNames = append(colNames, col.Name)
cols = append(cols, col)
} }
colPlaces = append(colPlaces, "?") colPlaces = append(colPlaces, "?")
} }
@ -197,7 +208,7 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
return 0, err return 0, err
} }
session.cacheInsert(tableName) _ = session.cacheInsert(tableName)
lenAfterClosures := len(session.afterClosures) lenAfterClosures := len(session.afterClosures)
for i := 0; i < size; i++ { 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 { if err := session.statement.SetRefBean(bean); err != nil {
return 0, err return 0, err
} }
if len(session.statement.TableName()) <= 0 { if len(session.statement.TableName()) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -277,6 +288,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
sqlStr = session.engine.dialect.Quoter().Replace(sqlStr)
handleAfterInsertProcessorFunc := func(bean interface{}) { handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.isAutoCommit { 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 there is auto increment column and driver don't support return it
if len(table.AutoIncrement) > 0 && !session.engine.driver.Features().SupportReturnInsertedID { if len(table.AutoIncrement) > 0 && !session.engine.driver.Features().SupportReturnInsertedID {
var sql = sqlStr var sql string
if session.engine.dialect.URI().DBType == schemas.ORACLE { var newArgs []interface{}
sql = "select seq_atable.currval from dual" 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 id == 0 {
if err != nil { err := session.queryRow(sql, newArgs...).Scan(&id)
return 0, err 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) defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName) _ = session.cacheInsert(tableName)
if table.Version != "" && session.statement.CheckVersion { if table.Version != "" && session.statement.CheckVersion {
verValue, err := table.VersionColumn().ValueOf(bean) 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) aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil { if err != nil {
session.engine.logger.Errorf("%v", err) session.engine.logger.Errorf("%v", err)
@ -360,7 +395,7 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) {
defer handleAfterInsertProcessorFunc(bean) defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName) _ = session.cacheInsert(tableName)
if table.Version != "" && session.statement.CheckVersion { if table.Version != "" && session.statement.CheckVersion {
verValue, err := table.VersionColumn().ValueOf(bean) 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. // InsertOne insert only one struct into database as a record.
// The in parameter bean must a struct or a point to struct. The return // The in parameter bean must a struct or a point to struct. The return
// parameter is inserted and error // parameter is inserted and error
// Deprecated: Please use Insert directly
func (session *Session) InsertOne(bean interface{}) (int64, error) { func (session *Session) InsertOne(bean interface{}) (int64, error) {
if session.isAutoClose { if session.isAutoClose {
defer session.Close() defer session.Close()
@ -507,7 +543,7 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
} }
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound 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) { func (session *Session) insertMultipleMapInterface(maps []map[string]interface{}) (int64, error) {
if len(maps) <= 0 { if len(maps) == 0 {
return 0, ErrNoElementsOnSlice return 0, ErrNoElementsOnSlice
} }
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -565,7 +601,7 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
} }
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound 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) { func (session *Session) insertMultipleMapString(maps []map[string]string) (int64, error) {
if len(maps) <= 0 { if len(maps) == 0 {
return 0, ErrNoElementsOnSlice return 0, ErrNoElementsOnSlice
} }
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound 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) { func (session *Session) insertMap(columns []string, args []interface{}) (int64, error) {
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -628,6 +664,7 @@ func (session *Session) insertMap(columns []string, args []interface{}) (int64,
if err != nil { if err != nil {
return 0, err return 0, err
} }
sql = session.engine.dialect.Quoter().Replace(sql)
if err := session.cacheInsert(tableName); err != nil { if err := session.cacheInsert(tableName); err != nil {
return 0, err 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) { func (session *Session) insertMultipleMap(columns []string, argss [][]interface{}) (int64, error) {
tableName := session.statement.TableName() tableName := session.statement.TableName()
if len(tableName) <= 0 { if len(tableName) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -654,6 +691,7 @@ func (session *Session) insertMultipleMap(columns []string, argss [][]interface{
if err != nil { if err != nil {
return 0, err return 0, err
} }
sql = session.engine.dialect.Quoter().Replace(sql)
if err := session.cacheInsert(tableName); err != nil { if err := session.cacheInsert(tableName); err != nil {
return 0, err return 0, err

View File

@ -95,7 +95,7 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
break break
} }
start = start + slice.Elem().Len() start += slice.Elem().Len()
if pLimitN != nil && start+bufferSize > *pLimitN { if pLimitN != nil && start+bufferSize > *pLimitN {
bufferSize = *pLimitN - start 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 { if session.isAutoCommit {
var db *core.DB 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() db = session.engine.engineGroup.Slave().DB()
} else { } else {
db = session.DB() db = session.DB()
@ -46,39 +46,106 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
return nil, err return nil, err
} }
rows, err := stmt.QueryContext(session.ctx, args...) return stmt.QueryContext(session.ctx, args...)
if err != nil {
return nil, err
}
return rows, nil
} }
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 { if err != nil {
return nil, err return nil, err
} }
return rows, nil
return stmt.QueryContext(session.ctx, args...)
} }
rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...) return session.tx.QueryContext(session.ctx, sqlStr, args...)
if err != nil {
return nil, err
}
return rows, nil
} }
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row { func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
return core.NewRow(session.queryRows(sqlStr, args...)) 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...) rows, err := session.queryRows(sqlStr, args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() 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) { 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 session.lastSQLArgs = args
if !session.isAutoCommit { 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...) 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 { if err != nil {
return nil, err return nil, err
} }
return stmt.ExecContext(session.ctx, args...)
res, err := stmt.ExecContext(session.ctx, args...)
if err != nil {
return nil, err
}
return res, nil
} }
return session.DB().ExecContext(session.ctx, sqlStr, args...) return session.DB().ExecContext(session.ctx, sqlStr, args...)

View File

@ -6,12 +6,14 @@ package xorm
import ( import (
"bufio" "bufio"
"context"
"database/sql" "database/sql"
"fmt" "fmt"
"io" "io"
"os" "os"
"strings" "strings"
"xorm.io/xorm/dialects"
"xorm.io/xorm/internal/utils" "xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
@ -40,13 +42,28 @@ func (session *Session) createTable(bean interface{}) error {
return err return err
} }
sqlStrs := session.statement.GenCreateTableSQL() session.statement.RefTable.StoreEngine = session.statement.StoreEngine
for _, s := range sqlStrs { session.statement.RefTable.Charset = session.statement.Charset
_, err := session.exec(s) 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 { if err != nil {
return err 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 return nil
} }
@ -141,11 +158,32 @@ func (session *Session) dropTable(beanOrTableName interface{}) error {
checkIfExist = exist checkIfExist = exist
} }
if checkIfExist { if !checkIfExist {
_, err := session.exec(sqlStr) return nil
}
if _, err := session.exec(sqlStr); err != nil {
return err 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 // IsTableExist if a table is exist
@ -185,24 +223,6 @@ func (session *Session) isTableEmpty(tableName string) (bool, error) {
return total == 0, nil 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 { func (session *Session) addColumn(colName string) error {
col := session.statement.RefTable.GetColumn(colName) col := session.statement.RefTable.GetColumn(colName)
sql := session.engine.dialect.AddColumnSQL(session.statement.TableName(), col) 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 // Sync2 synchronize structs to database tables
// Depricated
func (session *Session) Sync2(beans ...interface{}) error { 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 engine := session.engine
if session.isAutoClose { if session.isAutoClose {
@ -350,6 +376,8 @@ func (session *Session) Sync2(beans ...interface{}) error {
_, err = session.exec(engine.dialect.ModifyColumnSQL(tbNameWithSchema, col)) _, 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 { 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. // Sums call sum some columns. bean's non-empty fields are conditions.
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) { 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...) return res, session.sum(&res, bean, columnNames...)
} }
// SumsInt sum specify columns and return as []int64 instead of []float64 // SumsInt sum specify columns and return as []int64 instead of []float64
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) { 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...) 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{})) { cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
if len(*slices) > 0 { if len(*slices) > 0 {
*slices = make(map[interface{}]*[]func(interface{}), 0) *slices = make(map[interface{}]*[]func(interface{}))
} }
} }
cleanUpFunc(&session.afterInsertBeans) cleanUpFunc(&session.afterInsertBeans)

View File

@ -22,6 +22,7 @@ var (
ErrNoColumnsTobeUpdated = errors.New("no columns found to be updated") ErrNoColumnsTobeUpdated = errors.New("no columns found to be updated")
) )
//revive:disable
func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error { func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error {
if table == nil || if table == nil ||
session.tx != nil { session.tx != nil {
@ -39,7 +40,7 @@ func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr stri
var nStart int var nStart int
if len(args) > 0 { if len(args) > 0 {
if strings.Index(sqlStr, "?") > -1 { if strings.Contains(sqlStr, "?") {
nStart = strings.Count(oldhead, "?") nStart = strings.Count(oldhead, "?")
} else { } else {
// only for pq, TODO: if any other databse? // only for pq, TODO: if any other databse?
@ -182,7 +183,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
return 0, err return 0, err
} }
if len(session.statement.TableName()) <= 0 { if len(session.statement.TableName()) == 0 {
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
@ -278,7 +279,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
condBeanIsStruct := false condBeanIsStruct := false
if len(condiBean) > 0 { if len(condiBean) > 0 {
if c, ok := condiBean[0].(map[string]interface{}); ok { 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 { } else {
ct := reflect.TypeOf(condiBean[0]) ct := reflect.TypeOf(condiBean[0])
k := ct.Kind() 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 return 0, ErrNoColumnsTobeUpdated
} }
@ -352,7 +357,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
} }
if st.OrderStr != "" { 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() var tableName = session.statement.TableName()
@ -362,7 +367,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
limitValue := *st.LimitN limitValue := *st.LimitN
switch session.engine.dialect.URI().DBType { switch session.engine.dialect.URI().DBType {
case schemas.MYSQL: case schemas.MYSQL:
condSQL = condSQL + fmt.Sprintf(" LIMIT %d", limitValue) condSQL += fmt.Sprintf(" LIMIT %d", limitValue)
case schemas.SQLITE: case schemas.SQLITE:
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue) tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", 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 := schemas.NewEmptyTable()
table.Type = t table.Type = t
table.Name = names.GetTableName(parser.tableMapper, v) table.Name = names.GetTableName(parser.tableMapper, v)
table.Comment = names.GetTableComment(v)
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
col, err := parser.parseField(table, i, t.Field(i), v.Field(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" 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) { func TestParseTableName(t *testing.T) {
parser := NewParser( parser := NewParser(
"xorm", "xorm",
@ -47,6 +61,36 @@ func TestParseTableName(t *testing.T) {
assert.EqualValues(t, "p_parseTableName", table.Name) 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) { func TestUnexportField(t *testing.T) {
parser := NewParser( parser := NewParser(
"xorm", "xorm",