Browse Source

vendor: update github.com/go-xorm/xorm (#4913)

pull/5126/head
Unknwon 7 years ago
parent
commit
28f74cf1c6
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
  1. 9
      vendor/github.com/go-xorm/xorm/CONTRIBUTING.md
  2. 223
      vendor/github.com/go-xorm/xorm/README.md
  3. 201
      vendor/github.com/go-xorm/xorm/README_CN.md
  4. 34
      vendor/github.com/go-xorm/xorm/cache_lru.go
  5. 11
      vendor/github.com/go-xorm/xorm/circle.yml
  6. 26
      vendor/github.com/go-xorm/xorm/context.go
  7. 18
      vendor/github.com/go-xorm/xorm/convert.go
  8. 74
      vendor/github.com/go-xorm/xorm/dialect_mysql.go
  9. 154
      vendor/github.com/go-xorm/xorm/dialect_postgres.go
  10. 4
      vendor/github.com/go-xorm/xorm/doc.go
  11. 300
      vendor/github.com/go-xorm/xorm/engine.go
  12. 230
      vendor/github.com/go-xorm/xorm/engine_cond.go
  13. 194
      vendor/github.com/go-xorm/xorm/engine_group.go
  14. 116
      vendor/github.com/go-xorm/xorm/engine_group_policy.go
  15. 22
      vendor/github.com/go-xorm/xorm/engine_maxlife.go
  16. 2
      vendor/github.com/go-xorm/xorm/error.go
  17. 24
      vendor/github.com/go-xorm/xorm/helpers.go
  18. 104
      vendor/github.com/go-xorm/xorm/interface.go
  19. 40
      vendor/github.com/go-xorm/xorm/processors.go
  20. 73
      vendor/github.com/go-xorm/xorm/rows.go
  21. 216
      vendor/github.com/go-xorm/xorm/session.go
  22. 24
      vendor/github.com/go-xorm/xorm/session_cols.go
  23. 18
      vendor/github.com/go-xorm/xorm/session_cond.go
  24. 88
      vendor/github.com/go-xorm/xorm/session_convert.go
  25. 76
      vendor/github.com/go-xorm/xorm/session_delete.go
  26. 86
      vendor/github.com/go-xorm/xorm/session_exist.go
  27. 207
      vendor/github.com/go-xorm/xorm/session_find.go
  28. 138
      vendor/github.com/go-xorm/xorm/session_get.go
  29. 159
      vendor/github.com/go-xorm/xorm/session_insert.go
  30. 54
      vendor/github.com/go-xorm/xorm/session_iterate.go
  31. 262
      vendor/github.com/go-xorm/xorm/session_query.go
  32. 295
      vendor/github.com/go-xorm/xorm/session_raw.go
  33. 202
      vendor/github.com/go-xorm/xorm/session_schema.go
  34. 98
      vendor/github.com/go-xorm/xorm/session_stats.go
  35. 140
      vendor/github.com/go-xorm/xorm/session_sum.go
  36. 24
      vendor/github.com/go-xorm/xorm/session_tx.go
  37. 192
      vendor/github.com/go-xorm/xorm/session_update.go
  38. 376
      vendor/github.com/go-xorm/xorm/statement.go
  39. 9
      vendor/github.com/go-xorm/xorm/tag.go
  40. 1
      vendor/github.com/go-xorm/xorm/test_mssql_cache.sh
  41. 1
      vendor/github.com/go-xorm/xorm/test_mymysql.sh
  42. 1
      vendor/github.com/go-xorm/xorm/test_mymysql_cache.sh
  43. 1
      vendor/github.com/go-xorm/xorm/test_mysql_cache.sh
  44. 1
      vendor/github.com/go-xorm/xorm/test_postgres_cache.sh
  45. 1
      vendor/github.com/go-xorm/xorm/test_sqlite_cache.sh
  46. 14
      vendor/github.com/go-xorm/xorm/xorm.go
  47. 6
      vendor/vendor.json

9
vendor/github.com/go-xorm/xorm/CONTRIBUTING.md generated vendored

@ -32,13 +32,10 @@ proposed functionality.
We appreciate any bug reports, but especially ones with self-contained We appreciate any bug reports, but especially ones with self-contained
(doesn't depend on code outside of xorm), minimal (can't be simplified (doesn't depend on code outside of xorm), minimal (can't be simplified
further) test cases. It's especially helpful if you can submit a pull further) test cases. It's especially helpful if you can submit a pull
request with just the failing test case (you'll probably want to request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)).
pattern it after the tests in
[base.go](https://github.com/go-xorm/tests/blob/master/base.go) AND
[benchmark.go](https://github.com/go-xorm/tests/blob/master/benchmark.go).
If you implements a new database interface, you maybe need to add a <databasename>_test.go file. If you implements a new database interface, you maybe need to add a test_<databasename>.sh file.
For example, [mysql_test.go](https://github.com/go-xorm/tests/blob/master/mysql/mysql_test.go) For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh)
### New functionality ### New functionality

223
vendor/github.com/go-xorm/xorm/README.md generated vendored

@ -3,11 +3,8 @@
Xorm is a simple and powerful ORM for Go. Xorm is a simple and powerful ORM for Go.
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) [![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
# Notice
The last master version is not backwards compatible. You should use `engine.ShowSQL()` and `engine.Logger().SetLevel()` instead of `engine.ShowSQL = `, `engine.ShowInfo = ` and so on.
# Features # Features
@ -31,13 +28,15 @@ The last master version is not backwards compatible. You should use `engine.Show
* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder) * SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder)
* Automatical Read/Write seperatelly
# Drivers Support # Drivers Support
Drivers for Go's sql package which currently support database/sql includes: Drivers for Go's sql package which currently support database/sql includes:
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) * Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv)
* Postgres: [github.com/lib/pq](https://github.com/lib/pq) * Postgres: [github.com/lib/pq](https://github.com/lib/pq)
@ -51,34 +50,26 @@ Drivers for Go's sql package which currently support database/sql includes:
# Changelog # Changelog
* **v0.6.4**
* Automatical Read/Write seperatelly
* Query/QueryString/QueryInterface and action with Where/And
* Get support non-struct variables
* BufferSize on Iterate
* fix some other bugs.
* **v0.6.3**
* merge tests to main project
* add `Exist` function
* add `SumInt` function
* Mysql now support read and create column comment.
* fix time related bugs.
* fix some other bugs.
* **v0.6.2** * **v0.6.2**
* refactor tag parse methods * refactor tag parse methods
* add Scan features to Get * add Scan features to Get
* add QueryString method * add QueryString method
* **v0.6.0**
* remove support for ql
* add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or`
methods can use `builder.Cond` as parameter
* add Sum, SumInt, SumInt64 and NotIn methods
* some bugs fixed
* **v0.5.0**
* logging interface changed
* some bugs fixed
* **v0.4.5**
* many bugs fixed
* extends support unlimited deepth
* Delete Limit support
* **v0.4.4**
* ql database expriment support
* tidb database expriment support
* sql.NullString and etc. field support
* select ForUpdate support
* many bugs fixed
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16) [More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
# Installation # Installation
@ -117,15 +108,36 @@ type User struct {
err := engine.Sync2(new(User)) err := engine.Sync2(new(User))
``` ```
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`. * Create Engine Group
```Go
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
```
```Go
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
```
Then all place where `engine` you can just use `engineGroup`.
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`.
```Go ```Go
results, err := engine.Query("select * from user") results, err := engine.Query("select * from user")
results, err := engine.Where("a = 1").Query()
results, err := engine.QueryString("select * from user") results, err := engine.QueryString("select * from user")
results, err := engine.Where("a = 1").QueryString()
results, err := engine.QueryInterface("select * from user")
results, err := engine.Where("a = 1").QueryInterface()
``` ```
* `Execute` runs a SQL string, it returns `affetcted` and `error` * `Exec` runs a SQL string, it returns `affected` and `error`
```Go ```Go
affected, err := engine.Exec("update user set age = ? where name = ?", age, name) affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
@ -136,43 +148,76 @@ affected, err := engine.Exec("update user set age = ? where name = ?", age, name
```Go ```Go
affected, err := engine.Insert(&user) affected, err := engine.Insert(&user)
// INSERT INTO struct () values () // INSERT INTO struct () values ()
affected, err := engine.Insert(&user1, &user2) affected, err := engine.Insert(&user1, &user2)
// INSERT INTO struct1 () values () // INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values () // INSERT INTO struct2 () values ()
affected, err := engine.Insert(&users) affected, err := engine.Insert(&users)
// INSERT INTO struct () values (),(),() // INSERT INTO struct () values (),(),()
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 (),(),()
``` ```
* Query one record from database * `Get` query one record from database
```Go ```Go
has, err := engine.Get(&user) has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1 // SELECT * FROM user LIMIT 1
has, err := engine.Where("name = ?", name).Desc("id").Get(&user) has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 // SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
var name string var name string
has, err := engine.Where("id = ?", id).Cols("name").Get(&name) has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ? // SELECT name FROM user WHERE id = ?
var id int64 var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id) has, err := engine.Where("name = ?", name).Cols("id").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 valuesMap = make(map[string]string) var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap) has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ? // SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols)) var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ? // SELECT col1, col2, col3 FROM user WHERE id = ?
``` ```
* Query multiple records from database, also you can use join and extends * `Exist` check if one record exist on table
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* `Find` query multiple records from database, also you can use join and extends
```Go ```Go
var users []User var users []User
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10 // SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
type Detail struct { type Detail struct {
Id int64 Id int64
@ -185,14 +230,14 @@ 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)
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10 // SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
``` ```
* Query multiple records and record by record handle, there are two methods Iterate and Rows * `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows
```Go ```Go
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
@ -201,6 +246,13 @@ err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
}) })
// SELECT * FROM user // SELECT * FROM user
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
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()
@ -210,10 +262,10 @@ for rows.Next() {
} }
``` ```
* 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
affected, err := engine.Id(1).Update(&user) affected, err := engine.ID(1).Update(&user)
// UPDATE user SET ... Where id = ? // UPDATE user SET ... Where id = ?
affected, err := engine.Update(&user, &User{Name:name}) affected, err := engine.Update(&user, &User{Name:name})
@ -224,32 +276,50 @@ affected, err := engine.In("id", ids).Update(&user)
// UPDATE user SET ... Where id IN (?, ?, ?) // UPDATE user SET ... Where id IN (?, ?, ?)
// force update indicated columns by Cols // force update indicated columns by Cols
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? Where id = ?
// force NOT update indicated columns by Omit // force NOT update indicated columns by Omit
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? Where id = ?
affected, err := engine.Id(1).AllCols().Update(&user) affected, err := engine.ID(1).AllCols().Update(&user)
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? // UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
``` ```
* Delete one or more records, Delete MUST have condition * `Delete` delete one or more records, Delete MUST have condition
```Go ```Go
affected, err := engine.Where(...).Delete(&user) affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ... // DELETE FROM user Where ...
affected, err := engine.Id(2).Delete(&user)
affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ?
``` ```
* Count records * `Count` count records
```Go ```Go
counts, err := engine.Count(&user) counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user // SELECT count(*) AS total FROM user
``` ```
* `Sum` sum functions
```Go
agesFloat64, err := engine.Sum(&user, "age")
// SELECT sum(age) AS total FROM user
agesInt64, err := engine.SumInt(&user, "age")
// SELECT sum(age) AS total FROM user
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
```
* Query conditions builder * Query conditions builder
```Go ```Go
@ -257,15 +327,76 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) // SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
``` ```
* Multiple operations in one go routine, no transation here but resue session memory
```Go
session := engine.NewSession()
defer session.Close()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return nil
```
* Transation should on one go routine. There is transaction and resue session memory
```Go
session := engine.NewSession()
defer session.Close()
// add Begin() before any action
if err := session.Begin(); err != nil {
// if returned then will rollback automatically
return err
}
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
// add Commit() after all actions
return session.Commit()
```
# Cases # Cases
* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) * [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego) * [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/) * [Docker.cn](https://docker.cn/)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) * [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel) * [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel)

201
vendor/github.com/go-xorm/xorm/README_CN.md generated vendored

@ -5,11 +5,8 @@
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) [![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
# 注意
最新的版本有不兼容的更新,您必须使用 `engine.ShowSQL()``engine.Logger().SetLevel()` 来替代 `engine.ShowSQL = `, `engine.ShowInfo = ` 等等。
## 特性 ## 特性
@ -55,9 +52,18 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
## 更新日志 ## 更新日志
* **v0.6.3**
* 合并单元测试到主工程
* 新增`Exist`方法
* 新增`SumInt`方法
* Mysql新增读取和创建字段注释支持
* 新增`SetConnMaxLifetime`方法
* 修正了时间相关的Bug
* 修复了一些其它Bug
* **v0.6.2** * **v0.6.2**
* 重构Tag解析方式 * 重构Tag解析方式
* Get方法新增类似Sacn的特性 * Get方法新增类似Scan的特性
* 新增 QueryString 方法 * 新增 QueryString 方法
* **v0.6.0** * **v0.6.0**
@ -71,18 +77,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
* logging接口进行不兼容改变 * logging接口进行不兼容改变
* Bug修正 * Bug修正
* **v0.4.5**
* bug修正
* extends 支持无限级
* Delete Limit 支持
* **v0.4.4**
* Tidb 数据库支持
* QL 试验性支持
* sql.NullString支持
* ForUpdate 支持
* bug修正
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16) [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
## 安装 ## 安装
@ -121,12 +115,33 @@ type User struct {
err := engine.Sync2(new(User)) err := engine.Sync2(new(User))
``` ```
* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string * 创建Engine组
```Go
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
```
```Go
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
```
所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。
* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`.
```Go ```Go
results, err := engine.Query("select * from user") results, err := engine.Query("select * from user")
results, err := engine.Where("a = 1").Query()
results, err := engine.QueryString("select * from user") results, err := engine.QueryString("select * from user")
results, err := engine.Where("a = 1").QueryString()
results, err := engine.QueryInterface("select * from user")
results, err := engine.Where("a = 1").QueryInterface()
``` ```
* `Exec` 执行一个SQL语句 * `Exec` 执行一个SQL语句
@ -135,48 +150,81 @@ results, err := engine.QueryString("select * from user")
affected, err := engine.Exec("update user set age = ? where name = ?", age, name) affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
``` ```
* 插入一条或者多条记录 * `Insert` 插入一条或者多条记录
```Go ```Go
affected, err := engine.Insert(&user) affected, err := engine.Insert(&user)
// INSERT INTO struct () values () // INSERT INTO struct () values ()
affected, err := engine.Insert(&user1, &user2) affected, err := engine.Insert(&user1, &user2)
// INSERT INTO struct1 () values () // INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values () // INSERT INTO struct2 () values ()
affected, err := engine.Insert(&users) affected, err := engine.Insert(&users)
// INSERT INTO struct () values (),(),() // INSERT INTO struct () values (),(),()
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 (),(),()
``` ```
* 查询单条记录 * `Get` 查询单条记录
```Go ```Go
has, err := engine.Get(&user) has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1 // SELECT * FROM user LIMIT 1
has, err := engine.Where("name = ?", name).Desc("id").Get(&user) has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 // SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
var name string var name string
has, err := engine.Where("id = ?", id).Cols("name").Get(&name) has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ? // SELECT name FROM user WHERE id = ?
var id int64 var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id) has, err := engine.Where("name = ?", name).Cols("id").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 valuesMap = make(map[string]string) var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap) has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ? // SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols)) var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ? // SELECT col1, col2, col3 FROM user WHERE id = ?
``` ```
* 查询多条记录,当然可以使用Join和extends来组合使用 * `Exist` 检测记录是否存在
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* `Find` 查询多条记录,当然可以使用Join和extends来组合使用
```Go ```Go
var users []User var users []User
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10 // SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
type Detail struct { type Detail struct {
Id int64 Id int64
@ -193,10 +241,10 @@ 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)
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10 // SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
``` ```
* 根据条件遍历数据库,可以有两种方式: Iterate and Rows * `Iterate``Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows
```Go ```Go
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
@ -205,6 +253,13 @@ err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
}) })
// SELECT * FROM user // SELECT * FROM user
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
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()
@ -214,10 +269,10 @@ for rows.Next() {
} }
``` ```
* 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段 * `Update` 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
```Go ```Go
affected, err := engine.Id(1).Update(&user) affected, err := engine.ID(1).Update(&user)
// UPDATE user SET ... Where id = ? // UPDATE user SET ... Where id = ?
affected, err := engine.Update(&user, &User{Name:name}) affected, err := engine.Update(&user, &User{Name:name})
@ -228,31 +283,50 @@ affected, err := engine.In(ids).Update(&user)
// UPDATE user SET ... Where id IN (?, ?, ?) // UPDATE user SET ... Where id IN (?, ?, ?)
// force update indicated columns by Cols // force update indicated columns by Cols
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? Where id = ?
// force NOT update indicated columns by Omit // force NOT update indicated columns by Omit
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? Where id = ?
affected, err := engine.Id(1).AllCols().Update(&user) affected, err := engine.ID(1).AllCols().Update(&user)
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? // UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
``` ```
* 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable * `Delete` 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
```Go ```Go
affected, err := engine.Where(...).Delete(&user) affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ... // DELETE FROM user Where ...
affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ?
``` ```
* 获取记录条数 * `Count` 获取记录条数
```Go ```Go
counts, err := engine.Count(&user) counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user // SELECT count(*) AS total FROM user
``` ```
* `Sum` 求和函数
```Go
agesFloat64, err := engine.Sum(&user, "age")
// SELECT sum(age) AS total FROM user
agesInt64, err := engine.SumInt(&user, "age")
// SELECT sum(age) AS total FROM user
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
```
* 条件编辑器 * 条件编辑器
```Go ```Go
@ -260,15 +334,76 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) // SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
``` ```
* 在一个Go程中多次操作数据库,但没有事务
```Go
session := engine.NewSession()
defer session.Close()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return nil
```
* 在一个Go程中有事务
```Go
session := engine.NewSession()
defer session.Close()
// add Begin() before any action
if err := session.Begin(); err != nil {
// if returned then will rollback automatically
return err
}
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
// add Commit() after all actions
return session.Commit()
```
# 案例 # 案例
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) * [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego) * [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/) * [Docker.cn](https://docker.cn/)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) * [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) * [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)

34
vendor/github.com/go-xorm/xorm/cache_lru.go generated vendored

@ -15,13 +15,12 @@ import (
// LRUCacher implments cache object facilities // LRUCacher implments cache object facilities
type LRUCacher struct { type LRUCacher struct {
idList *list.List idList *list.List
sqlList *list.List sqlList *list.List
idIndex map[string]map[string]*list.Element idIndex map[string]map[string]*list.Element
sqlIndex map[string]map[string]*list.Element sqlIndex map[string]map[string]*list.Element
store core.CacheStore store core.CacheStore
mutex sync.Mutex mutex sync.Mutex
// maxSize int
MaxElementSize int MaxElementSize int
Expired time.Duration Expired time.Duration
GcInterval time.Duration GcInterval time.Duration
@ -54,8 +53,6 @@ func (m *LRUCacher) RunGC() {
// GC check ids lit and sql list to remove all element expired // GC check ids lit and sql list to remove all element expired
func (m *LRUCacher) GC() { func (m *LRUCacher) GC() {
//fmt.Println("begin gc ...")
//defer fmt.Println("end gc ...")
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
var removedNum int var removedNum int
@ -64,12 +61,10 @@ func (m *LRUCacher) GC() {
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
removedNum++ removedNum++
next := e.Next() next := e.Next()
//fmt.Println("removing ...", e.Value)
node := e.Value.(*idNode) node := e.Value.(*idNode)
m.delBean(node.tbName, node.id) m.delBean(node.tbName, node.id)
e = next e = next
} else { } else {
//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len())
break break
} }
} }
@ -80,12 +75,10 @@ func (m *LRUCacher) GC() {
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
removedNum++ removedNum++
next := e.Next() next := e.Next()
//fmt.Println("removing ...", e.Value)
node := e.Value.(*sqlNode) node := e.Value.(*sqlNode)
m.delIds(node.tbName, node.sql) m.delIds(node.tbName, node.sql)
e = next e = next
} else { } else {
//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len())
break break
} }
} }
@ -116,7 +109,6 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
} }
m.delIds(tableName, sql) m.delIds(tableName, sql)
return nil return nil
} }
@ -134,7 +126,6 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
// 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.Now().Sub(lastTime) > m.Expired {
m.delBean(tableName, id) m.delBean(tableName, id)
//m.clearIds(tableName)
return nil return nil
} }
m.idList.MoveToBack(el) m.idList.MoveToBack(el)
@ -148,7 +139,6 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
// store bean is not exist, then remove memory's index // store bean is not exist, then remove memory's index
m.delBean(tableName, id) m.delBean(tableName, id)
//m.clearIds(tableName)
return nil return nil
} }
@ -166,8 +156,8 @@ func (m *LRUCacher) clearIds(tableName string) {
// ClearIds clears all sql-ids mapping on table tableName from cache // ClearIds clears all sql-ids mapping on table tableName from cache
func (m *LRUCacher) ClearIds(tableName string) { func (m *LRUCacher) ClearIds(tableName string) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
m.clearIds(tableName) m.clearIds(tableName)
m.mutex.Unlock()
} }
func (m *LRUCacher) clearBeans(tableName string) { func (m *LRUCacher) clearBeans(tableName string) {
@ -184,14 +174,13 @@ func (m *LRUCacher) clearBeans(tableName string) {
// ClearBeans clears all beans in some table // ClearBeans clears all beans in some table
func (m *LRUCacher) ClearBeans(tableName string) { func (m *LRUCacher) ClearBeans(tableName string) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
m.clearBeans(tableName) m.clearBeans(tableName)
m.mutex.Unlock()
} }
// PutIds pus ids into table // PutIds pus ids into table
func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.sqlIndex[tableName]; !ok { if _, ok := m.sqlIndex[tableName]; !ok {
m.sqlIndex[tableName] = make(map[string]*list.Element) m.sqlIndex[tableName] = make(map[string]*list.Element)
} }
@ -207,12 +196,12 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
node := e.Value.(*sqlNode) node := e.Value.(*sqlNode)
m.delIds(node.tbName, node.sql) m.delIds(node.tbName, node.sql)
} }
m.mutex.Unlock()
} }
// PutBean puts beans into table // PutBean puts beans into table
func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
var el *list.Element var el *list.Element
var ok bool var ok bool
@ -229,6 +218,7 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
node := e.Value.(*idNode) node := e.Value.(*idNode)
m.delBean(node.tbName, node.id) m.delBean(node.tbName, node.id)
} }
m.mutex.Unlock()
} }
func (m *LRUCacher) delIds(tableName, sql string) { func (m *LRUCacher) delIds(tableName, sql string) {
@ -244,8 +234,8 @@ func (m *LRUCacher) delIds(tableName, sql string) {
// DelIds deletes ids // DelIds deletes ids
func (m *LRUCacher) DelIds(tableName, sql string) { func (m *LRUCacher) DelIds(tableName, sql string) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
m.delIds(tableName, sql) m.delIds(tableName, sql)
m.mutex.Unlock()
} }
func (m *LRUCacher) delBean(tableName string, id string) { func (m *LRUCacher) delBean(tableName string, id string) {
@ -261,8 +251,8 @@ func (m *LRUCacher) delBean(tableName string, id string) {
// DelBean deletes beans in some table // DelBean deletes beans in some table
func (m *LRUCacher) DelBean(tableName string, id string) { func (m *LRUCacher) DelBean(tableName string, id string) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
m.delBean(tableName, id) m.delBean(tableName, id)
m.mutex.Unlock()
} }
type idNode struct { type idNode struct {

11
vendor/github.com/go-xorm/xorm/circle.yml generated vendored

@ -21,7 +21,16 @@ database:
test: test:
override: override:
# './...' is a relative pattern which means all subdirectories # './...' is a relative pattern which means all subdirectories
- go test -v -race -db="sqlite3::mysql::postgres" -conn_str="./test.db::root:@/xorm_test::dbname=xorm_test sslmode=disable" -coverprofile=coverage.txt -covermode=atomic - go get -u github.com/wadey/gocovmerge;
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic
- go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic
- go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt > coverage.txt
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh

26
vendor/github.com/go-xorm/xorm/context.go generated vendored

@ -0,0 +1,26 @@
// 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.
// +build go1.8
package xorm
import "context"
// PingContext tests if database is alive
func (engine *Engine) PingContext(ctx context.Context) error {
session := engine.NewSession()
defer session.Close()
return session.PingContext(ctx)
}
// PingContext test if database is ok
func (session *Session) PingContext(ctx context.Context) error {
if session.isAutoClose {
defer session.Close()
}
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
return session.DB().PingContext(ctx)
}

18
vendor/github.com/go-xorm/xorm/convert.go generated vendored

@ -209,10 +209,10 @@ func convertAssign(dest, src interface{}) error {
if src == nil { if src == nil {
dv.Set(reflect.Zero(dv.Type())) dv.Set(reflect.Zero(dv.Type()))
return nil return nil
} else {
dv.Set(reflect.New(dv.Type().Elem()))
return convertAssign(dv.Interface(), src)
} }
dv.Set(reflect.New(dv.Type().Elem()))
return convertAssign(dv.Interface(), src)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s := asString(src) s := asString(src)
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
@ -334,3 +334,15 @@ func convertInt(v interface{}) (int64, error) {
} }
return 0, fmt.Errorf("unsupported type: %v", v) return 0, fmt.Errorf("unsupported type: %v", v)
} }
func asBool(bs []byte) (bool, error) {
if len(bs) == 0 {
return false, nil
}
if bs[0] == 0x00 {
return false, nil
} else if bs[0] == 0x01 {
return true, nil
}
return strconv.ParseBool(string(bs))
}

74
vendor/github.com/go-xorm/xorm/dialect_mysql.go generated vendored

@ -172,12 +172,33 @@ type mysql struct {
allowAllFiles bool allowAllFiles bool
allowOldPasswords bool allowOldPasswords bool
clientFoundRows bool clientFoundRows bool
rowFormat string
} }
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName) return db.Base.Init(d, db, uri, drivername, dataSourceName)
} }
func (db *mysql) SetParams(params map[string]string) {
rowFormat, ok := params["rowFormat"]
if ok {
var t = strings.ToUpper(rowFormat)
switch t {
case "COMPACT":
fallthrough
case "REDUNDANT":
fallthrough
case "DYNAMIC":
fallthrough
case "COMPRESSED":
db.rowFormat = t
break
default:
break
}
}
}
func (db *mysql) SqlType(c *core.Column) string { func (db *mysql) SqlType(c *core.Column) string {
var res string var res string
switch t := c.SQLType.Name; t { switch t := c.SQLType.Name; t {
@ -487,6 +508,59 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
return indexes, nil return indexes, nil
} }
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
sql += db.Quote(tableName)
sql += " ("
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(db)
} else {
sql += col.StringNoPk(db)
}
sql = strings.TrimSpace(sql)
if len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
if storeEngine != "" {
sql += " ENGINE=" + storeEngine
}
if len(charset) == 0 {
charset = db.URI().Charset
} else if len(charset) > 0 {
sql += " DEFAULT CHARSET " + charset
}
if db.rowFormat != "" {
sql += " ROW_FORMAT=" + db.rowFormat
}
return sql
}
func (db *mysql) Filters() []core.Filter { func (db *mysql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}} return []core.Filter{&core.IdFilter{}}
} }

154
vendor/github.com/go-xorm/xorm/dialect_postgres.go generated vendored

@ -8,7 +8,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/url" "net/url"
"sort"
"strconv" "strconv"
"strings" "strings"
@ -765,6 +764,9 @@ var (
"YES": true, "YES": true,
"ZONE": true, "ZONE": true,
} }
// DefaultPostgresSchema default postgres schema
DefaultPostgresSchema = "public"
) )
type postgres struct { type postgres struct {
@ -772,7 +774,14 @@ type postgres struct {
} }
func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName) err := db.Base.Init(d, db, uri, drivername, dataSourceName)
if err != nil {
return err
}
if db.Schema == "" {
db.Schema = DefaultPostgresSchema
}
return nil
} }
func (db *postgres) SqlType(c *core.Column) string { func (db *postgres) SqlType(c *core.Column) string {
@ -781,6 +790,9 @@ func (db *postgres) SqlType(c *core.Column) string {
case core.TinyInt: case core.TinyInt:
res = core.SmallInt res = core.SmallInt
return res return res
case core.Bit:
res = core.Boolean
return res
case core.MediumInt, core.Int, core.Integer: case core.MediumInt, core.Int, core.Integer:
if c.IsAutoIncrement { if c.IsAutoIncrement {
return core.Serial return core.Serial
@ -866,29 +878,35 @@ func (db *postgres) IndexOnTable() bool {
} }
func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) { func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{tableName, idxName} if len(db.Schema) == 0 {
args := []interface{}{tableName, idxName}
return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
}
args := []interface{}{db.Schema, tableName, idxName}
return `SELECT indexname FROM pg_indexes ` + return `SELECT indexname FROM pg_indexes ` +
`WHERE tablename = ? AND indexname = ?`, args `WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
} }
func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) { func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{tableName} if len(db.Schema) == 0 {
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args args := []interface{}{tableName}
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
}
args := []interface{}{db.Schema, tableName}
return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
} }
/*func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName, colName}
return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
" AND column_name = ?", args
}*/
func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string { func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", if len(db.Schema) == 0 {
tableName, col.Name, db.SqlType(col)) return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
tableName, col.Name, db.SqlType(col))
}
return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
db.Schema, tableName, col.Name, db.SqlType(col))
} }
func (db *postgres) DropIndexSql(tableName string, index *core.Index) string { func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
//var unique string
quote := db.Quote quote := db.Quote
idxName := index.Name idxName := index.Name
@ -904,9 +922,14 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
} }
func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) { func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
args := []interface{}{tableName, colName} args := []interface{}{db.Schema, tableName, colName}
query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" + query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" +
" AND column_name = $2" " AND column_name = $3"
if len(db.Schema) == 0 {
args = []interface{}{tableName, colName}
query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
" AND column_name = $2"
}
db.LogSQL(query, args) db.LogSQL(query, args)
rows, err := db.DB().Query(query, args...) rows, err := db.DB().Query(query, args...)
@ -919,8 +942,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
} }
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
// FIXME: the schema should be replaced by user custom's args := []interface{}{tableName}
args := []interface{}{tableName, "public"}
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix , s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
@ -931,7 +953,15 @@ FROM pg_attribute f
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey) LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
LEFT JOIN pg_class AS g ON p.confrelid = g.oid LEFT JOIN pg_class AS g ON p.confrelid = g.oid
LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;` WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
var f string
if len(db.Schema) != 0 {
args = append(args, db.Schema)
f = "AND s.table_schema = $2"
}
s = fmt.Sprintf(s, f)
db.LogSQL(s, args) db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...) rows, err := db.DB().Query(s, args...)
@ -1021,9 +1051,13 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
} }
func (db *postgres) GetTables() ([]*core.Table, error) { func (db *postgres) GetTables() ([]*core.Table, error) {
// FIXME: replace public to user customrize schema args := []interface{}{}
args := []interface{}{"public"} s := "SELECT tablename FROM pg_tables"
s := fmt.Sprintf("SELECT tablename FROM pg_tables WHERE schemaname = $1") if len(db.Schema) != 0 {
args = append(args, db.Schema)
s = s + " WHERE schemaname = $1"
}
db.LogSQL(s, args) db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...) rows, err := db.DB().Query(s, args...)
@ -1047,10 +1081,13 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
} }
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
// FIXME: replace the public schema to user specify schema args := []interface{}{tableName}
args := []interface{}{"public", tableName} s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname=$1 AND tablename=$2")
db.LogSQL(s, args) db.LogSQL(s, args)
if len(db.Schema) != 0 {
args = append(args, db.Schema)
s = s + " AND schemaname=$2"
}
rows, err := db.DB().Query(s, args...) rows, err := db.DB().Query(s, args...)
if err != nil { if err != nil {
@ -1114,10 +1151,6 @@ func (vs values) Get(k string) (v string) {
return vs[k] return vs[k]
} }
func errorf(s string, args ...interface{}) {
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
}
func parseURL(connstr string) (string, error) { func parseURL(connstr string) (string, error) {
u, err := url.Parse(connstr) u, err := url.Parse(connstr)
if err != nil { if err != nil {
@ -1128,46 +1161,18 @@ func parseURL(connstr string) (string, error) {
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
} }
var kvs []string
escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
accrue := func(k, v string) {
if v != "" {
kvs = append(kvs, k+"="+escaper.Replace(v))
}
}
if u.User != nil {
v := u.User.Username()
accrue("user", v)
v, _ = u.User.Password()
accrue("password", v)
}
i := strings.Index(u.Host, ":")
if i < 0 {
accrue("host", u.Host)
} else {
accrue("host", u.Host[:i])
accrue("port", u.Host[i+1:])
}
if u.Path != "" { if u.Path != "" {
accrue("dbname", u.Path[1:]) return escaper.Replace(u.Path[1:]), nil
} }
q := u.Query() return "", nil
for k := range q {
accrue(k, q.Get(k))
}
sort.Strings(kvs) // Makes testing easier (not a performance concern)
return strings.Join(kvs, " "), nil
} }
func parseOpts(name string, o values) { func parseOpts(name string, o values) error {
if len(name) == 0 { if len(name) == 0 {
return return fmt.Errorf("invalid options: %s", name)
} }
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
@ -1176,31 +1181,36 @@ func parseOpts(name string, o values) {
for _, p := range ps { for _, p := range ps {
kv := strings.Split(p, "=") kv := strings.Split(p, "=")
if len(kv) < 2 { if len(kv) < 2 {
errorf("invalid option: %q", p) return fmt.Errorf("invalid option: %q", p)
} }
o.Set(kv[0], kv[1]) o.Set(kv[0], kv[1])
} }
return nil
} }
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.POSTGRES} db := &core.Uri{DbType: core.POSTGRES}
o := make(values)
var err error var err error
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") { if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
dataSourceName, err = parseURL(dataSourceName) db.DbName, err = parseURL(dataSourceName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else {
o := make(values)
err = parseOpts(dataSourceName, o)
if err != nil {
return nil, err
}
db.DbName = o.Get("dbname")
} }
parseOpts(dataSourceName, o)
db.DbName = o.Get("dbname")
if db.DbName == "" { if db.DbName == "" {
return nil, errors.New("dbname is empty") return nil, errors.New("dbname is empty")
} }
/*db.Schema = o.Get("schema")
if len(db.Schema) == 0 {
db.Schema = "public"
}*/
return db, nil return db, nil
} }

4
vendor/github.com/go-xorm/xorm/doc.go generated vendored

@ -8,7 +8,7 @@ Package xorm is a simple and powerful ORM for Go.
Installation Installation
Make sure you have installed Go 1.5+ and then: Make sure you have installed Go 1.6+ and then:
go get github.com/go-xorm/xorm go get github.com/go-xorm/xorm
@ -90,7 +90,7 @@ another is Rows
5. Update one or more records 5. Update one or more records
affected, err := engine.Id(...).Update(&user) affected, err := engine.ID(...).Update(&user)
// UPDATE user SET ... // UPDATE user SET ...
6. Delete one or more records, Delete MUST has condition 6. Delete one or more records, Delete MUST has condition

300
vendor/github.com/go-xorm/xorm/engine.go generated vendored

@ -19,6 +19,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core" "github.com/go-xorm/core"
) )
@ -46,6 +47,23 @@ type Engine struct {
disableGlobalCache bool disableGlobalCache bool
tagHandlers map[string]tagHandler tagHandlers map[string]tagHandler
engineGroup *EngineGroup
}
// BufferSize sets buffer size for iterate
func (engine *Engine) BufferSize(size int) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.BufferSize(size)
}
// CondDeleted returns the conditions whether a record is soft deleted.
func (engine *Engine) CondDeleted(colName string) builder.Cond {
if engine.dialect.DBType() == core.MSSQL {
return builder.IsNull{colName}
}
return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1})
} }
// ShowSQL show SQL statement or not on logger if log level is great than INFO // ShowSQL show SQL statement or not on logger if log level is great than INFO
@ -78,6 +96,11 @@ func (engine *Engine) SetLogger(logger core.ILogger) {
engine.dialect.SetLogger(logger) engine.dialect.SetLogger(logger)
} }
// SetLogLevel sets the logger level
func (engine *Engine) SetLogLevel(level core.LogLevel) {
engine.logger.SetLevel(level)
}
// SetDisableGlobalCache disable global cache or not // SetDisableGlobalCache disable global cache or not
func (engine *Engine) SetDisableGlobalCache(disable bool) { func (engine *Engine) SetDisableGlobalCache(disable bool) {
if engine.disableGlobalCache != disable { if engine.disableGlobalCache != disable {
@ -168,7 +191,7 @@ func (engine *Engine) quote(sql string) string {
return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr() return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
} }
// SqlType will be depracated, please use SQLType instead // SqlType will be deprecated, please use SQLType instead
// //
// Deprecated: use SQLType instead // Deprecated: use SQLType instead
func (engine *Engine) SqlType(c *core.Column) string { func (engine *Engine) SqlType(c *core.Column) string {
@ -195,28 +218,28 @@ func (engine *Engine) SetMaxIdleConns(conns int) {
engine.db.SetMaxIdleConns(conns) engine.db.SetMaxIdleConns(conns)
} }
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.db.SetConnMaxLifetime(d)
}
// SetDefaultCacher set the default cacher. Xorm's default not enable cacher. // SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
func (engine *Engine) SetDefaultCacher(cacher core.Cacher) { func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
engine.Cacher = cacher engine.Cacher = cacher
} }
// GetDefaultCacher returns the default cacher
func (engine *Engine) GetDefaultCacher() core.Cacher {
return engine.Cacher
}
// NoCache If you has set default cacher, and you want temporilly stop use cache, // NoCache If you has set default cacher, and you want temporilly stop use cache,
// you can use NoCache() // you can use NoCache()
func (engine *Engine) NoCache() *Session { func (engine *Engine) NoCache() *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.NoCache() return session.NoCache()
} }
// NoCascade If you do not want to auto cascade load object // NoCascade If you do not want to auto cascade load object
func (engine *Engine) NoCascade() *Session { func (engine *Engine) NoCascade() *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.NoCascade() return session.NoCascade()
} }
@ -249,7 +272,7 @@ func (engine *Engine) Dialect() core.Dialect {
// NewSession New a session // NewSession New a session
func (engine *Engine) NewSession() *Session { func (engine *Engine) NewSession() *Session {
session := &Session{Engine: engine} session := &Session{engine: engine}
session.Init() session.Init()
return session return session
} }
@ -263,7 +286,6 @@ func (engine *Engine) Close() error {
func (engine *Engine) Ping() error { func (engine *Engine) Ping() error {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
engine.logger.Infof("PING DATABASE %v", engine.DriverName())
return session.Ping() return session.Ping()
} }
@ -271,43 +293,13 @@ func (engine *Engine) Ping() error {
func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
if engine.showSQL && !engine.showExecTime { if engine.showSQL && !engine.showExecTime {
if len(sqlArgs) > 0 { if len(sqlArgs) > 0 {
engine.logger.Infof("[SQL] %v %v", sqlStr, sqlArgs) engine.logger.Infof("[SQL] %v %#v", sqlStr, sqlArgs)
} else { } else {
engine.logger.Infof("[SQL] %v", sqlStr) engine.logger.Infof("[SQL] %v", sqlStr)
} }
} }
} }
func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) {
if engine.showSQL && engine.showExecTime {
b4ExecTime := time.Now()
stmt, res, err := executionBlock()
execDuration := time.Since(b4ExecTime)
if len(args) > 0 {
engine.logger.Infof("[SQL] %s %v - took: %v", sqlStr, args, execDuration)
} else {
engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
}
return stmt, res, err
}
return executionBlock()
}
func (engine *Engine) logSQLExecutionTime(sqlStr string, args []interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) {
if engine.showSQL && engine.showExecTime {
b4ExecTime := time.Now()
res, err := executionBlock()
execDuration := time.Since(b4ExecTime)
if len(args) > 0 {
engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration)
} else {
engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration)
}
return res, err
}
return executionBlock()
}
// Sql provides raw sql input parameter. When you have a complex SQL statement // Sql provides raw sql input parameter. When you have a complex SQL statement
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. // and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
// //
@ -324,7 +316,7 @@ func (engine *Engine) Sql(querystring string, args ...interface{}) *Session {
// This code will execute "select * from user" and set the records to users // This code will execute "select * from user" and set the records to users
func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session { func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.SQL(query, args...) return session.SQL(query, args...)
} }
@ -333,14 +325,14 @@ func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
// invoked. Call NoAutoTime if you dont' want to fill automatically. // invoked. Call NoAutoTime if you dont' want to fill automatically.
func (engine *Engine) NoAutoTime() *Session { func (engine *Engine) NoAutoTime() *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.NoAutoTime() return session.NoAutoTime()
} }
// NoAutoCondition disable auto generate Where condition from bean or not // NoAutoCondition disable auto generate Where condition from bean or not
func (engine *Engine) NoAutoCondition(no ...bool) *Session { func (engine *Engine) NoAutoCondition(no ...bool) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.NoAutoCondition(no...) return session.NoAutoCondition(no...)
} }
@ -574,56 +566,56 @@ func (engine *Engine) tbName(v reflect.Value) string {
// Cascade use cascade or not // Cascade use cascade or not
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Cascade(trueOrFalse...) return session.Cascade(trueOrFalse...)
} }
// Where method provide a condition query // Where method provide a condition query
func (engine *Engine) Where(query interface{}, args ...interface{}) *Session { func (engine *Engine) Where(query interface{}, args ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Where(query, args...) return session.Where(query, args...)
} }
// Id will be depracated, please use ID instead // Id will be deprecated, please use ID instead
func (engine *Engine) Id(id interface{}) *Session { func (engine *Engine) Id(id interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Id(id) return session.Id(id)
} }
// ID method provoide a condition as (id) = ? // ID method provoide a condition as (id) = ?
func (engine *Engine) ID(id interface{}) *Session { func (engine *Engine) ID(id interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.ID(id) return session.ID(id)
} }
// Before apply before Processor, affected bean is passed to closure arg // Before apply before Processor, affected bean is passed to closure arg
func (engine *Engine) Before(closures func(interface{})) *Session { func (engine *Engine) Before(closures func(interface{})) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Before(closures) return session.Before(closures)
} }
// After apply after insert Processor, affected bean is passed to closure arg // After apply after insert Processor, affected bean is passed to closure arg
func (engine *Engine) After(closures func(interface{})) *Session { func (engine *Engine) After(closures func(interface{})) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.After(closures) return session.After(closures)
} }
// Charset set charset when create table, only support mysql now // Charset set charset when create table, only support mysql now
func (engine *Engine) Charset(charset string) *Session { func (engine *Engine) Charset(charset string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Charset(charset) return session.Charset(charset)
} }
// StoreEngine set store engine when create table, only support mysql now // StoreEngine set store engine when create table, only support mysql now
func (engine *Engine) StoreEngine(storeEngine string) *Session { func (engine *Engine) StoreEngine(storeEngine string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.StoreEngine(storeEngine) return session.StoreEngine(storeEngine)
} }
@ -632,35 +624,35 @@ func (engine *Engine) StoreEngine(storeEngine string) *Session {
// but distinct will not provide id // but distinct will not provide id
func (engine *Engine) Distinct(columns ...string) *Session { func (engine *Engine) Distinct(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Distinct(columns...) return session.Distinct(columns...)
} }
// Select customerize your select columns or contents // Select customerize your select columns or contents
func (engine *Engine) Select(str string) *Session { func (engine *Engine) Select(str string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Select(str) return session.Select(str)
} }
// Cols only use the parameters as select or update columns // Cols only use the parameters as select or update columns
func (engine *Engine) Cols(columns ...string) *Session { func (engine *Engine) Cols(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Cols(columns...) return session.Cols(columns...)
} }
// AllCols indicates that all columns should be use // AllCols indicates that all columns should be use
func (engine *Engine) AllCols() *Session { func (engine *Engine) AllCols() *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.AllCols() return session.AllCols()
} }
// MustCols specify some columns must use even if they are empty // MustCols specify some columns must use even if they are empty
func (engine *Engine) MustCols(columns ...string) *Session { func (engine *Engine) MustCols(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.MustCols(columns...) return session.MustCols(columns...)
} }
@ -671,77 +663,84 @@ func (engine *Engine) MustCols(columns ...string) *Session {
// it will use parameters's columns // it will use parameters's columns
func (engine *Engine) UseBool(columns ...string) *Session { func (engine *Engine) UseBool(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.UseBool(columns...) return session.UseBool(columns...)
} }
// Omit only not use the parameters as select or update columns // Omit only not use the parameters as select or update columns
func (engine *Engine) Omit(columns ...string) *Session { func (engine *Engine) Omit(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Omit(columns...) return session.Omit(columns...)
} }
// Nullable set null when column is zero-value and nullable for update // Nullable set null when column is zero-value and nullable for update
func (engine *Engine) Nullable(columns ...string) *Session { func (engine *Engine) Nullable(columns ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Nullable(columns...) return session.Nullable(columns...)
} }
// In will generate "column IN (?, ?)" // In will generate "column IN (?, ?)"
func (engine *Engine) In(column string, args ...interface{}) *Session { func (engine *Engine) In(column string, args ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.In(column, args...) return session.In(column, args...)
} }
// NotIn will generate "column NOT IN (?, ?)"
func (engine *Engine) NotIn(column string, args ...interface{}) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.NotIn(column, args...)
}
// Incr provides a update string like "column = column + ?" // Incr provides a update string like "column = column + ?"
func (engine *Engine) Incr(column string, arg ...interface{}) *Session { func (engine *Engine) Incr(column string, arg ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Incr(column, arg...) return session.Incr(column, arg...)
} }
// Decr provides a update string like "column = column - ?" // Decr provides a update string like "column = column - ?"
func (engine *Engine) Decr(column string, arg ...interface{}) *Session { func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Decr(column, arg...) return session.Decr(column, arg...)
} }
// SetExpr provides a update string like "column = {expression}" // SetExpr provides a update string like "column = {expression}"
func (engine *Engine) SetExpr(column string, expression string) *Session { func (engine *Engine) SetExpr(column string, expression string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.SetExpr(column, expression) return session.SetExpr(column, expression)
} }
// Table temporarily change the Get, Find, Update's table // Table temporarily change the Get, Find, Update's table
func (engine *Engine) Table(tableNameOrBean interface{}) *Session { func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Table(tableNameOrBean) return session.Table(tableNameOrBean)
} }
// Alias set the table alias // Alias set the table alias
func (engine *Engine) Alias(alias string) *Session { func (engine *Engine) Alias(alias string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Alias(alias) return session.Alias(alias)
} }
// Limit will generate "LIMIT start, limit" // Limit will generate "LIMIT start, limit"
func (engine *Engine) Limit(limit int, start ...int) *Session { func (engine *Engine) Limit(limit int, start ...int) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Limit(limit, start...) return session.Limit(limit, start...)
} }
// Desc will generate "ORDER BY column1 DESC, column2 DESC" // Desc will generate "ORDER BY column1 DESC, column2 DESC"
func (engine *Engine) Desc(colNames ...string) *Session { func (engine *Engine) Desc(colNames ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Desc(colNames...) return session.Desc(colNames...)
} }
@ -753,39 +752,47 @@ func (engine *Engine) Desc(colNames ...string) *Session {
// //
func (engine *Engine) Asc(colNames ...string) *Session { func (engine *Engine) Asc(colNames ...string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Asc(colNames...) return session.Asc(colNames...)
} }
// OrderBy will generate "ORDER BY order" // OrderBy will generate "ORDER BY order"
func (engine *Engine) OrderBy(order string) *Session { func (engine *Engine) OrderBy(order string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.OrderBy(order) return session.OrderBy(order)
} }
// Prepare enables prepare statement
func (engine *Engine) Prepare() *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.Prepare()
}
// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN // Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Join(joinOperator, tablename, condition, args...) return session.Join(joinOperator, tablename, condition, args...)
} }
// GroupBy generate group by statement // GroupBy generate group by statement
func (engine *Engine) GroupBy(keys string) *Session { func (engine *Engine) GroupBy(keys string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.GroupBy(keys) return session.GroupBy(keys)
} }
// Having generate having statement // Having generate having statement
func (engine *Engine) Having(conditions string) *Session { func (engine *Engine) Having(conditions string) *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Having(conditions) return session.Having(conditions)
} }
func (engine *Engine) unMapType(t reflect.Type) { // UnMapType removes the datbase mapper of a type
func (engine *Engine) UnMapType(t reflect.Type) {
engine.mutex.Lock() engine.mutex.Lock()
defer engine.mutex.Unlock() defer engine.mutex.Unlock()
delete(engine.Tables, t) delete(engine.Tables, t)
@ -942,7 +949,7 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
} }
if pStart > -1 { if pStart > -1 {
if !strings.HasSuffix(k, ")") { if !strings.HasSuffix(k, ")") {
return nil, errors.New("cannot match ) charactor") return nil, fmt.Errorf("field %s tag %s cannot match ) charactor", col.FieldName, key)
} }
ctx.tagName = k[:pStart] ctx.tagName = k[:pStart]
@ -1108,19 +1115,39 @@ func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
pk := make([]interface{}, len(table.PrimaryKeys)) pk := make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() { for i, col := range table.PKColumns() {
var err error
pkField := v.FieldByName(col.FieldName) pkField := v.FieldByName(col.FieldName)
switch pkField.Kind() { switch pkField.Kind() {
case reflect.String: case reflect.String:
pk[i] = pkField.String() pk[i], err = engine.idTypeAssertion(col, pkField.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
pk[i] = pkField.Int() pk[i], err = engine.idTypeAssertion(col, strconv.FormatInt(pkField.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
pk[i] = pkField.Uint() // id of uint will be converted to int64
pk[i], err = engine.idTypeAssertion(col, strconv.FormatUint(pkField.Uint(), 10))
}
if err != nil {
return nil, err
} }
} }
return core.PK(pk), nil return core.PK(pk), nil
} }
func (engine *Engine) idTypeAssertion(col *core.Column, sid string) (interface{}, error) {
if col.SQLType.IsNumeric() {
n, err := strconv.ParseInt(sid, 10, 64)
if err != nil {
return nil, err
}
return n, nil
} else if col.SQLType.IsText() {
return sid, nil
} else {
return nil, errors.New("not supported")
}
}
// CreateIndexes create indexes // CreateIndexes create indexes
func (engine *Engine) CreateIndexes(bean interface{}) error { func (engine *Engine) CreateIndexes(bean interface{}) error {
session := engine.NewSession() session := engine.NewSession()
@ -1192,6 +1219,9 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
// table, column, index, unique. but will not delete or change anything. // table, column, index, unique. but will not delete or change anything.
// If you change some field, you should change the database manually. // If you change some field, you should change the database manually.
func (engine *Engine) Sync(beans ...interface{}) error { func (engine *Engine) Sync(beans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
for _, bean := range beans { for _, bean := range beans {
v := rValue(bean) v := rValue(bean)
tableName := engine.tbName(v) tableName := engine.tbName(v)
@ -1200,14 +1230,12 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err return err
} }
s := engine.NewSession() isExist, err := session.Table(bean).isTableExist(tableName)
defer s.Close()
isExist, err := s.Table(bean).isTableExist(tableName)
if err != nil { if err != nil {
return err return err
} }
if !isExist { if !isExist {
err = engine.CreateTables(bean) err = session.createTable(bean)
if err != nil { if err != nil {
return err return err
} }
@ -1218,11 +1246,11 @@ func (engine *Engine) Sync(beans ...interface{}) error {
}*/ }*/
var isEmpty bool var isEmpty bool
if isEmpty { if isEmpty {
err = engine.DropTables(bean) err = session.dropTable(bean)
if err != nil { if err != nil {
return err return err
} }
err = engine.CreateTables(bean) err = session.createTable(bean)
if err != nil { if err != nil {
return err return err
} }
@ -1233,9 +1261,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err return err
} }
if !isExist { if !isExist {
session := engine.NewSession() if err := session.statement.setRefValue(v); err != nil {
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
return err return err
} }
err = session.addColumn(col.Name) err = session.addColumn(col.Name)
@ -1246,9 +1272,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
} }
for name, index := range table.Indexes { for name, index := range table.Indexes {
session := engine.NewSession() if err := session.statement.setRefValue(v); err != nil {
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
return err return err
} }
if index.Type == core.UniqueType { if index.Type == core.UniqueType {
@ -1257,9 +1281,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err return err
} }
if !isExist { if !isExist {
session := engine.NewSession() if err := session.statement.setRefValue(v); err != nil {
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
return err return err
} }
@ -1274,9 +1296,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err return err
} }
if !isExist { if !isExist {
session := engine.NewSession() if err := session.statement.setRefValue(v); err != nil {
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
return err return err
} }
@ -1312,7 +1332,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
@ -1332,7 +1352,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
@ -1356,17 +1376,24 @@ func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error)
} }
// Query a raw sql and return records as []map[string][]byte // Query a raw sql and return records as []map[string][]byte
func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { func (engine *Engine) Query(sqlorArgs ...interface{}) (resultsSlice []map[string][]byte, err error) {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.Query(sql, paramStr...) return session.Query(sqlorArgs...)
} }
// QueryString runs a raw sql and return records as []map[string]string // QueryString runs a raw sql and return records as []map[string]string
func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { func (engine *Engine) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
session := engine.NewSession()
defer session.Close()
return session.QueryString(sqlorArgs...)
}
// QueryInterface runs a raw sql and return records as []map[string]interface{}
func (engine *Engine) QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.QueryString(sqlStr, args...) return session.QueryInterface(sqlorArgs...)
} }
// Insert one or more records // Insert one or more records
@ -1410,6 +1437,13 @@ func (engine *Engine) Get(bean interface{}) (bool, error) {
return session.Get(bean) return session.Get(bean)
} }
// Exist returns true if the record exist otherwise return false
func (engine *Engine) Exist(bean ...interface{}) (bool, error) {
session := engine.NewSession()
defer session.Close()
return session.Exist(bean...)
}
// Find retrieve records from table, condiBeans's non-empty fields // Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct // map[int64]*Struct
@ -1419,6 +1453,13 @@ func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
return session.Find(beans, condiBeans...) return session.Find(beans, condiBeans...)
} }
// FindAndCount find the results and also return the counts
func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.FindAndCount(rowsSlicePtr, condiBean...)
}
// Iterate record by record handle records from table, bean's non-empty fields // Iterate record by record handle records from table, bean's non-empty fields
// are conditions. // are conditions.
func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error { func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error {
@ -1435,10 +1476,10 @@ func (engine *Engine) Rows(bean interface{}) (*Rows, error) {
} }
// Count counts the records. bean's non-empty fields are conditions. // Count counts the records. bean's non-empty fields are conditions.
func (engine *Engine) Count(bean interface{}) (int64, error) { func (engine *Engine) Count(bean ...interface{}) (int64, error) {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.Count(bean) return session.Count(bean...)
} }
// Sum sum the records by some column. bean's non-empty fields are conditions. // Sum sum the records by some column. bean's non-empty fields are conditions.
@ -1448,6 +1489,13 @@ func (engine *Engine) Sum(bean interface{}, colName string) (float64, error) {
return session.Sum(bean, colName) return session.Sum(bean, colName)
} }
// SumInt sum the records by some column. bean's non-empty fields are conditions.
func (engine *Engine) SumInt(bean interface{}, colName string) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.SumInt(bean, colName)
}
// Sums sum the records by some columns. bean's non-empty fields are conditions. // Sums sum the records by some columns. bean's non-empty fields are conditions.
func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) { func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) {
session := engine.NewSession() session := engine.NewSession()
@ -1510,10 +1558,14 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
return results, lastError return results, lastError
} }
// NowTime2 return current time // nowTime return current time
func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) { func (engine *Engine) nowTime(col *core.Column) (interface{}, time.Time) {
t := time.Now() t := time.Now()
return engine.formatTime(sqlTypeName, t.In(engine.DatabaseTZ)), t.In(engine.TZLocation) var tz = engine.DatabaseTZ
if !col.DisableTimeZone && col.TimeZone != nil {
tz = col.TimeZone
}
return engine.formatTime(col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation)
} }
func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) { func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
@ -1554,9 +1606,39 @@ func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}
return return
} }
// GetColumnMapper returns the column name mapper
func (engine *Engine) GetColumnMapper() core.IMapper {
return engine.ColumnMapper
}
// GetTableMapper returns the table name mapper
func (engine *Engine) GetTableMapper() core.IMapper {
return engine.TableMapper
}
// GetTZLocation returns time zone of the application
func (engine *Engine) GetTZLocation() *time.Location {
return engine.TZLocation
}
// SetTZLocation sets time zone of the application
func (engine *Engine) SetTZLocation(tz *time.Location) {
engine.TZLocation = tz
}
// GetTZDatabase returns time zone of the database
func (engine *Engine) GetTZDatabase() *time.Location {
return engine.DatabaseTZ
}
// SetTZDatabase sets time zone of the database
func (engine *Engine) SetTZDatabase(tz *time.Location) {
engine.DatabaseTZ = tz
}
// Unscoped always disable struct tag "deleted" // Unscoped always disable struct tag "deleted"
func (engine *Engine) Unscoped() *Session { func (engine *Engine) Unscoped() *Session {
session := engine.NewSession() session := engine.NewSession()
session.IsAutoClose = true session.isAutoClose = true
return session.Unscoped() return session.Unscoped()
} }

230
vendor/github.com/go-xorm/xorm/engine_cond.go generated vendored

@ -0,0 +1,230 @@
// 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 (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (engine *Engine) buildConds(table *core.Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool,
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
var conds []builder.Cond
for _, col := range table.Columns() {
if !includeVersion && col.IsVersion {
continue
}
if !includeUpdated && col.IsUpdated {
continue
}
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
continue
}
if col.SQLType.IsJson() {
continue
}
var colName string
if addedTableName {
var nm = tableName
if len(aliasName) > 0 {
nm = aliasName
}
colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
} else {
colName = engine.Quote(col.Name)
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
engine.logger.Error(err)
continue
}
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
conds = append(conds, engine.CondDeleted(colName))
}
fieldValue := *fieldValuePtr
if fieldValue.Interface() == nil {
continue
}
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
if b {
requiredField = true
} else {
continue
}
}
if fieldType.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
if includeNil {
conds = append(conds, builder.Eq{colName: nil})
}
continue
} else if !fieldValue.IsValid() {
continue
} else {
// dereference ptr type to instance type
fieldValue = fieldValue.Elem()
fieldType = reflect.TypeOf(fieldValue.Interface())
requiredField = true
}
}
var val interface{}
switch fieldType.Kind() {
case reflect.Bool:
if allUseBool || requiredField {
val = fieldValue.Interface()
} else {
// if a bool in a struct, it will not be as a condition because it default is false,
// please use Where() instead
continue
}
case reflect.String:
if !requiredField && fieldValue.String() == "" {
continue
}
// for MyString, should convert to string or panic
if fieldType.String() != reflect.String.String() {
val = fieldValue.String()
} else {
val = fieldValue.Interface()
}
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
if !requiredField && fieldValue.Int() == 0 {
continue
}
val = fieldValue.Interface()
case reflect.Float32, reflect.Float64:
if !requiredField && fieldValue.Float() == 0.0 {
continue
}
val = fieldValue.Interface()
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
if !requiredField && fieldValue.Uint() == 0 {
continue
}
t := int64(fieldValue.Uint())
val = reflect.ValueOf(&t).Interface()
case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
continue
}
val = engine.formatColTime(col, t)
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
continue
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
val, _ = valNul.Value()
if val == nil {
continue
}
} else {
if col.SQLType.IsJson() {
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
if len(table.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
// fix non-int pk issues
//if pkField.Int() != 0 {
if pkField.IsValid() && !isZero(pkField.Interface()) {
val = pkField.Interface()
} else {
continue
}
} else {
//TODO: how to handler?
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
}
} else {
val = fieldValue.Interface()
}
}
}
case reflect.Array:
continue
case reflect.Slice, reflect.Map:
if fieldValue == reflect.Zero(fieldType) {
continue
}
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
continue
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
fieldType.Elem().Kind() == reflect.Uint8 {
if fieldValue.Len() > 0 {
val = fieldValue.Bytes()
} else {
continue
}
} else {
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
continue
}
default:
val = fieldValue.Interface()
}
conds = append(conds, builder.Eq{colName: val})
}
return builder.And(conds...), nil
}

194
vendor/github.com/go-xorm/xorm/engine_group.go generated vendored

@ -0,0 +1,194 @@
// 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 (
"github.com/go-xorm/core"
)
// EngineGroup defines an engine group
type EngineGroup struct {
*Engine
slaves []*Engine
policy GroupPolicy
}
// NewEngineGroup creates a new engine group
func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) {
var eg EngineGroup
if len(policies) > 0 {
eg.policy = policies[0]
} else {
eg.policy = RoundRobinPolicy()
}
driverName, ok1 := args1.(string)
conns, ok2 := args2.([]string)
if ok1 && ok2 {
engines := make([]*Engine, len(conns))
for i, conn := range conns {
engine, err := NewEngine(driverName, conn)
if err != nil {
return nil, err
}
engine.engineGroup = &eg
engines[i] = engine
}
eg.Engine = engines[0]
eg.slaves = engines[1:]
return &eg, nil
}
master, ok3 := args1.(*Engine)
slaves, ok4 := args2.([]*Engine)
if ok3 && ok4 {
master.engineGroup = &eg
for i := 0; i < len(slaves); i++ {
slaves[i].engineGroup = &eg
}
eg.Engine = master
eg.slaves = slaves
return &eg, nil
}
return nil, ErrParamsType
}
// Close the engine
func (eg *EngineGroup) Close() error {
err := eg.Engine.Close()
if err != nil {
return err
}
for i := 0; i < len(eg.slaves); i++ {
err := eg.slaves[i].Close()
if err != nil {
return err
}
}
return nil
}
// Master returns the master engine
func (eg *EngineGroup) Master() *Engine {
return eg.Engine
}
// Ping tests if database is alive
func (eg *EngineGroup) Ping() error {
if err := eg.Engine.Ping(); err != nil {
return err
}
for _, slave := range eg.slaves {
if err := slave.Ping(); err != nil {
return err
}
}
return nil
}
// SetColumnMapper set the column name mapping rule
func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
eg.Engine.ColumnMapper = mapper
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ColumnMapper = mapper
}
}
// SetDefaultCacher set the default cacher
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
eg.Engine.SetDefaultCacher(cacher)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetDefaultCacher(cacher)
}
}
// SetLogger set the new logger
func (eg *EngineGroup) SetLogger(logger core.ILogger) {
eg.Engine.SetLogger(logger)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetLogger(logger)
}
}
// SetLogLevel sets the logger level
func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
eg.Engine.SetLogLevel(level)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetLogLevel(level)
}
}
// SetMapper set the name mapping rules
func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
eg.Engine.SetMapper(mapper)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetMapper(mapper)
}
}
// SetMaxIdleConns set the max idle connections on pool, default is 2
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
eg.Engine.db.SetMaxIdleConns(conns)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].db.SetMaxIdleConns(conns)
}
}
// SetMaxOpenConns is only available for go 1.2+
func (eg *EngineGroup) SetMaxOpenConns(conns int) {
eg.Engine.db.SetMaxOpenConns(conns)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].db.SetMaxOpenConns(conns)
}
}
// SetPolicy set the group policy
func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
eg.policy = policy
return eg
}
// SetTableMapper set the table name mapping rule
func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
eg.Engine.TableMapper = mapper
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].TableMapper = mapper
}
}
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
func (eg *EngineGroup) ShowExecTime(show ...bool) {
eg.Engine.ShowExecTime(show...)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ShowExecTime(show...)
}
}
// ShowSQL show SQL statement or not on logger if log level is great than INFO
func (eg *EngineGroup) ShowSQL(show ...bool) {
eg.Engine.ShowSQL(show...)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ShowSQL(show...)
}
}
// Slave returns one of the physical databases which is a slave according the policy
func (eg *EngineGroup) Slave() *Engine {
switch len(eg.slaves) {
case 0:
return eg.Engine
case 1:
return eg.slaves[0]
}
return eg.policy.Slave(eg)
}
// Slaves returns all the slaves
func (eg *EngineGroup) Slaves() []*Engine {
return eg.slaves
}

116
vendor/github.com/go-xorm/xorm/engine_group_policy.go generated vendored

@ -0,0 +1,116 @@
// 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 (
"math/rand"
"sync"
"time"
)
// GroupPolicy is be used by chosing the current slave from slaves
type GroupPolicy interface {
Slave(*EngineGroup) *Engine
}
// GroupPolicyHandler should be used when a function is a GroupPolicy
type GroupPolicyHandler func(*EngineGroup) *Engine
// Slave implements the chosen of slaves
func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine {
return h(eg)
}
// RandomPolicy implmentes randomly chose the slave of slaves
func RandomPolicy() GroupPolicyHandler {
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
return func(g *EngineGroup) *Engine {
return g.Slaves()[r.Intn(len(g.Slaves()))]
}
}
// WeightRandomPolicy implmentes randomly chose the slave of slaves
func WeightRandomPolicy(weights []int) GroupPolicyHandler {
var rands = make([]int, 0, len(weights))
for i := 0; i < len(weights); i++ {
for n := 0; n < weights[i]; n++ {
rands = append(rands, i)
}
}
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
idx := rands[r.Intn(len(rands))]
if idx >= len(slaves) {
idx = len(slaves) - 1
}
return slaves[idx]
}
}
func RoundRobinPolicy() GroupPolicyHandler {
var pos = -1
var lock sync.Mutex
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
lock.Lock()
defer lock.Unlock()
pos++
if pos >= len(slaves) {
pos = 0
}
return slaves[pos]
}
}
func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
var rands = make([]int, 0, len(weights))
for i := 0; i < len(weights); i++ {
for n := 0; n < weights[i]; n++ {
rands = append(rands, i)
}
}
var pos = -1
var lock sync.Mutex
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
lock.Lock()
defer lock.Unlock()
pos++
if pos >= len(rands) {
pos = 0
}
idx := rands[pos]
if idx >= len(slaves) {
idx = len(slaves) - 1
}
return slaves[idx]
}
}
// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
func LeastConnPolicy() GroupPolicyHandler {
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
connections := 0
idx := 0
for i := 0; i < len(slaves); i++ {
openConnections := slaves[i].DB().Stats().OpenConnections
if i == 0 {
connections = openConnections
idx = i
} else if openConnections <= connections {
connections = openConnections
idx = i
}
}
return slaves[idx]
}
}

22
vendor/github.com/go-xorm/xorm/engine_maxlife.go generated vendored

@ -0,0 +1,22 @@
// 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.
// +build go1.6
package xorm
import "time"
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.db.SetConnMaxLifetime(d)
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
eg.Engine.SetConnMaxLifetime(d)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetConnMaxLifetime(d)
}
}

2
vendor/github.com/go-xorm/xorm/error.go generated vendored

@ -23,4 +23,6 @@ var (
ErrNeedDeletedCond = errors.New("Delete need at least one condition") ErrNeedDeletedCond = errors.New("Delete need at least one condition")
// ErrNotImplemented not implemented // ErrNotImplemented not implemented
ErrNotImplemented = errors.New("Not implemented") ErrNotImplemented = errors.New("Not implemented")
// ErrConditionType condition type unsupported
ErrConditionType = errors.New("Unsupported conditon type")
) )

24
vendor/github.com/go-xorm/xorm/helpers.go generated vendored

@ -358,7 +358,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
for _, col := range table.Columns() { for _, col := range table.Columns() {
if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated { if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
continue continue
} }
} }
@ -397,28 +397,32 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
continue continue
} }
if session.Statement.ColumnStr != "" { if session.statement.ColumnStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
continue
} else if _, ok := session.statement.incrColumns[col.Name]; ok {
continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
continue continue
} }
} }
if session.Statement.OmitStr != "" { if session.statement.OmitStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
continue continue
} }
} }
// !evalphobia! set fieldValue as nil when column is nullable and zero-value // !evalphobia! set fieldValue as nil when column is nullable and zero-value
if _, ok := getFlagForColumn(session.Statement.nullableMap, col); ok { if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
if col.Nullable && isZero(fieldValue.Interface()) { if col.Nullable && isZero(fieldValue.Interface()) {
var nilValue *int var nilValue *int
fieldValue = reflect.ValueOf(nilValue) fieldValue = reflect.ValueOf(nilValue)
} }
} }
if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ { if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
// if time is non-empty, then set to auto time // if time is non-empty, then set to auto time
val, t := session.Engine.NowTime2(col.SQLType.Name) val, t := session.engine.nowTime(col)
args = append(args, val) args = append(args, val)
var colName = col.Name var colName = col.Name
@ -426,7 +430,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
col := table.GetColumn(colName) col := table.GetColumn(colName)
setColumnTime(bean, col, t) setColumnTime(bean, col, t)
}) })
} else if col.IsVersion && session.Statement.checkVersion { } else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1) args = append(args, 1)
} else { } else {
arg, err := session.value2Interface(col, fieldValue) arg, err := session.value2Interface(col, fieldValue)
@ -437,7 +441,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
} }
if includeQuote { if includeQuote {
colNames = append(colNames, session.Engine.Quote(col.Name)+" = ?") colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
} else { } else {
colNames = append(colNames, col.Name) colNames = append(colNames, col.Name)
} }

104
vendor/github.com/go-xorm/xorm/interface.go generated vendored

@ -0,0 +1,104 @@
// 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 (
"database/sql"
"reflect"
"time"
"github.com/go-xorm/core"
)
// Interface defines the interface which Engine, EngineGroup and Session will implementate.
type Interface interface {
AllCols() *Session
Alias(alias string) *Session
Asc(colNames ...string) *Session
BufferSize(size int) *Session
Cols(columns ...string) *Session
Count(...interface{}) (int64, error)
CreateIndexes(bean interface{}) error
CreateUniques(bean interface{}) error
Decr(column string, arg ...interface{}) *Session
Desc(...string) *Session
Delete(interface{}) (int64, error)
Distinct(columns ...string) *Session
DropIndexes(bean interface{}) error
Exec(string, ...interface{}) (sql.Result, error)
Exist(bean ...interface{}) (bool, error)
Find(interface{}, ...interface{}) error
FindAndCount(interface{}, ...interface{}) (int64, error)
Get(interface{}) (bool, error)
GroupBy(keys string) *Session
ID(interface{}) *Session
In(string, ...interface{}) *Session
Incr(column string, arg ...interface{}) *Session
Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error)
IsTableEmpty(bean interface{}) (bool, error)
IsTableExist(beanOrTableName interface{}) (bool, error)
Iterate(interface{}, IterFunc) error
Limit(int, ...int) *Session
NoAutoCondition(...bool) *Session
NotIn(string, ...interface{}) *Session
Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
Omit(columns ...string) *Session
OrderBy(order string) *Session
Ping() error
Query(sqlOrAgrs ...interface{}) (resultsSlice []map[string][]byte, err error)
QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error)
QueryString(sqlorArgs ...interface{}) ([]map[string]string, error)
Rows(bean interface{}) (*Rows, error)
SetExpr(string, string) *Session
SQL(interface{}, ...interface{}) *Session
Sum(bean interface{}, colName string) (float64, error)
SumInt(bean interface{}, colName string) (int64, error)
Sums(bean interface{}, colNames ...string) ([]float64, error)
SumsInt(bean interface{}, colNames ...string) ([]int64, error)
Table(tableNameOrBean interface{}) *Session
Unscoped() *Session
Update(bean interface{}, condiBeans ...interface{}) (int64, error)
UseBool(...string) *Session
Where(interface{}, ...interface{}) *Session
}
// EngineInterface defines the interface which Engine, EngineGroup will implementate.
type EngineInterface interface {
Interface
Before(func(interface{})) *Session
Charset(charset string) *Session
CreateTables(...interface{}) error
DBMetas() ([]*core.Table, error)
Dialect() core.Dialect
DropTables(...interface{}) error
DumpAllToFile(fp string, tp ...core.DbType) error
GetColumnMapper() core.IMapper
GetDefaultCacher() core.Cacher
GetTableMapper() core.IMapper
GetTZDatabase() *time.Location
GetTZLocation() *time.Location
NewSession() *Session
NoAutoTime() *Session
Quote(string) string
SetDefaultCacher(core.Cacher)
SetLogLevel(core.LogLevel)
SetMapper(core.IMapper)
SetTZDatabase(tz *time.Location)
SetTZLocation(tz *time.Location)
ShowSQL(show ...bool)
Sync(...interface{}) error
Sync2(...interface{}) error
StoreEngine(storeEngine string) *Session
TableInfo(bean interface{}) *Table
UnMapType(reflect.Type)
}
var (
_ Interface = &Session{}
_ EngineInterface = &Engine{}
_ EngineInterface = &EngineGroup{}
)

40
vendor/github.com/go-xorm/xorm/processors.go generated vendored

@ -29,13 +29,6 @@ type AfterSetProcessor interface {
AfterSet(string, Cell) AfterSet(string, Cell)
} }
// !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
//// Executed before an object is validated
//type BeforeValidateProcessor interface {
// BeforeValidate()
//}
// --
// AfterInsertProcessor executed after an object is persisted to the database // AfterInsertProcessor executed after an object is persisted to the database
type AfterInsertProcessor interface { type AfterInsertProcessor interface {
AfterInsert() AfterInsert()
@ -50,3 +43,36 @@ type AfterUpdateProcessor interface {
type AfterDeleteProcessor interface { type AfterDeleteProcessor interface {
AfterDelete() AfterDelete()
} }
// AfterLoadProcessor executed after an ojbect has been loaded from database
type AfterLoadProcessor interface {
AfterLoad()
}
// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter
type AfterLoadSessionProcessor interface {
AfterLoad(*Session)
}
type executedProcessorFunc func(*Session, interface{}) error
type executedProcessor struct {
fun executedProcessorFunc
session *Session
bean interface{}
}
func (executor *executedProcessor) execute() error {
return executor.fun(executor.session, executor.bean)
}
func (session *Session) executeProcessors() error {
processors := session.afterProcessors
session.afterProcessors = make([]executedProcessor, 0)
for _, processor := range processors {
if err := processor.execute(); err != nil {
return err
}
}
return nil
}

73
vendor/github.com/go-xorm/xorm/rows.go generated vendored

@ -17,7 +17,6 @@ type Rows struct {
NoTypeCheck bool NoTypeCheck bool
session *Session session *Session
stmt *core.Stmt
rows *core.Rows rows *core.Rows
fields []string fields []string
beanType reflect.Type beanType reflect.Type
@ -29,53 +28,33 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
rows.session = session rows.session = session
rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type() rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
defer rows.session.resetStatement()
var sqlStr string var sqlStr string
var args []interface{} var args []interface{}
var err error
if err := rows.session.Statement.setRefValue(rValue(bean)); err != nil { if err = rows.session.statement.setRefValue(rValue(bean)); err != nil {
return nil, err return nil, err
} }
if len(session.Statement.TableName()) <= 0 { if len(session.statement.TableName()) <= 0 {
return nil, ErrTableNotFound return nil, ErrTableNotFound
} }
if rows.session.Statement.RawSQL == "" { if rows.session.statement.RawSQL == "" {
sqlStr, args = rows.session.Statement.genGetSQL(bean) sqlStr, args, err = rows.session.statement.genGetSQL(bean)
} else {
sqlStr = rows.session.Statement.RawSQL
args = rows.session.Statement.RawParams
}
for _, filter := range rows.session.Engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
}
rows.session.saveLastSQL(sqlStr, args...)
var err error
if rows.session.prepareStmt {
rows.stmt, err = rows.session.DB().Prepare(sqlStr)
if err != nil {
rows.lastError = err
rows.Close()
return nil, err
}
rows.rows, err = rows.stmt.Query(args...)
if err != nil { if err != nil {
rows.lastError = err
rows.Close()
return nil, err return nil, err
} }
} else { } else {
rows.rows, err = rows.session.DB().Query(sqlStr, args...) sqlStr = rows.session.statement.RawSQL
if err != nil { args = rows.session.statement.RawParams
rows.lastError = err }
rows.Close()
return nil, err rows.rows, err = rows.session.queryRows(sqlStr, args...)
} if err != nil {
rows.lastError = err
rows.Close()
return nil, err
} }
rows.fields, err = rows.rows.Columns() rows.fields, err = rows.rows.Columns()
@ -116,17 +95,26 @@ func (rows *Rows) Scan(bean interface{}) error {
} }
dataStruct := rValue(bean) dataStruct := rValue(bean)
if err := rows.session.Statement.setRefValue(dataStruct); err != nil { if err := rows.session.statement.setRefValue(dataStruct); err != nil {
return err return err
} }
_, err := rows.session.row2Bean(rows.rows, rows.fields, len(rows.fields), bean, &dataStruct, rows.session.Statement.RefTable)
return err scanResults, err := rows.session.row2Slice(rows.rows, rows.fields, bean)
if err != nil {
return err
}
_, err = rows.session.slice2Bean(scanResults, rows.fields, bean, &dataStruct, rows.session.statement.RefTable)
if err != nil {
return err
}
return rows.session.executeProcessors()
} }
// Close session if session.IsAutoClose is true, and claimed any opened resources // Close session if session.IsAutoClose is true, and claimed any opened resources
func (rows *Rows) Close() error { func (rows *Rows) Close() error {
if rows.session.IsAutoClose { if rows.session.isAutoClose {
defer rows.session.Close() defer rows.session.Close()
} }
@ -134,17 +122,10 @@ func (rows *Rows) Close() error {
if rows.rows != nil { if rows.rows != nil {
rows.lastError = rows.rows.Close() rows.lastError = rows.rows.Close()
if rows.lastError != nil { if rows.lastError != nil {
defer rows.stmt.Close()
return rows.lastError return rows.lastError
} }
} }
if rows.stmt != nil {
rows.lastError = rows.stmt.Close()
}
} else { } else {
if rows.stmt != nil {
defer rows.stmt.Close()
}
if rows.rows != nil { if rows.rows != nil {
defer rows.rows.Close() defer rows.rows.Close()
} }

216
vendor/github.com/go-xorm/xorm/session.go generated vendored

@ -21,16 +21,16 @@ import (
// kind of database operations. // kind of database operations.
type Session struct { type Session struct {
db *core.DB db *core.DB
Engine *Engine engine *Engine
Tx *core.Tx tx *core.Tx
Statement Statement statement Statement
IsAutoCommit bool isAutoCommit bool
IsCommitedOrRollbacked bool isCommitedOrRollbacked bool
IsAutoClose bool isAutoClose bool
// Automatically reset the statement after operations that execute a SQL // Automatically reset the statement after operations that execute a SQL
// query such as Count(), Find(), Get(), ... // query such as Count(), Find(), Get(), ...
AutoResetStatement bool autoResetStatement bool
// !nashtsai! storing these beans due to yet committed tx // !nashtsai! storing these beans due to yet committed tx
afterInsertBeans map[interface{}]*[]func(interface{}) afterInsertBeans map[interface{}]*[]func(interface{})
@ -41,6 +41,8 @@ type Session struct {
beforeClosures []func(interface{}) beforeClosures []func(interface{})
afterClosures []func(interface{}) afterClosures []func(interface{})
afterProcessors []executedProcessor
prepareStmt bool prepareStmt bool
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
@ -48,6 +50,8 @@ type Session struct {
//beforeSQLExec func(string, ...interface{}) //beforeSQLExec func(string, ...interface{})
lastSQL string lastSQL string
lastSQLArgs []interface{} lastSQLArgs []interface{}
err error
} }
// Clone copy all the session's content and return a new session // Clone copy all the session's content and return a new session
@ -58,12 +62,12 @@ func (session *Session) Clone() *Session {
// Init reset the session as the init status. // Init reset the session as the init status.
func (session *Session) Init() { func (session *Session) Init() {
session.Statement.Init() session.statement.Init()
session.Statement.Engine = session.Engine session.statement.Engine = session.engine
session.IsAutoCommit = true session.isAutoCommit = true
session.IsCommitedOrRollbacked = false session.isCommitedOrRollbacked = false
session.IsAutoClose = false session.isAutoClose = false
session.AutoResetStatement = true session.autoResetStatement = true
session.prepareStmt = false session.prepareStmt = false
// !nashtsai! is lazy init better? // !nashtsai! is lazy init better?
@ -72,6 +76,9 @@ func (session *Session) Init() {
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0) session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
session.beforeClosures = make([]func(interface{}), 0) session.beforeClosures = make([]func(interface{}), 0)
session.afterClosures = make([]func(interface{}), 0) session.afterClosures = make([]func(interface{}), 0)
session.stmtCache = make(map[uint32]*core.Stmt)
session.afterProcessors = make([]executedProcessor, 0)
session.lastSQL = "" session.lastSQL = ""
session.lastSQLArgs = []interface{}{} session.lastSQLArgs = []interface{}{}
@ -86,19 +93,23 @@ func (session *Session) Close() {
if session.db != nil { if session.db != nil {
// 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.
if session.Tx != nil && !session.IsCommitedOrRollbacked { if session.tx != nil && !session.isCommitedOrRollbacked {
session.Rollback() session.Rollback()
} }
session.Tx = nil session.tx = nil
session.stmtCache = nil session.stmtCache = nil
session.Init()
session.db = nil session.db = nil
} }
} }
// IsClosed returns if session is closed
func (session *Session) IsClosed() bool {
return session.db == nil
}
func (session *Session) resetStatement() { func (session *Session) resetStatement() {
if session.AutoResetStatement { if session.autoResetStatement {
session.Statement.Init() session.statement.Init()
} }
} }
@ -126,75 +137,75 @@ func (session *Session) After(closures func(interface{})) *Session {
// Table can input a string or pointer to struct for special a table to operate. // Table can input a string or pointer to struct for special a table to operate.
func (session *Session) Table(tableNameOrBean interface{}) *Session { func (session *Session) Table(tableNameOrBean interface{}) *Session {
session.Statement.Table(tableNameOrBean) session.statement.Table(tableNameOrBean)
return session return session
} }
// Alias set the table alias // Alias set the table alias
func (session *Session) Alias(alias string) *Session { func (session *Session) Alias(alias string) *Session {
session.Statement.Alias(alias) session.statement.Alias(alias)
return session return session
} }
// NoCascade indicate that no cascade load child object // NoCascade indicate that no cascade load child object
func (session *Session) NoCascade() *Session { func (session *Session) NoCascade() *Session {
session.Statement.UseCascade = false session.statement.UseCascade = false
return session return session
} }
// ForUpdate Set Read/Write locking for UPDATE // ForUpdate Set Read/Write locking for UPDATE
func (session *Session) ForUpdate() *Session { func (session *Session) ForUpdate() *Session {
session.Statement.IsForUpdate = true session.statement.IsForUpdate = true
return session return session
} }
// NoAutoCondition disable generate SQL condition from beans // NoAutoCondition disable generate SQL condition from beans
func (session *Session) NoAutoCondition(no ...bool) *Session { func (session *Session) NoAutoCondition(no ...bool) *Session {
session.Statement.NoAutoCondition(no...) session.statement.NoAutoCondition(no...)
return session return session
} }
// Limit provide limit and offset query condition // Limit provide limit and offset query condition
func (session *Session) Limit(limit int, start ...int) *Session { func (session *Session) Limit(limit int, start ...int) *Session {
session.Statement.Limit(limit, start...) session.statement.Limit(limit, start...)
return session return session
} }
// OrderBy provide order by query condition, the input parameter is the content // OrderBy provide order by query condition, the input parameter is the content
// after order by on a sql statement. // after order by on a sql statement.
func (session *Session) OrderBy(order string) *Session { func (session *Session) OrderBy(order string) *Session {
session.Statement.OrderBy(order) session.statement.OrderBy(order)
return session return session
} }
// Desc provide desc order by query condition, the input parameters are columns. // Desc provide desc order by query condition, the input parameters are columns.
func (session *Session) Desc(colNames ...string) *Session { func (session *Session) Desc(colNames ...string) *Session {
session.Statement.Desc(colNames...) session.statement.Desc(colNames...)
return session return session
} }
// Asc provide asc order by query condition, the input parameters are columns. // Asc provide asc order by query condition, the input parameters are columns.
func (session *Session) Asc(colNames ...string) *Session { func (session *Session) Asc(colNames ...string) *Session {
session.Statement.Asc(colNames...) session.statement.Asc(colNames...)
return session return session
} }
// StoreEngine is only avialble mysql dialect currently // StoreEngine is only avialble mysql dialect currently
func (session *Session) StoreEngine(storeEngine string) *Session { func (session *Session) StoreEngine(storeEngine string) *Session {
session.Statement.StoreEngine = storeEngine session.statement.StoreEngine = storeEngine
return session return session
} }
// Charset is only avialble mysql dialect currently // Charset is only avialble mysql dialect currently
func (session *Session) Charset(charset string) *Session { func (session *Session) Charset(charset string) *Session {
session.Statement.Charset = charset session.statement.Charset = charset
return session return session
} }
// Cascade indicates if loading sub Struct // Cascade indicates if loading sub Struct
func (session *Session) Cascade(trueOrFalse ...bool) *Session { func (session *Session) Cascade(trueOrFalse ...bool) *Session {
if len(trueOrFalse) >= 1 { if len(trueOrFalse) >= 1 {
session.Statement.UseCascade = trueOrFalse[0] session.statement.UseCascade = trueOrFalse[0]
} }
return session return session
} }
@ -202,32 +213,32 @@ func (session *Session) Cascade(trueOrFalse ...bool) *Session {
// NoCache ask this session do not retrieve data from cache system and // NoCache ask this session do not retrieve data from cache system and
// get data from database directly. // get data from database directly.
func (session *Session) NoCache() *Session { func (session *Session) NoCache() *Session {
session.Statement.UseCache = false session.statement.UseCache = false
return session return session
} }
// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN // Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
session.Statement.Join(joinOperator, tablename, condition, args...) session.statement.Join(joinOperator, tablename, condition, args...)
return session return session
} }
// GroupBy Generate Group By statement // GroupBy Generate Group By statement
func (session *Session) GroupBy(keys string) *Session { func (session *Session) GroupBy(keys string) *Session {
session.Statement.GroupBy(keys) session.statement.GroupBy(keys)
return session return session
} }
// Having Generate Having statement // Having Generate Having statement
func (session *Session) Having(conditions string) *Session { func (session *Session) Having(conditions string) *Session {
session.Statement.Having(conditions) session.statement.Having(conditions)
return session return session
} }
// DB db return the wrapper of sql.DB // DB db return the wrapper of sql.DB
func (session *Session) DB() *core.DB { func (session *Session) DB() *core.DB {
if session.db == nil { if session.db == nil {
session.db = session.Engine.db session.db = session.engine.db
session.stmtCache = make(map[uint32]*core.Stmt, 0) session.stmtCache = make(map[uint32]*core.Stmt, 0)
} }
return session.db return session.db
@ -240,25 +251,25 @@ func cleanupProcessorsClosures(slices *[]func(interface{})) {
} }
func (session *Session) canCache() bool { func (session *Session) canCache() bool {
if session.Statement.RefTable == nil || if session.statement.RefTable == nil ||
session.Statement.JoinStr != "" || session.statement.JoinStr != "" ||
session.Statement.RawSQL != "" || session.statement.RawSQL != "" ||
!session.Statement.UseCache || !session.statement.UseCache ||
session.Statement.IsForUpdate || session.statement.IsForUpdate ||
session.Tx != nil || session.tx != nil ||
len(session.Statement.selectStr) > 0 { len(session.statement.selectStr) > 0 {
return false return false
} }
return true return true
} }
func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) { func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
crc := crc32.ChecksumIEEE([]byte(sqlStr)) crc := crc32.ChecksumIEEE([]byte(sqlStr))
// TODO try hash(sqlStr+len(sqlStr)) // TODO try hash(sqlStr+len(sqlStr))
var has bool var has bool
stmt, has = session.stmtCache[crc] stmt, has = session.stmtCache[crc]
if !has { if !has {
stmt, err = session.DB().Prepare(sqlStr) stmt, err = db.Prepare(sqlStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -270,18 +281,18 @@ func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) {
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value { func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value {
var col *core.Column var col *core.Column
if col = table.GetColumnIdx(key, idx); col == nil { if col = table.GetColumnIdx(key, idx); col == nil {
//session.Engine.logger.Warnf("table %v has no column %v. %v", table.Name, key, table.ColumnsSeq()) //session.engine.logger.Warnf("table %v has no column %v. %v", table.Name, key, table.ColumnsSeq())
return nil return nil
} }
fieldValue, err := col.ValueOfV(dataStruct) fieldValue, err := col.ValueOfV(dataStruct)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return nil return nil
} }
if !fieldValue.IsValid() || !fieldValue.CanSet() { if !fieldValue.IsValid() || !fieldValue.CanSet() {
session.Engine.logger.Warnf("table %v's column %v is not valid or cannot set", table.Name, key) session.engine.logger.Warnf("table %v's column %v is not valid or cannot set", table.Name, key)
return nil return nil
} }
return fieldValue return fieldValue
@ -290,33 +301,40 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c
// Cell cell is a result of one column field // Cell cell is a result of one column field
type Cell *interface{} type Cell *interface{}
func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount int, func (session *Session) rows2Beans(rows *core.Rows, fields []string,
table *core.Table, newElemFunc func([]string) reflect.Value, table *core.Table, newElemFunc func([]string) reflect.Value,
sliceValueSetFunc func(*reflect.Value, core.PK) error) error { sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
for rows.Next() { for rows.Next() {
var newValue = newElemFunc(fields) var newValue = newElemFunc(fields)
bean := newValue.Interface() bean := newValue.Interface()
dataStruct := rValue(bean) dataStruct := newValue.Elem()
pk, err := session.row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
// handle beforeClosures
scanResults, err := session.row2Slice(rows, fields, bean)
if err != nil { if err != nil {
return err return err
} }
pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
err = sliceValueSetFunc(&newValue, pk)
if err != nil { if err != nil {
return err return err
} }
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(*Session, interface{}) error {
return sliceValueSetFunc(&newValue, pk)
},
session: session,
bean: bean,
})
} }
return nil return nil
} }
func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) { func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) {
// handle beforeClosures
for _, closure := range session.beforeClosures { for _, closure := range session.beforeClosures {
closure(bean) closure(bean)
} }
scanResults := make([]interface{}, fieldsCount) scanResults := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ { for i := 0; i < len(fields); i++ {
var cell interface{} var cell interface{}
scanResults[i] = &cell scanResults[i] = &cell
@ -330,20 +348,52 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
b.BeforeSet(key, Cell(scanResults[ii].(*interface{}))) b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
} }
} }
return scanResults, nil
}
func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
defer func() { defer func() {
if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet { if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
for ii, key := range fields { for ii, key := range fields {
b.AfterSet(key, Cell(scanResults[ii].(*interface{}))) b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
} }
} }
// handle afterClosures
for _, closure := range session.afterClosures {
closure(bean)
}
}() }()
// handle afterClosures
for _, closure := range session.afterClosures {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
closure(bean)
return nil
},
session: session,
bean: bean,
})
}
if a, has := bean.(AfterLoadProcessor); has {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
a.AfterLoad()
return nil
},
session: session,
bean: bean,
})
}
if a, has := bean.(AfterLoadSessionProcessor); has {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
a.AfterLoad(sess)
return nil
},
session: session,
bean: bean,
})
}
var tempMap = make(map[string]int) var tempMap = make(map[string]int)
var pk core.PK var pk core.PK
for ii, key := range fields { for ii, key := range fields {
@ -412,6 +462,10 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
hasAssigned = true hasAssigned = true
if len(bs) > 0 { if len(bs) > 0 {
if fieldType.Kind() == reflect.String {
fieldValue.SetString(string(bs))
continue
}
if fieldValue.CanAddr() { if fieldValue.CanAddr() {
err := json.Unmarshal(bs, fieldValue.Addr().Interface()) err := json.Unmarshal(bs, fieldValue.Addr().Interface())
if err != nil { if err != nil {
@ -519,7 +573,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
} }
case reflect.Struct: case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) { if fieldType.ConvertibleTo(core.TimeType) {
dbTZ := session.Engine.DatabaseTZ dbTZ := session.engine.DatabaseTZ
if col.TimeZone != nil { if col.TimeZone != nil {
dbTZ = col.TimeZone dbTZ = col.TimeZone
} }
@ -532,25 +586,25 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
z, _ := t.Zone() z, _ := t.Zone()
// set new location if database don't save timezone or give an incorrect timezone // set new location if database don't save timezone or give an incorrect timezone
if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
session.Engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
t.Minute(), t.Second(), t.Nanosecond(), dbTZ) t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
} }
t = t.In(session.Engine.TZLocation) t = t.In(session.engine.TZLocation)
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
} else if rawValueType == core.IntType || rawValueType == core.Int64Type || } else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
rawValueType == core.Int32Type { rawValueType == core.Int32Type {
hasAssigned = true hasAssigned = true
t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation) t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
} else { } else {
if d, ok := vv.Interface().([]uint8); ok { if d, ok := vv.Interface().([]uint8); ok {
hasAssigned = true hasAssigned = true
t, err := session.byte2Time(col, d) t, err := session.byte2Time(col, d)
if err != nil { if err != nil {
session.Engine.logger.Error("byte2Time error:", err.Error()) session.engine.logger.Error("byte2Time error:", err.Error())
hasAssigned = false hasAssigned = false
} else { } else {
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
@ -559,20 +613,20 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
hasAssigned = true hasAssigned = true
t, err := session.str2Time(col, d) t, err := session.str2Time(col, d)
if err != nil { if err != nil {
session.Engine.logger.Error("byte2Time error:", err.Error()) session.engine.logger.Error("byte2Time error:", err.Error())
hasAssigned = false hasAssigned = false
} else { } else {
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
} }
} else { } else {
panic(fmt.Sprintf("rawValueType is %v, value is %v", rawValueType, vv.Interface())) return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
} }
} }
} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { } else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString // !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
hasAssigned = true hasAssigned = true
if err := nulVal.Scan(vv.Interface()); err != nil { if err := nulVal.Scan(vv.Interface()); err != nil {
session.Engine.logger.Error("sql.Sanner error:", err.Error()) session.engine.logger.Error("sql.Sanner error:", err.Error())
hasAssigned = false hasAssigned = false
} }
} else if col.SQLType.IsJson() { } else if col.SQLType.IsJson() {
@ -597,15 +651,15 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
fieldValue.Set(x.Elem()) fieldValue.Set(x.Elem())
} }
} }
} else if session.Statement.UseCascade { } else if session.statement.UseCascade {
table, err := session.Engine.autoMapType(*fieldValue) table, err := session.engine.autoMapType(*fieldValue)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hasAssigned = true hasAssigned = true
if len(table.PrimaryKeys) != 1 { if len(table.PrimaryKeys) != 1 {
panic("unsupported non or composited primary key cascade") return nil, errors.New("unsupported non or composited primary key cascade")
} }
var pk = make(core.PK, len(table.PrimaryKeys)) var pk = make(core.PK, len(table.PrimaryKeys))
pk[0], err = asKind(vv, rawValueType) pk[0], err = asKind(vv, rawValueType)
@ -618,9 +672,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily // property to be fetched lazily
structInter := reflect.New(fieldValue.Type()) structInter := reflect.New(fieldValue.Type())
newsession := session.Engine.NewSession() has, err := session.ID(pk).NoCascade().get(structInter.Interface())
defer newsession.Close()
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -764,19 +816,11 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
return pk, nil return pk, nil
} }
func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
for _, filter := range session.Engine.dialect.Filters() {
*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
}
session.saveLastSQL(*sqlStr, paramStr...)
}
// saveLastSQL stores executed query information // saveLastSQL stores executed query information
func (session *Session) saveLastSQL(sql string, args ...interface{}) { func (session *Session) saveLastSQL(sql string, args ...interface{}) {
session.lastSQL = sql session.lastSQL = sql
session.lastSQLArgs = args session.lastSQLArgs = args
session.Engine.logSQL(sql, args...) session.engine.logSQL(sql, args...)
} }
// LastSQL returns last query information // LastSQL returns last query information
@ -786,8 +830,8 @@ func (session *Session) LastSQL() (string, []interface{}) {
// tbName get some table's table name // tbName get some table's table name
func (session *Session) tbNameNoSchema(table *core.Table) string { func (session *Session) tbNameNoSchema(table *core.Table) string {
if len(session.Statement.AltTableName) > 0 { if len(session.statement.AltTableName) > 0 {
return session.Statement.AltTableName return session.statement.AltTableName
} }
return table.Name return table.Name
@ -795,6 +839,6 @@ func (session *Session) tbNameNoSchema(table *core.Table) string {
// Unscoped always disable struct tag "deleted" // Unscoped always disable struct tag "deleted"
func (session *Session) Unscoped() *Session { func (session *Session) Unscoped() *Session {
session.Statement.Unscoped() session.statement.Unscoped()
return session return session
} }

24
vendor/github.com/go-xorm/xorm/session_cols.go generated vendored

@ -6,43 +6,43 @@ package xorm
// Incr provides a query string like "count = count + 1" // Incr provides a query string like "count = count + 1"
func (session *Session) Incr(column string, arg ...interface{}) *Session { func (session *Session) Incr(column string, arg ...interface{}) *Session {
session.Statement.Incr(column, arg...) session.statement.Incr(column, arg...)
return session return session
} }
// Decr provides a query string like "count = count - 1" // Decr provides a query string like "count = count - 1"
func (session *Session) Decr(column string, arg ...interface{}) *Session { func (session *Session) Decr(column string, arg ...interface{}) *Session {
session.Statement.Decr(column, arg...) session.statement.Decr(column, arg...)
return session return session
} }
// SetExpr provides a query string like "column = {expression}" // SetExpr provides a query string like "column = {expression}"
func (session *Session) SetExpr(column string, expression string) *Session { func (session *Session) SetExpr(column string, expression string) *Session {
session.Statement.SetExpr(column, expression) session.statement.SetExpr(column, expression)
return session return session
} }
// Select provides some columns to special // Select provides some columns to special
func (session *Session) Select(str string) *Session { func (session *Session) Select(str string) *Session {
session.Statement.Select(str) session.statement.Select(str)
return session return session
} }
// Cols provides some columns to special // Cols provides some columns to special
func (session *Session) Cols(columns ...string) *Session { func (session *Session) Cols(columns ...string) *Session {
session.Statement.Cols(columns...) session.statement.Cols(columns...)
return session return session
} }
// AllCols ask all columns // AllCols ask all columns
func (session *Session) AllCols() *Session { func (session *Session) AllCols() *Session {
session.Statement.AllCols() session.statement.AllCols()
return session return session
} }
// MustCols specify some columns must use even if they are empty // MustCols specify some columns must use even if they are empty
func (session *Session) MustCols(columns ...string) *Session { func (session *Session) MustCols(columns ...string) *Session {
session.Statement.MustCols(columns...) session.statement.MustCols(columns...)
return session return session
} }
@ -52,7 +52,7 @@ func (session *Session) MustCols(columns ...string) *Session {
// If no parameters, it will use all the bool field of struct, or // If no parameters, it will use all the bool field of struct, or
// it will use parameters's columns // it will use parameters's columns
func (session *Session) UseBool(columns ...string) *Session { func (session *Session) UseBool(columns ...string) *Session {
session.Statement.UseBool(columns...) session.statement.UseBool(columns...)
return session return session
} }
@ -60,25 +60,25 @@ func (session *Session) UseBool(columns ...string) *Session {
// distinct will not be cached because cache system need id, // distinct will not be cached because cache system need id,
// but distinct will not provide id // but distinct will not provide id
func (session *Session) Distinct(columns ...string) *Session { func (session *Session) Distinct(columns ...string) *Session {
session.Statement.Distinct(columns...) session.statement.Distinct(columns...)
return session return session
} }
// Omit Only not use the parameters as select or update columns // Omit Only not use the parameters as select or update columns
func (session *Session) Omit(columns ...string) *Session { func (session *Session) Omit(columns ...string) *Session {
session.Statement.Omit(columns...) session.statement.Omit(columns...)
return session return session
} }
// Nullable Set null when column is zero-value and nullable for update // Nullable Set null when column is zero-value and nullable for update
func (session *Session) Nullable(columns ...string) *Session { func (session *Session) Nullable(columns ...string) *Session {
session.Statement.Nullable(columns...) session.statement.Nullable(columns...)
return session return session
} }
// NoAutoTime means do not automatically give created field and updated field // NoAutoTime means do not automatically give created field and updated field
// the current time on the current session temporarily // the current time on the current session temporarily
func (session *Session) NoAutoTime() *Session { func (session *Session) NoAutoTime() *Session {
session.Statement.UseAutoTime = false session.statement.UseAutoTime = false
return session return session
} }

18
vendor/github.com/go-xorm/xorm/session_cond.go generated vendored

@ -17,25 +17,25 @@ func (session *Session) Sql(query string, args ...interface{}) *Session {
// SQL provides raw sql input parameter. When you have a complex SQL statement // SQL provides raw sql input parameter. When you have a complex SQL statement
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. // and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
func (session *Session) SQL(query interface{}, args ...interface{}) *Session { func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
session.Statement.SQL(query, args...) session.statement.SQL(query, args...)
return session return session
} }
// Where provides custom query condition. // Where provides custom query condition.
func (session *Session) Where(query interface{}, args ...interface{}) *Session { func (session *Session) Where(query interface{}, args ...interface{}) *Session {
session.Statement.Where(query, args...) session.statement.Where(query, args...)
return session return session
} }
// And provides custom query condition. // And provides custom query condition.
func (session *Session) And(query interface{}, args ...interface{}) *Session { func (session *Session) And(query interface{}, args ...interface{}) *Session {
session.Statement.And(query, args...) session.statement.And(query, args...)
return session return session
} }
// Or provides custom query condition. // Or provides custom query condition.
func (session *Session) Or(query interface{}, args ...interface{}) *Session { func (session *Session) Or(query interface{}, args ...interface{}) *Session {
session.Statement.Or(query, args...) session.statement.Or(query, args...)
return session return session
} }
@ -48,23 +48,23 @@ func (session *Session) Id(id interface{}) *Session {
// ID provides converting id as a query condition // ID provides converting id as a query condition
func (session *Session) ID(id interface{}) *Session { func (session *Session) ID(id interface{}) *Session {
session.Statement.ID(id) session.statement.ID(id)
return session return session
} }
// In provides a query string like "id in (1, 2, 3)" // In provides a query string like "id in (1, 2, 3)"
func (session *Session) In(column string, args ...interface{}) *Session { func (session *Session) In(column string, args ...interface{}) *Session {
session.Statement.In(column, args...) session.statement.In(column, args...)
return session return session
} }
// NotIn provides a query string like "id in (1, 2, 3)" // NotIn provides a query string like "id in (1, 2, 3)"
func (session *Session) NotIn(column string, args ...interface{}) *Session { func (session *Session) NotIn(column string, args ...interface{}) *Session {
session.Statement.NotIn(column, args...) session.statement.NotIn(column, args...)
return session return session
} }
// Conds returns session query conditions // Conds returns session query conditions except auto bean conditions
func (session *Session) Conds() builder.Cond { func (session *Session) Conds() builder.Cond {
return session.Statement.cond return session.statement.cond
} }

88
vendor/github.com/go-xorm/xorm/session_convert.go generated vendored

@ -23,39 +23,38 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
var x time.Time var x time.Time
var err error var err error
var parseLoc = session.Engine.DatabaseTZ var parseLoc = session.engine.DatabaseTZ
if col.TimeZone != nil { if col.TimeZone != nil {
parseLoc = col.TimeZone parseLoc = col.TimeZone
} }
if sdata == "0000-00-00 00:00:00" || if sdata == zeroTime0 || sdata == zeroTime1 {
sdata == "0001-01-01 00:00:00" {
} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
// time stamp // time stamp
sd, err := strconv.ParseInt(sdata, 10, 64) sd, err := strconv.ParseInt(sdata, 10, 64)
if err == nil { if err == nil {
x = time.Unix(sd, 0) x = time.Unix(sd, 0)
session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else { } else {
session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
} else if len(sdata) > 19 && strings.Contains(sdata, "-") { } else if len(sdata) > 19 && strings.Contains(sdata, "-") {
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc) x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
if err != nil { if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc) x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
if err != nil { if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc) x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
} else if len(sdata) == 19 && strings.Contains(sdata, "-") { } else if len(sdata) == 19 && strings.Contains(sdata, "-") {
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc) x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc) x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if col.SQLType.Name == core.Time { } else if col.SQLType.Name == core.Time {
if strings.Contains(sdata, " ") { if strings.Contains(sdata, " ") {
ssd := strings.Split(sdata, " ") ssd := strings.Split(sdata, " ")
@ -63,13 +62,13 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
} }
sdata = strings.TrimSpace(sdata) sdata = strings.TrimSpace(sdata)
if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
sdata = sdata[len(sdata)-8:] sdata = sdata[len(sdata)-8:]
} }
st := fmt.Sprintf("2006-01-02 %v", sdata) st := fmt.Sprintf("2006-01-02 %v", sdata)
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc) x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) //session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else { } else {
outErr = fmt.Errorf("unsupported time format %v", sdata) outErr = fmt.Errorf("unsupported time format %v", sdata)
return return
@ -78,7 +77,7 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
return return
} }
outTime = x.In(session.Engine.TZLocation) outTime = x.In(session.engine.TZLocation)
return return
} }
@ -106,7 +105,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if len(data) > 0 { if len(data) > 0 {
err := json.Unmarshal(data, x.Interface()) err := json.Unmarshal(data, x.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return err return err
} }
fieldValue.Set(x.Elem()) fieldValue.Set(x.Elem())
@ -120,7 +119,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if len(data) > 0 { if len(data) > 0 {
err := json.Unmarshal(data, x.Interface()) err := json.Unmarshal(data, x.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return err return err
} }
fieldValue.Set(x.Elem()) fieldValue.Set(x.Elem())
@ -133,7 +132,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if len(data) > 0 { if len(data) > 0 {
err := json.Unmarshal(data, x.Interface()) err := json.Unmarshal(data, x.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return err return err
} }
fieldValue.Set(x.Elem()) fieldValue.Set(x.Elem())
@ -145,8 +144,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
case reflect.String: case reflect.String:
fieldValue.SetString(string(data)) fieldValue.SetString(string(data))
case reflect.Bool: case reflect.Bool:
d := string(data) v, err := asBool(data)
v, err := strconv.ParseBool(d)
if err != nil { if err != nil {
return fmt.Errorf("arg %v as bool: %s", key, err.Error()) return fmt.Errorf("arg %v as bool: %s", key, err.Error())
} }
@ -157,7 +155,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
if len(data) == 1 { if len(data) == 1 {
x = int64(data[0]) x = int64(data[0])
} else { } else {
@ -205,16 +203,17 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
} }
v = x v = x
fieldValue.Set(reflect.ValueOf(v).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
} else if session.Statement.UseCascade { } else if session.statement.UseCascade {
table, err := session.Engine.autoMapType(*fieldValue) table, err := session.engine.autoMapType(*fieldValue)
if err != nil { if err != nil {
return err return err
} }
// TODO: current only support 1 primary key // TODO: current only support 1 primary key
if len(table.PrimaryKeys) > 1 { if len(table.PrimaryKeys) > 1 {
panic("unsupported composited primary key cascade") return errors.New("unsupported composited primary key cascade")
} }
var pk = make(core.PK, len(table.PrimaryKeys)) var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
pk[0], err = str2PK(string(data), rawValueType) pk[0], err = str2PK(string(data), rawValueType)
@ -227,9 +226,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily // property to be fetched lazily
structInter := reflect.New(fieldValue.Type()) structInter := reflect.New(fieldValue.Type())
newsession := session.Engine.NewSession() has, err := session.ID(pk).NoCascade().get(structInter.Interface())
defer newsession.Close()
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil { if err != nil {
return err return err
} }
@ -264,7 +261,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if len(data) > 0 { if len(data) > 0 {
err := json.Unmarshal(data, &x) err := json.Unmarshal(data, &x)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return err return err
} }
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
@ -275,7 +272,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if len(data) > 0 { if len(data) > 0 {
err := json.Unmarshal(data, &x) err := json.Unmarshal(data, &x)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return err return err
} }
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
@ -347,7 +344,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
strings.Contains(session.Engine.DriverName(), "mysql") { strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 { if len(data) == 1 {
x = int64(data[0]) x = int64(data[0])
} else { } else {
@ -372,7 +369,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
strings.Contains(session.Engine.DriverName(), "mysql") { strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 { if len(data) == 1 {
x = int(data[0]) x = int(data[0])
} else { } else {
@ -400,7 +397,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
session.Engine.dialect.DBType() == core.MYSQL { session.engine.dialect.DBType() == core.MYSQL {
if len(data) == 1 { if len(data) == 1 {
x = int32(data[0]) x = int32(data[0])
} else { } else {
@ -428,7 +425,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
strings.Contains(session.Engine.DriverName(), "mysql") { strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 { if len(data) == 1 {
x = int8(data[0]) x = int8(data[0])
} else { } else {
@ -456,7 +453,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit && if col.SQLType.Name == core.Bit &&
strings.Contains(session.Engine.DriverName(), "mysql") { strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 { if len(data) == 1 {
x = int16(data[0]) x = int16(data[0])
} else { } else {
@ -488,16 +485,17 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
v = x v = x
fieldValue.Set(reflect.ValueOf(&x)) fieldValue.Set(reflect.ValueOf(&x))
default: default:
if session.Statement.UseCascade { if session.statement.UseCascade {
structInter := reflect.New(fieldType.Elem()) structInter := reflect.New(fieldType.Elem())
table, err := session.Engine.autoMapType(structInter.Elem()) table, err := session.engine.autoMapType(structInter.Elem())
if err != nil { if err != nil {
return err return err
} }
if len(table.PrimaryKeys) > 1 { if len(table.PrimaryKeys) > 1 {
panic("unsupported composited primary key cascade") return errors.New("unsupported composited primary key cascade")
} }
var pk = make(core.PK, len(table.PrimaryKeys)) var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
pk[0], err = str2PK(string(data), rawValueType) pk[0], err = str2PK(string(data), rawValueType)
@ -509,9 +507,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily // property to be fetched lazily
newsession := session.Engine.NewSession() has, err := session.ID(pk).NoCascade().get(structInter.Interface())
defer newsession.Close()
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil { if err != nil {
return err return err
} }
@ -568,7 +564,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
if fieldValue.IsNil() { if fieldValue.IsNil() {
return nil, nil return nil, nil
} else if !fieldValue.IsValid() { } else if !fieldValue.IsValid() {
session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid") session.engine.logger.Warn("the field[", col.FieldName, "] is invalid")
return nil, nil return nil, nil
} else { } else {
// !nashtsai! deference pointer type to instance type // !nashtsai! deference pointer type to instance type
@ -586,7 +582,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
case reflect.Struct: case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) { if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time) t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
tf := session.Engine.formatColTime(col, t) tf := session.engine.formatColTime(col, t)
return tf, nil return tf, nil
} }
@ -596,7 +592,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
return v.Value() return v.Value()
} }
fieldTable, err := session.Engine.autoMapType(fieldValue) fieldTable, err := session.engine.autoMapType(fieldValue)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -610,14 +606,14 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
if col.SQLType.IsText() { if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface()) bytes, err := json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return 0, err return 0, err
} }
return string(bytes), nil return string(bytes), nil
} else if col.SQLType.IsBlob() { } else if col.SQLType.IsBlob() {
bytes, err := json.Marshal(fieldValue.Interface()) bytes, err := json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return 0, err return 0, err
} }
return bytes, nil return bytes, nil
@ -626,7 +622,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
bytes, err := json.Marshal(fieldValue.Interface()) bytes, err := json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return 0, err return 0, err
} }
return string(bytes), nil return string(bytes), nil
@ -638,7 +634,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
if col.SQLType.IsText() { if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface()) bytes, err := json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return 0, err return 0, err
} }
return string(bytes), nil return string(bytes), nil
@ -651,7 +647,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
} else { } else {
bytes, err = json.Marshal(fieldValue.Interface()) bytes, err = json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
return 0, err return 0, err
} }
} }

76
vendor/github.com/go-xorm/xorm/session_delete.go generated vendored

@ -12,26 +12,26 @@ import (
"github.com/go-xorm/core" "github.com/go-xorm/core"
) )
func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
if session.Statement.RefTable == nil || if table == nil ||
session.Tx != nil { session.tx != nil {
return ErrCacheFailed return ErrCacheFailed
} }
for _, filter := range session.Engine.dialect.Filters() { for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) sqlStr = filter.Do(sqlStr, session.engine.dialect, table)
} }
newsql := session.Statement.convertIDSQL(sqlStr) newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" { if newsql == "" {
return ErrCacheFailed return ErrCacheFailed
} }
cacher := session.Engine.getCacher2(session.Statement.RefTable) cacher := session.engine.getCacher2(table)
tableName := session.Statement.TableName() pkColumns := table.PKColumns()
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil { if err != nil {
resultsSlice, err := session.query(newsql, args...) resultsSlice, err := session.queryBytes(newsql, args...)
if err != nil { if err != nil {
return err return err
} }
@ -40,7 +40,7 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
for _, data := range resultsSlice { for _, data := range resultsSlice {
var id int64 var id int64
var pk core.PK = make([]interface{}, 0) var pk core.PK = make([]interface{}, 0)
for _, col := range session.Statement.RefTable.PKColumns() { for _, col := range pkColumns {
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() {
@ -58,35 +58,30 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
ids = append(ids, pk) ids = append(ids, pk)
} }
} }
} /*else { }
session.Engine.LogDebug("delete cache sql %v", newsql)
cacher.DelIds(tableName, genSqlKey(newsql, args))
}*/
for _, id := range ids { for _, id := range ids {
session.Engine.logger.Debug("[cacheDelete] delete cache obj", tableName, id) session.engine.logger.Debug("[cacheDelete] delete cache obj:", tableName, id)
sid, err := id.ToString() sid, err := id.ToString()
if err != nil { if err != nil {
return err return err
} }
cacher.DelBean(tableName, sid) cacher.DelBean(tableName, sid)
} }
session.Engine.logger.Debug("[cacheDelete] clear cache sql", tableName) session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName)
cacher.ClearIds(tableName) cacher.ClearIds(tableName)
return nil return nil
} }
// Delete records, bean's non-empty fields are conditions // Delete records, bean's non-empty fields are conditions
func (session *Session) Delete(bean interface{}) (int64, error) { func (session *Session) Delete(bean interface{}) (int64, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
if err := session.Statement.setRefValue(rValue(bean)); err != nil { if err := session.statement.setRefValue(rValue(bean)); err != nil {
return 0, err return 0, err
} }
var table = session.Statement.RefTable
// handle before delete processors // handle before delete processors
for _, closure := range session.beforeClosures { for _, closure := range session.beforeClosures {
@ -98,13 +93,17 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
processor.BeforeDelete() processor.BeforeDelete()
} }
// -- condSQL, condArgs, err := session.statement.genConds(bean)
condSQL, condArgs, _ := session.Statement.genConds(bean) if err != nil {
if len(condSQL) == 0 && session.Statement.LimitN == 0 { return 0, err
}
if len(condSQL) == 0 && session.statement.LimitN == 0 {
return 0, ErrNeedDeletedCond return 0, ErrNeedDeletedCond
} }
var tableName = session.Engine.Quote(session.Statement.TableName()) var tableNameNoQuote = session.statement.TableName()
var tableName = session.engine.Quote(tableNameNoQuote)
var table = session.statement.RefTable
var deleteSQL string var deleteSQL string
if len(condSQL) > 0 { if len(condSQL) > 0 {
deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL) deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
@ -113,15 +112,15 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
} }
var orderSQL string var orderSQL string
if len(session.Statement.OrderStr) > 0 { if len(session.statement.OrderStr) > 0 {
orderSQL += fmt.Sprintf(" ORDER BY %s", session.Statement.OrderStr) orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
} }
if session.Statement.LimitN > 0 { if session.statement.LimitN > 0 {
orderSQL += fmt.Sprintf(" LIMIT %d", session.Statement.LimitN) orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN)
} }
if len(orderSQL) > 0 { if len(orderSQL) > 0 {
switch session.Engine.dialect.DBType() { switch session.engine.dialect.DBType() {
case core.POSTGRES: case core.POSTGRES:
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 { if len(condSQL) > 0 {
@ -146,7 +145,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
var realSQL string var realSQL string
argsForCache := make([]interface{}, 0, len(condArgs)*2) argsForCache := make([]interface{}, 0, len(condArgs)*2)
if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
realSQL = deleteSQL realSQL = deleteSQL
copy(argsForCache, condArgs) copy(argsForCache, condArgs)
argsForCache = append(condArgs, argsForCache...) argsForCache = append(condArgs, argsForCache...)
@ -157,12 +156,12 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
deletedColumn := table.DeletedColumn() deletedColumn := table.DeletedColumn()
realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v", realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(session.statement.TableName()),
session.Engine.Quote(deletedColumn.Name), session.engine.Quote(deletedColumn.Name),
condSQL) condSQL)
if len(orderSQL) > 0 { if len(orderSQL) > 0 {
switch session.Engine.dialect.DBType() { switch session.engine.dialect.DBType() {
case core.POSTGRES: case core.POSTGRES:
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 { if len(condSQL) > 0 {
@ -185,12 +184,12 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
} }
} }
// !oinume! Insert NowTime to the head of session.Statement.Params // !oinume! Insert nowTime to the head of session.statement.Params
condArgs = append(condArgs, "") condArgs = append(condArgs, "")
paramsLen := len(condArgs) paramsLen := len(condArgs)
copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1]) copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
val, t := session.Engine.NowTime2(deletedColumn.SQLType.Name) val, t := session.engine.nowTime(deletedColumn)
condArgs[0] = val condArgs[0] = val
var colName = deletedColumn.Name var colName = deletedColumn.Name
@ -200,17 +199,18 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
}) })
} }
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
session.cacheDelete(deleteSQL, argsForCache...) session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
} }
session.statement.RefTable = table
res, err := session.exec(realSQL, condArgs...) res, err := session.exec(realSQL, condArgs...)
if err != nil { if err != nil {
return 0, err return 0, err
} }
// handle after delete processors // handle after delete processors
if session.IsAutoCommit { if session.isAutoCommit {
for _, closure := range session.afterClosures { for _, closure := range session.afterClosures {
closure(bean) closure(bean)
} }

86
vendor/github.com/go-xorm/xorm/session_exist.go generated vendored

@ -0,0 +1,86 @@
// 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 (
"errors"
"fmt"
"reflect"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
// Exist returns true if the record exist otherwise return false
func (session *Session) Exist(bean ...interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
if len(bean) == 0 {
tableName := session.statement.TableName()
if len(tableName) <= 0 {
return false, ErrTableNotFound
}
if session.statement.cond.IsValid() {
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil {
return false, err
}
if session.engine.dialect.DBType() == core.MSSQL {
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s WHERE %s", tableName, condSQL)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
}
args = condArgs
} else {
if session.engine.dialect.DBType() == core.MSSQL {
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s", tableName)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
}
args = []interface{}{}
}
} else {
beanValue := reflect.ValueOf(bean[0])
if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer")
}
if beanValue.Elem().Kind() == reflect.Struct {
if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
return false, err
}
}
if len(session.statement.TableName()) <= 0 {
return false, ErrTableNotFound
}
session.statement.Limit(1)
sqlStr, args, err = session.statement.genGetSQL(bean[0])
if err != nil {
return false, err
}
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return false, err
}
defer rows.Close()
return rows.Next(), nil
}

207
vendor/github.com/go-xorm/xorm/session_find.go generated vendored

@ -8,7 +8,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv"
"strings" "strings"
"github.com/go-xorm/builder" "github.com/go-xorm/builder"
@ -24,11 +23,43 @@ const (
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct // map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
return session.find(rowsSlicePtr, condiBean...)
}
// FindAndCount find the results and also return the counts
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
session.autoResetStatement = false
err := session.find(rowsSlicePtr, condiBean...)
if err != nil {
return 0, err
}
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
return 0, errors.New("needs a pointer to a slice or a map")
}
sliceElementType := sliceValue.Type().Elem()
if sliceElementType.Kind() == reflect.Ptr {
sliceElementType = sliceElementType.Elem()
}
session.autoResetStatement = true
if session.statement.selectStr != "" {
session.statement.selectStr = ""
}
return session.Count(reflect.New(sliceElementType).Interface())
}
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
return errors.New("needs a pointer to a slice or a map") return errors.New("needs a pointer to a slice or a map")
@ -37,11 +68,11 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
sliceElementType := sliceValue.Type().Elem() sliceElementType := sliceValue.Type().Elem()
var tp = tpStruct var tp = tpStruct
if session.Statement.RefTable == nil { if session.statement.RefTable == nil {
if sliceElementType.Kind() == reflect.Ptr { if sliceElementType.Kind() == reflect.Ptr {
if sliceElementType.Elem().Kind() == reflect.Struct { if sliceElementType.Elem().Kind() == reflect.Struct {
pv := reflect.New(sliceElementType.Elem()) pv := reflect.New(sliceElementType.Elem())
if err := session.Statement.setRefValue(pv.Elem()); err != nil { if err := session.statement.setRefValue(pv.Elem()); err != nil {
return err return err
} }
} else { } else {
@ -49,7 +80,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
} }
} else if sliceElementType.Kind() == reflect.Struct { } else if sliceElementType.Kind() == reflect.Struct {
pv := reflect.New(sliceElementType) pv := reflect.New(sliceElementType)
if err := session.Statement.setRefValue(pv.Elem()); err != nil { if err := session.statement.setRefValue(pv.Elem()); err != nil {
return err return err
} }
} else { } else {
@ -57,61 +88,59 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
} }
} }
var table = session.Statement.RefTable var table = session.statement.RefTable
var addedTableName = (len(session.Statement.JoinStr) > 0) var addedTableName = (len(session.statement.JoinStr) > 0)
var autoCond builder.Cond var autoCond builder.Cond
if tp == tpStruct { if tp == tpStruct {
if !session.Statement.noAutoCondition && len(condiBean) > 0 { if !session.statement.noAutoCondition && len(condiBean) > 0 {
var err error var err error
autoCond, err = session.Statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName) autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
if err != nil { if err != nil {
panic(err) return err
} }
} else { } else {
// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given. // !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
// See https://github.com/go-xorm/xorm/issues/179 // See https://github.com/go-xorm/xorm/issues/179
if col := table.DeletedColumn(); col != nil && !session.Statement.unscoped { // tag "deleted" is enabled if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
var colName = session.Engine.Quote(col.Name) var colName = session.engine.Quote(col.Name)
if addedTableName { if addedTableName {
var nm = session.Statement.TableName() var nm = session.statement.TableName()
if len(session.Statement.TableAlias) > 0 { if len(session.statement.TableAlias) > 0 {
nm = session.Statement.TableAlias nm = session.statement.TableAlias
} }
colName = session.Engine.Quote(nm) + "." + colName colName = session.engine.Quote(nm) + "." + colName
}
if session.Engine.dialect.DBType() == core.MSSQL {
autoCond = builder.IsNull{colName}
} else {
autoCond = builder.IsNull{colName}.Or(builder.Eq{colName: "0001-01-01 00:00:00"})
} }
autoCond = session.engine.CondDeleted(colName)
} }
} }
} }
var sqlStr string var sqlStr string
var args []interface{} var args []interface{}
if session.Statement.RawSQL == "" { var err error
if len(session.Statement.TableName()) <= 0 { if session.statement.RawSQL == "" {
if len(session.statement.TableName()) <= 0 {
return ErrTableNotFound return ErrTableNotFound
} }
var columnStr = session.Statement.ColumnStr var columnStr = session.statement.ColumnStr
if len(session.Statement.selectStr) > 0 { if len(session.statement.selectStr) > 0 {
columnStr = session.Statement.selectStr columnStr = session.statement.selectStr
} else { } else {
if session.Statement.JoinStr == "" { if session.statement.JoinStr == "" {
if columnStr == "" { if columnStr == "" {
if session.Statement.GroupByStr != "" { if session.statement.GroupByStr != "" {
columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1)) columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else { } else {
columnStr = session.Statement.genColumnStr() columnStr = session.statement.genColumnStr()
} }
} }
} else { } else {
if columnStr == "" { if columnStr == "" {
if session.Statement.GroupByStr != "" { if session.statement.GroupByStr != "" {
columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1)) columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else { } else {
columnStr = "*" columnStr = "*"
} }
@ -122,34 +151,37 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
} }
} }
condSQL, condArgs, err := builder.ToSQL(session.Statement.cond.And(autoCond)) session.statement.cond = session.statement.cond.And(autoCond)
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil { if err != nil {
return err return err
} }
args = append(session.Statement.joinArgs, condArgs...) args = append(session.statement.joinArgs, condArgs...)
sqlStr = session.Statement.genSelectSQL(columnStr, condSQL) sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true)
if err != nil {
return err
}
// for mssql and use limit // for mssql and use limit
qs := strings.Count(sqlStr, "?") qs := strings.Count(sqlStr, "?")
if len(args)*2 == qs { if len(args)*2 == qs {
args = append(args, args...) args = append(args, args...)
} }
} else { } else {
sqlStr = session.Statement.RawSQL sqlStr = session.statement.RawSQL
args = session.Statement.RawParams args = session.statement.RawParams
} }
var err error
if session.canCache() { if session.canCache() {
if cacher := session.Engine.getCacher2(table); cacher != nil && if cacher := session.engine.getCacher2(table); cacher != nil &&
!session.Statement.IsDistinct && !session.statement.IsDistinct &&
!session.Statement.unscoped { !session.statement.unscoped {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...) err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
if err != ErrCacheFailed { if err != ErrCacheFailed {
return err return err
} }
err = nil // !nashtsai! reset err to nil for ErrCacheFailed err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.Engine.logger.Warn("Cache Find Failed") session.engine.logger.Warn("Cache Find Failed")
} }
} }
@ -157,21 +189,13 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
} }
func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
var rawRows *core.Rows rows, err := session.queryRows(sqlStr, args...)
var err error
session.queryPreprocess(&sqlStr, args...)
if session.IsAutoCommit {
_, rawRows, err = session.innerQuery(sqlStr, args...)
} else {
rawRows, err = session.Tx.Query(sqlStr, args...)
}
if err != nil { if err != nil {
return err return err
} }
defer rawRows.Close() defer rows.Close()
fields, err := rawRows.Columns() fields, err := rows.Columns()
if err != nil { if err != nil {
return err return err
} }
@ -241,24 +265,29 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
if elemType.Kind() == reflect.Struct { if elemType.Kind() == reflect.Struct {
var newValue = newElemFunc(fields) var newValue = newElemFunc(fields)
dataStruct := rValue(newValue.Interface()) dataStruct := rValue(newValue.Interface())
tb, err := session.Engine.autoMapType(dataStruct) tb, err := session.engine.autoMapType(dataStruct)
if err != nil { if err != nil {
return err return err
} }
return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc) err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
rows.Close()
if err != nil {
return err
}
return session.executeProcessors()
} }
for rawRows.Next() { for rows.Next() {
var newValue = newElemFunc(fields) var newValue = newElemFunc(fields)
bean := newValue.Interface() bean := newValue.Interface()
switch elemType.Kind() { switch elemType.Kind() {
case reflect.Slice: case reflect.Slice:
err = rawRows.ScanSlice(bean) err = rows.ScanSlice(bean)
case reflect.Map: case reflect.Map:
err = rawRows.ScanMap(bean) err = rows.ScanMap(bean)
default: default:
err = rawRows.Scan(bean) err = rows.Scan(bean)
} }
if err != nil { if err != nil {
@ -289,22 +318,21 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
return ErrCacheFailed return ErrCacheFailed
} }
for _, filter := range session.Engine.dialect.Filters() { for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
} }
newsql := session.Statement.convertIDSQL(sqlStr) newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" { if newsql == "" {
return ErrCacheFailed return ErrCacheFailed
} }
tableName := session.Statement.TableName() tableName := session.statement.TableName()
table := session.statement.RefTable
table := session.Statement.RefTable cacher := session.engine.getCacher2(table)
cacher := session.Engine.getCacher2(table)
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil { if err != nil {
rows, err := session.DB().Query(newsql, args...) rows, err := session.queryRows(newsql, args...)
if err != nil { if err != nil {
return err return err
} }
@ -315,7 +343,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
for rows.Next() { for rows.Next() {
i++ i++
if i > 500 { if i > 500 {
session.Engine.logger.Debug("[cacheFind] ids length > 500, no cache") session.engine.logger.Debug("[cacheFind] ids length > 500, no cache")
return ErrCacheFailed return ErrCacheFailed
} }
var res = make([]string, len(table.PrimaryKeys)) var res = make([]string, len(table.PrimaryKeys))
@ -323,32 +351,24 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
if err != nil { if err != nil {
return err return err
} }
var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() { for i, col := range table.PKColumns() {
if col.SQLType.IsNumeric() { pk[i], err = session.engine.idTypeAssertion(col, res[i])
n, err := strconv.ParseInt(res[i], 10, 64) if err != nil {
if err != nil { return err
return err
}
pk[i] = n
} else if col.SQLType.IsText() {
pk[i] = res[i]
} else {
return errors.New("not supported")
} }
} }
ids = append(ids, pk) ids = append(ids, pk)
} }
session.Engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, newsql, args) session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args) err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
session.Engine.logger.Debug("[cacheFind] cache hit sql:", newsql, args) session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, newsql, args)
} }
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
@ -363,20 +383,20 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
return err return err
} }
bean := cacher.GetBean(tableName, sid) bean := cacher.GetBean(tableName, sid)
if bean == nil { if bean == nil || reflect.ValueOf(bean).Elem().Type() != t {
ides = append(ides, id) ides = append(ides, id)
ididxes[sid] = idx ididxes[sid] = idx
} else { } else {
session.Engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean) session.engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean)
pk := session.Engine.IdOf(bean) pk := session.engine.IdOf(bean)
xid, err := pk.ToString() xid, err := pk.ToString()
if err != nil { if err != nil {
return err return err
} }
if sid != xid { if sid != xid {
session.Engine.logger.Error("[cacheFind] error cache", xid, sid, bean) session.engine.logger.Error("[cacheFind] error cache", xid, sid, bean)
return ErrCacheFailed return ErrCacheFailed
} }
temps[idx] = bean temps[idx] = bean
@ -384,9 +404,6 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
} }
if len(ides) > 0 { if len(ides) > 0 {
newSession := session.Engine.NewSession()
defer newSession.Close()
slices := reflect.New(reflect.SliceOf(t)) slices := reflect.New(reflect.SliceOf(t))
beans := slices.Interface() beans := slices.Interface()
@ -396,18 +413,18 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
ff = append(ff, ie[0]) ff = append(ff, ie[0])
} }
newSession.In("`"+table.PrimaryKeys[0]+"`", ff...) session.In("`"+table.PrimaryKeys[0]+"`", ff...)
} else { } else {
for _, ie := range ides { for _, ie := range ides {
cond := builder.NewCond() cond := builder.NewCond()
for i, name := range table.PrimaryKeys { for i, name := range table.PrimaryKeys {
cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
} }
newSession.Or(cond) session.Or(cond)
} }
} }
err = newSession.NoCache().Find(beans) err = session.NoCache().Table(tableName).find(beans)
if err != nil { if err != nil {
return err return err
} }
@ -418,7 +435,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
if rv.Kind() != reflect.Ptr { if rv.Kind() != reflect.Ptr {
rv = rv.Addr() rv = rv.Addr()
} }
id, err := session.Engine.idOfV(rv) id, err := session.engine.idOfV(rv)
if err != nil { if err != nil {
return err return err
} }
@ -429,7 +446,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
bean := rv.Interface() bean := rv.Interface()
temps[ididxes[sid]] = bean temps[ididxes[sid]] = bean
session.Engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps) session.engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps)
cacher.PutBean(tableName, sid, bean) cacher.PutBean(tableName, sid, bean)
} }
} }
@ -437,7 +454,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
for j := 0; j < len(temps); j++ { for j := 0; j < len(temps); j++ {
bean := temps[j] bean := temps[j]
if bean == nil { if bean == nil {
session.Engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps) session.engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps)
// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
continue continue
} }

138
vendor/github.com/go-xorm/xorm/session_get.go generated vendored

@ -5,6 +5,7 @@
package xorm package xorm
import ( import (
"database/sql"
"errors" "errors"
"reflect" "reflect"
"strconv" "strconv"
@ -15,39 +16,49 @@ import (
// 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(bean interface{}) (bool, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
return session.get(bean)
}
func (session *Session) get(bean interface{}) (bool, error) {
beanValue := reflect.ValueOf(bean) beanValue := reflect.ValueOf(bean)
if beanValue.Kind() != reflect.Ptr { if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer") return false, errors.New("needs a pointer to a value")
} else if beanValue.Elem().Kind() == reflect.Ptr {
return false, errors.New("a pointer to a pointer is not allowed")
} }
if beanValue.Elem().Kind() == reflect.Struct { if beanValue.Elem().Kind() == reflect.Struct {
if err := session.Statement.setRefValue(beanValue.Elem()); err != nil { if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
return false, err return false, err
} }
} }
var sqlStr string var sqlStr string
var args []interface{} var args []interface{}
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 = session.Statement.genGetSQL(bean) sqlStr, args, err = session.statement.genGetSQL(bean)
if err != nil {
return false, err
}
} else { } else {
sqlStr = session.Statement.RawSQL sqlStr = session.statement.RawSQL
args = session.Statement.RawParams args = session.statement.RawParams
} }
table := session.statement.RefTable
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct { if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && if cacher := session.engine.getCacher2(table); cacher != nil &&
!session.Statement.unscoped { !session.statement.unscoped {
has, err := session.cacheGet(bean, sqlStr, args...) has, err := session.cacheGet(bean, sqlStr, args...)
if err != ErrCacheFailed { if err != ErrCacheFailed {
return has, err return has, err
@ -55,49 +66,58 @@ func (session *Session) Get(bean interface{}) (bool, error) {
} }
} }
return session.nocacheGet(beanValue.Elem().Kind(), bean, sqlStr, args...) return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
} }
func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) { func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
session.queryPreprocess(&sqlStr, args...) rows, err := session.queryRows(sqlStr, args...)
var rawRows *core.Rows
var err error
if session.IsAutoCommit {
_, rawRows, err = session.innerQuery(sqlStr, args...)
} else {
rawRows, err = session.Tx.Query(sqlStr, args...)
}
if err != nil { if err != nil {
return false, err return false, err
} }
defer rows.Close()
defer rawRows.Close() if !rows.Next() {
return false, nil
}
if rawRows.Next() { switch bean.(type) {
switch beanKind { case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
case reflect.Struct: return true, rows.Scan(&bean)
fields, err := rawRows.Columns() case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
if err != nil { return true, rows.Scan(bean)
// WARN: Alougth rawRows return true, but get fields failed }
return true, err
} switch beanKind {
dataStruct := rValue(bean) case reflect.Struct:
if err := session.Statement.setRefValue(dataStruct); err != nil { fields, err := rows.Columns()
return false, err if err != nil {
} // WARN: Alougth rows return true, but get fields failed
_, err = session.row2Bean(rawRows, fields, len(fields), bean, &dataStruct, session.Statement.RefTable) return true, err
case reflect.Slice:
err = rawRows.ScanSlice(bean)
case reflect.Map:
err = rawRows.ScanMap(bean)
default:
err = rawRows.Scan(bean)
} }
return true, err scanResults, err := session.row2Slice(rows, fields, bean)
if err != nil {
return false, err
}
// close it before covert data
rows.Close()
dataStruct := rValue(bean)
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
if err != nil {
return true, err
}
return true, session.executeProcessors()
case reflect.Slice:
err = rows.ScanSlice(bean)
case reflect.Map:
err = rows.ScanMap(bean)
default:
err = rows.Scan(bean)
} }
return false, nil
return true, err
} }
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) {
@ -106,22 +126,22 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
return false, ErrCacheFailed return false, ErrCacheFailed
} }
for _, filter := range session.Engine.dialect.Filters() { for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
} }
newsql := session.Statement.convertIDSQL(sqlStr) newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" { if newsql == "" {
return false, ErrCacheFailed return false, ErrCacheFailed
} }
cacher := session.Engine.getCacher2(session.Statement.RefTable) cacher := session.engine.getCacher2(session.statement.RefTable)
tableName := session.Statement.TableName() tableName := session.statement.TableName()
session.Engine.logger.Debug("[cacheGet] find sql:", newsql, args) session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
table := session.statement.RefTable
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
table := session.Statement.RefTable
if err != nil { if err != nil {
var res = make([]string, len(table.PrimaryKeys)) var res = make([]string, len(table.PrimaryKeys))
rows, err := session.DB().Query(newsql, args...) rows, err := session.NoCache().queryRows(newsql, args...)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -152,19 +172,19 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
} }
ids = []core.PK{pk} ids = []core.PK{pk}
session.Engine.logger.Debug("[cacheGet] cache ids:", newsql, ids) session.engine.logger.Debug("[cacheGet] cache ids:", newsql, ids)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args) err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil { if err != nil {
return false, err return false, err
} }
} else { } else {
session.Engine.logger.Debug("[cacheGet] cache hit sql:", newsql) session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql, ids)
} }
if len(ids) > 0 { if len(ids) > 0 {
structValue := reflect.Indirect(reflect.ValueOf(bean)) structValue := reflect.Indirect(reflect.ValueOf(bean))
id := ids[0] id := ids[0]
session.Engine.logger.Debug("[cacheGet] get bean:", tableName, id) session.engine.logger.Debug("[cacheGet] get bean:", tableName, id)
sid, err := id.ToString() sid, err := id.ToString()
if err != nil { if err != nil {
return false, err return false, err
@ -172,15 +192,15 @@ 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, cacheBean, sqlStr, args...) has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...)
if err != nil || !has { if err != nil || !has {
return has, err return has, err
} }
session.Engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean) session.engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean)
cacher.PutBean(tableName, sid, cacheBean) cacher.PutBean(tableName, sid, cacheBean)
} else { } else {
session.Engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean) session.engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean)
has = true has = true
} }
structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean))) structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean)))

159
vendor/github.com/go-xorm/xorm/session_insert.go generated vendored

@ -19,17 +19,16 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
var affected int64 var affected int64
var err error var err error
if session.IsAutoClose { if session.isAutoClose {
defer session.Close() defer session.Close()
} }
defer session.resetStatement()
for _, bean := range beans { for _, bean := range beans {
sliceValue := reflect.Indirect(reflect.ValueOf(bean)) sliceValue := reflect.Indirect(reflect.ValueOf(bean))
if sliceValue.Kind() == reflect.Slice { if sliceValue.Kind() == reflect.Slice {
size := sliceValue.Len() size := sliceValue.Len()
if size > 0 { if size > 0 {
if session.Engine.SupportInsertMany() { if session.engine.SupportInsertMany() {
cnt, err := session.innerInsertMulti(bean) cnt, err := session.innerInsertMulti(bean)
if err != nil { if err != nil {
return affected, err return affected, err
@ -67,15 +66,15 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
return 0, errors.New("could not insert a empty slice") return 0, errors.New("could not insert a empty slice")
} }
if err := session.Statement.setRefValue(reflect.ValueOf(sliceValue.Index(0).Interface())); err != nil { if err := session.statement.setRefValue(reflect.ValueOf(sliceValue.Index(0).Interface())); 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
} }
table := session.Statement.RefTable table := session.statement.RefTable
size := sliceValue.Len() size := sliceValue.Len()
var colNames []string var colNames []string
@ -116,18 +115,18 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
if col.IsDeleted { if col.IsDeleted {
continue continue
} }
if session.Statement.ColumnStr != "" { if session.statement.ColumnStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
continue continue
} }
} }
if session.Statement.OmitStr != "" { if session.statement.OmitStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
continue continue
} }
} }
if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime { if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t := session.Engine.NowTime2(col.SQLType.Name) val, t := session.engine.nowTime(col)
args = append(args, val) args = append(args, val)
var colName = col.Name var colName = col.Name
@ -135,7 +134,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
col := table.GetColumn(colName) col := table.GetColumn(colName)
setColumnTime(bean, col, t) setColumnTime(bean, col, t)
}) })
} else if col.IsVersion && session.Statement.checkVersion { } else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1) args = append(args, 1)
var colName = col.Name var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) { session.afterClosures = append(session.afterClosures, func(bean interface{}) {
@ -171,18 +170,18 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
if col.IsDeleted { if col.IsDeleted {
continue continue
} }
if session.Statement.ColumnStr != "" { if session.statement.ColumnStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
continue continue
} }
} }
if session.Statement.OmitStr != "" { if session.statement.OmitStr != "" {
if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok { if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
continue continue
} }
} }
if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime { if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t := session.Engine.NowTime2(col.SQLType.Name) val, t := session.engine.nowTime(col)
args = append(args, val) args = append(args, val)
var colName = col.Name var colName = col.Name
@ -190,7 +189,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
col := table.GetColumn(colName) col := table.GetColumn(colName)
setColumnTime(bean, col, t) setColumnTime(bean, col, t)
}) })
} else if col.IsVersion && session.Statement.checkVersion { } else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1) args = append(args, 1)
var colName = col.Name var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) { session.afterClosures = append(session.afterClosures, func(bean interface{}) {
@ -214,25 +213,26 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)" var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
var statement string var statement string
if session.Engine.dialect.DBType() == core.ORACLE { var tableName = session.statement.TableName()
if session.engine.dialect.DBType() == core.ORACLE {
sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL" sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (", temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(tableName),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.Engine.QuoteStr()) session.engine.QuoteStr())
statement = fmt.Sprintf(sql, statement = fmt.Sprintf(sql,
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(tableName),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colMultiPlaces, temp)) strings.Join(colMultiPlaces, temp))
} else { } else {
statement = fmt.Sprintf(sql, statement = fmt.Sprintf(sql,
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(tableName),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colMultiPlaces, "),(")) strings.Join(colMultiPlaces, "),("))
} }
res, err := session.exec(statement, args...) res, err := session.exec(statement, args...)
@ -240,8 +240,8 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
return 0, err return 0, err
} }
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(table, tableName)
} }
lenAfterClosures := len(session.afterClosures) lenAfterClosures := len(session.afterClosures)
@ -249,7 +249,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface() elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface()
// handle AfterInsertProcessor // handle AfterInsertProcessor
if session.IsAutoCommit { if session.isAutoCommit {
// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi?? // !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
for _, closure := range session.afterClosures { for _, closure := range session.afterClosures {
closure(elemValue) closure(elemValue)
@ -280,8 +280,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
// InsertMulti insert multiple records // InsertMulti insert multiple records
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
@ -299,14 +298,14 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
} }
func (session *Session) innerInsert(bean interface{}) (int64, error) { func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err := session.Statement.setRefValue(rValue(bean)); err != nil { if err := session.statement.setRefValue(rValue(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
} }
table := session.Statement.RefTable table := session.statement.RefTable
// handle BeforeInsertProcessor // handle BeforeInsertProcessor
for _, closure := range session.beforeClosures { for _, closure := range session.beforeClosures {
@ -318,12 +317,12 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
processor.BeforeInsert() processor.BeforeInsert()
} }
// -- // --
colNames, args, err := genCols(session.Statement.RefTable, session, bean, false, false) colNames, args, err := genCols(session.statement.RefTable, session, bean, false, false)
if err != nil { if err != nil {
return 0, err return 0, err
} }
// insert expr columns, override if exists // insert expr columns, override if exists
exprColumns := session.Statement.getExpr() exprColumns := session.statement.getExpr()
exprColVals := make([]string, 0, len(exprColumns)) exprColVals := make([]string, 0, len(exprColumns))
for _, v := range exprColumns { for _, v := range exprColumns {
// remove the expr columns // remove the expr columns
@ -349,23 +348,24 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
} }
var sqlStr string var sqlStr string
var tableName = session.statement.TableName()
if len(colPlaces) > 0 { if len(colPlaces) > 0 {
sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(tableName),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
strings.Join(colNames, session.Engine.Quote(", ")), strings.Join(colNames, session.engine.Quote(", ")),
session.Engine.QuoteStr(), session.engine.QuoteStr(),
colPlaces) colPlaces)
} else { } else {
if session.Engine.dialect.DBType() == core.MYSQL { if session.engine.dialect.DBType() == core.MYSQL {
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.Engine.Quote(session.Statement.TableName())) sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName))
} else { } else {
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.Engine.Quote(session.Statement.TableName())) sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.engine.Quote(tableName))
} }
} }
handleAfterInsertProcessorFunc := func(bean interface{}) { handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.IsAutoCommit { if session.isAutoCommit {
for _, closure := range session.afterClosures { for _, closure := range session.afterClosures {
closure(bean) closure(bean)
} }
@ -394,22 +394,22 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
// for postgres, many of them didn't implement lastInsertId, so we should // for postgres, many of them didn't implement lastInsertId, so we should
// implemented it ourself. // implemented it ourself.
if session.Engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 { if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
res, err := session.query("select seq_atable.currval from dual", args...) res, err := session.queryBytes("select seq_atable.currval from dual", args...)
if err != nil { if err != nil {
return 0, err return 0, err
} }
handleAfterInsertProcessorFunc(bean) defer handleAfterInsertProcessorFunc(bean)
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(table, 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)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() { } else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1) verValue.SetInt(1)
} }
@ -427,7 +427,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
aiValue, err := table.AutoIncrColumn().ValueOf(bean) aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} }
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
@ -437,24 +437,24 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
aiValue.Set(int64ToIntValue(id, aiValue.Type())) aiValue.Set(int64ToIntValue(id, aiValue.Type()))
return 1, nil return 1, nil
} else if session.Engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 { } else if session.engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 {
//assert table.AutoIncrement != "" //assert table.AutoIncrement != ""
sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement) sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement)
res, err := session.query(sqlStr, args...) res, err := session.queryBytes(sqlStr, args...)
if err != nil { if err != nil {
return 0, err return 0, err
} }
handleAfterInsertProcessorFunc(bean) defer handleAfterInsertProcessorFunc(bean)
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(table, 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)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() { } else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1) verValue.SetInt(1)
} }
@ -472,7 +472,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
aiValue, err := table.AutoIncrColumn().ValueOf(bean) aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} }
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
@ -490,14 +490,14 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
defer handleAfterInsertProcessorFunc(bean) defer handleAfterInsertProcessorFunc(bean)
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(table, 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)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() { } else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1) verValue.SetInt(1)
} }
@ -515,7 +515,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
aiValue, err := table.AutoIncrColumn().ValueOf(bean) aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} }
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
@ -532,24 +532,21 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
// 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
func (session *Session) InsertOne(bean interface{}) (int64, error) { func (session *Session) InsertOne(bean interface{}) (int64, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
return session.innerInsert(bean) return session.innerInsert(bean)
} }
func (session *Session) cacheInsert(tables ...string) error { func (session *Session) cacheInsert(table *core.Table, tables ...string) error {
if session.Statement.RefTable == nil { if table == nil {
return ErrCacheFailed return ErrCacheFailed
} }
table := session.Statement.RefTable cacher := session.engine.getCacher2(table)
cacher := session.Engine.getCacher2(table)
for _, t := range tables { for _, t := range tables {
session.Engine.logger.Debug("[cache] clear sql:", t) session.engine.logger.Debug("[cache] clear sql:", t)
cacher.ClearIds(t) cacher.ClearIds(t)
} }

54
vendor/github.com/go-xorm/xorm/session_iterate.go generated vendored

@ -19,6 +19,14 @@ func (session *Session) Rows(bean interface{}) (*Rows, error) {
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct // map[int64]*Struct
func (session *Session) Iterate(bean interface{}, fun IterFunc) error { func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
if session.isAutoClose {
defer session.Close()
}
if session.statement.bufferSize > 0 {
return session.bufferIterate(bean, fun)
}
rows, err := session.Rows(bean) rows, err := session.Rows(bean)
if err != nil { if err != nil {
return err return err
@ -40,3 +48,49 @@ func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
} }
return err return err
} }
// BufferSize sets the buffersize for iterate
func (session *Session) BufferSize(size int) *Session {
session.statement.bufferSize = size
return session
}
func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
if session.isAutoClose {
defer session.Close()
}
var bufferSize = session.statement.bufferSize
var limit = session.statement.LimitN
if limit > 0 && bufferSize > limit {
bufferSize = limit
}
var start = session.statement.Start
v := rValue(bean)
sliceType := reflect.SliceOf(v.Type())
var idx = 0
for {
slice := reflect.New(sliceType)
if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil {
return err
}
for i := 0; i < slice.Elem().Len(); i++ {
if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil {
return err
}
idx++
}
start = start + slice.Elem().Len()
if limit > 0 && idx+bufferSize > limit {
bufferSize = limit - idx
}
if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit {
break
}
}
return nil
}

262
vendor/github.com/go-xorm/xorm/session_query.go generated vendored

@ -0,0 +1,262 @@
// 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 (
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
if len(sqlorArgs) > 0 {
switch sqlorArgs[0].(type) {
case string:
return sqlorArgs[0].(string), sqlorArgs[1:], nil
case *builder.Builder:
return sqlorArgs[0].(*builder.Builder).ToSQL()
case builder.Builder:
bd := sqlorArgs[0].(builder.Builder)
return bd.ToSQL()
default:
return "", nil, ErrUnSupportedType
}
}
if session.statement.RawSQL != "" {
return session.statement.RawSQL, session.statement.RawParams, nil
}
if len(session.statement.TableName()) <= 0 {
return "", nil, ErrTableNotFound
}
var columnStr = session.statement.ColumnStr
if len(session.statement.selectStr) > 0 {
columnStr = session.statement.selectStr
} else {
if session.statement.JoinStr == "" {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = session.statement.genColumnStr()
}
}
} else {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = "*"
}
}
}
if columnStr == "" {
columnStr = "*"
}
}
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil {
return "", nil, err
}
args := append(session.statement.joinArgs, condArgs...)
sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true)
if err != nil {
return "", nil, err
}
// for mssql and use limit
qs := strings.Count(sqlStr, "?")
if len(args)*2 == qs {
args = append(args, args...)
}
return sqlStr, args, nil
}
// 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.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
return session.queryBytes(sqlStr, args...)
}
func value2String(rawValue *reflect.Value) (str string, err error) {
aa := reflect.TypeOf((*rawValue).Interface())
vv := reflect.ValueOf((*rawValue).Interface())
switch aa.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
str = strconv.FormatInt(vv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
str = strconv.FormatUint(vv.Uint(), 10)
case reflect.Float32, reflect.Float64:
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
case reflect.String:
str = vv.String()
case reflect.Array, reflect.Slice:
switch aa.Elem().Kind() {
case reflect.Uint8:
data := rawValue.Interface().([]byte)
str = string(data)
if str == "\x00" {
str = "0"
}
default:
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
// time type
case reflect.Struct:
if aa.ConvertibleTo(core.TimeType) {
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
} else {
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
case reflect.Bool:
str = strconv.FormatBool(vv.Bool())
case reflect.Complex128, reflect.Complex64:
str = fmt.Sprintf("%v", vv.Complex())
/* TODO: unsupported types below
case reflect.Map:
case reflect.Ptr:
case reflect.Uintptr:
case reflect.UnsafePointer:
case reflect.Chan, reflect.Func, reflect.Interface:
*/
default:
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
return
}
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
result := make(map[string]string)
scanResultContainers := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var scanResultContainer interface{}
scanResultContainers[i] = &scanResultContainer
}
if err := rows.Scan(scanResultContainers...); err != nil {
return nil, err
}
for ii, key := range fields {
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
// if row is null then as empty string
if rawValue.Interface() == nil {
result[key] = ""
continue
}
if data, err := value2String(&rawValue); err == nil {
result[key] = data
} else {
return nil, err
}
}
return result, nil
}
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := row2mapStr(rows, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
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.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2Strings(rows)
}
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
resultsMap = make(map[string]interface{}, len(fields))
scanResultContainers := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var scanResultContainer interface{}
scanResultContainers[i] = &scanResultContainer
}
if err := rows.Scan(scanResultContainers...); err != nil {
return nil, err
}
for ii, key := range fields {
resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface()
}
return
}
func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := row2mapInterface(rows, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
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.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2Interfaces(rows)
}

295
vendor/github.com/go-xorm/xorm/session_raw.go generated vendored

@ -6,87 +6,92 @@ package xorm
import ( import (
"database/sql" "database/sql"
"fmt"
"reflect" "reflect"
"strconv"
"time" "time"
"github.com/go-xorm/core" "github.com/go-xorm/core"
) )
func (session *Session) query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) { func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
session.queryPreprocess(&sqlStr, paramStr...) for _, filter := range session.engine.dialect.Filters() {
*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
if session.IsAutoCommit {
return session.innerQuery2(sqlStr, paramStr...)
} }
return session.txQuery(session.Tx, sqlStr, paramStr...)
session.lastSQL = *sqlStr
session.lastSQLArgs = paramStr
} }
func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string][]byte, error) { func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
rows, err := tx.Query(sqlStr, params...) defer session.resetStatement()
if err != nil {
return nil, err session.queryPreprocess(&sqlStr, args...)
if session.engine.showSQL {
if session.engine.showExecTime {
b4ExecTime := time.Now()
defer func() {
execDuration := time.Since(b4ExecTime)
if len(args) > 0 {
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
} else {
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
}
}()
} else {
if len(args) > 0 {
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
} else {
session.engine.logger.Infof("[SQL] %v", sqlStr)
}
}
} }
defer rows.Close()
return rows2maps(rows) if session.isAutoCommit {
} var db *core.DB
if session.engine.engineGroup != nil {
db = session.engine.engineGroup.Slave().DB()
} else {
db = session.DB()
}
func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) { if session.prepareStmt {
var callback func() (*core.Stmt, *core.Rows, error) // don't clear stmt since session will cache them
if session.prepareStmt { stmt, err := session.doPrepare(db, sqlStr)
callback = func() (*core.Stmt, *core.Rows, error) {
stmt, err := session.doPrepare(sqlStr)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
rows, err := stmt.Query(params...)
rows, err := stmt.Query(args...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
return stmt, rows, nil return rows, nil
} }
} else {
callback = func() (*core.Stmt, *core.Rows, error) { rows, err := db.Query(sqlStr, args...)
rows, err := session.DB().Query(sqlStr, params...) if err != nil {
if err != nil { return nil, err
return nil, nil, err
}
return nil, rows, err
} }
return rows, nil
} }
stmt, rows, err := session.Engine.logSQLQueryTime(sqlStr, params, callback)
if err != nil {
return nil, nil, err
}
return stmt, rows, nil
}
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { rows, err := session.tx.Query(sqlStr, args...)
fields, err := rows.Columns()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for rows.Next() { return rows, nil
result, err := row2map(rows, fields) }
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
return resultsSlice, nil func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
return core.NewRow(session.queryRows(sqlStr, args...))
} }
func value2Bytes(rawValue *reflect.Value) (data []byte, err error) { func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
var str string str, err := value2String(rawValue)
str, err = reflect2value(rawValue)
if err != nil { if err != nil {
return return nil, err
} }
data = []byte(str) return []byte(str), nil
return
} }
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) { func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
@ -104,7 +109,7 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
//if row is null then ignore //if row is null then ignore
if rawValue.Interface() == nil { if rawValue.Interface() == nil {
//fmt.Println("ignore ...", key, rawValue) result[key] = []byte{}
continue continue
} }
@ -117,34 +122,13 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
return result, nil return result, nil
} }
func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) { func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
_, rows, err := session.innerQuery(sqlStr, params...)
if rows != nil {
defer rows.Close()
}
if err != nil {
return nil, err
}
return rows2maps(rows)
}
// Query runs a raw sql and return records as []map[string][]byte
func (session *Session) Query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
return session.query(sqlStr, paramStr...)
}
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
fields, err := rows.Columns() fields, err := rows.Columns()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for rows.Next() { for rows.Next() {
result, err := row2mapStr(rows, fields) result, err := row2map(rows, fields)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -154,124 +138,47 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
return resultsSlice, nil return resultsSlice, nil
} }
func reflect2value(rawValue *reflect.Value) (str string, err error) { func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
aa := reflect.TypeOf((*rawValue).Interface()) rows, err := session.queryRows(sqlStr, args...)
vv := reflect.ValueOf((*rawValue).Interface())
switch aa.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
str = strconv.FormatInt(vv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
str = strconv.FormatUint(vv.Uint(), 10)
case reflect.Float32, reflect.Float64:
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
case reflect.String:
str = vv.String()
case reflect.Array, reflect.Slice:
switch aa.Elem().Kind() {
case reflect.Uint8:
data := rawValue.Interface().([]byte)
str = string(data)
default:
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
// time type
case reflect.Struct:
if aa.ConvertibleTo(core.TimeType) {
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
} else {
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
case reflect.Bool:
str = strconv.FormatBool(vv.Bool())
case reflect.Complex128, reflect.Complex64:
str = fmt.Sprintf("%v", vv.Complex())
/* TODO: unsupported types below
case reflect.Map:
case reflect.Ptr:
case reflect.Uintptr:
case reflect.UnsafePointer:
case reflect.Chan, reflect.Func, reflect.Interface:
*/
default:
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
}
return
}
func value2String(rawValue *reflect.Value) (data string, err error) {
data, err = reflect2value(rawValue)
if err != nil {
return
}
return
}
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
result := make(map[string]string)
scanResultContainers := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var scanResultContainer interface{}
scanResultContainers[i] = &scanResultContainer
}
if err := rows.Scan(scanResultContainers...); err != nil {
return nil, err
}
for ii, key := range fields {
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
//if row is null then ignore
if rawValue.Interface() == nil {
//fmt.Println("ignore ...", key, rawValue)
continue
}
if data, err := value2String(&rawValue); err == nil {
result[key] = data
} else {
return nil, err // !nashtsai! REVIEW, should return err or just error log?
}
}
return result, nil
}
func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) {
rows, err := tx.Query(sqlStr, params...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
return rows2Strings(rows) return rows2maps(rows)
}
func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) {
rows, err := db.Query(sqlStr, params...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2Strings(rows)
} }
// QueryString runs a raw sql and return records as []map[string]string func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
defer session.resetStatement() defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
session.queryPreprocess(&sqlStr, args...) session.queryPreprocess(&sqlStr, args...)
if session.IsAutoCommit { if session.engine.showSQL {
return query2(session.DB(), sqlStr, args...) if session.engine.showExecTime {
b4ExecTime := time.Now()
defer func() {
execDuration := time.Since(b4ExecTime)
if len(args) > 0 {
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
} else {
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
}
}()
} else {
if len(args) > 0 {
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
} else {
session.engine.logger.Infof("[SQL] %v", sqlStr)
}
}
}
if !session.isAutoCommit {
return session.tx.Exec(sqlStr, args...)
} }
return txQuery2(session.Tx, sqlStr, args...)
}
// Execute sql
func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) {
if session.prepareStmt { if session.prepareStmt {
stmt, err := session.doPrepare(sqlStr) stmt, err := session.doPrepare(session.DB(), sqlStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -286,33 +193,9 @@ func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Resul
return session.DB().Exec(sqlStr, args...) return session.DB().Exec(sqlStr, args...)
} }
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
for _, filter := range session.Engine.dialect.Filters() {
// TODO: for table name, it's no need to RefTable
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
}
session.saveLastSQL(sqlStr, args...)
return session.Engine.logSQLExecutionTime(sqlStr, args, func() (sql.Result, error) {
if session.IsAutoCommit {
// FIXME: oci8 can not auto commit (github.com/mattn/go-oci8)
if session.Engine.dialect.DBType() == core.ORACLE {
session.Begin()
r, err := session.Tx.Exec(sqlStr, args...)
session.Commit()
return r, err
}
return session.innerExec(sqlStr, args...)
}
return session.Tx.Exec(sqlStr, args...)
})
}
// Exec raw sql // Exec raw sql
func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) { func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }

202
vendor/github.com/go-xorm/xorm/session_schema.go generated vendored

@ -16,42 +16,50 @@ import (
// Ping test if database is ok // Ping test if database is ok
func (session *Session) Ping() error { func (session *Session) Ping() error {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
return session.DB().Ping() return session.DB().Ping()
} }
// CreateTable create a table according a bean // CreateTable create a table according a bean
func (session *Session) CreateTable(bean interface{}) error { func (session *Session) CreateTable(bean interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.createTable(bean)
}
func (session *Session) createTable(bean interface{}) error {
v := rValue(bean) v := rValue(bean)
if err := session.Statement.setRefValue(v); err != nil { if err := session.statement.setRefValue(v); err != nil {
return err return err
} }
defer session.resetStatement() sqlStr := session.statement.genCreateTableSQL()
if session.IsAutoClose { _, err := session.exec(sqlStr)
return err
}
// CreateIndexes create indexes
func (session *Session) CreateIndexes(bean interface{}) error {
if session.isAutoClose {
defer session.Close() defer session.Close()
} }
return session.createOneTable() return session.createIndexes(bean)
} }
// CreateIndexes create indexes func (session *Session) createIndexes(bean interface{}) error {
func (session *Session) CreateIndexes(bean interface{}) error {
v := rValue(bean) v := rValue(bean)
if err := session.Statement.setRefValue(v); err != nil { if err := session.statement.setRefValue(v); err != nil {
return err return err
} }
defer session.resetStatement() sqls := session.statement.genIndexSQL()
if session.IsAutoClose {
defer session.Close()
}
sqls := session.Statement.genIndexSQL()
for _, sqlStr := range sqls { for _, sqlStr := range sqls {
_, err := session.exec(sqlStr) _, err := session.exec(sqlStr)
if err != nil { if err != nil {
@ -63,17 +71,19 @@ func (session *Session) CreateIndexes(bean interface{}) error {
// CreateUniques create uniques // CreateUniques create uniques
func (session *Session) CreateUniques(bean interface{}) error { func (session *Session) CreateUniques(bean interface{}) error {
v := rValue(bean) if session.isAutoClose {
if err := session.Statement.setRefValue(v); err != nil { defer session.Close()
return err
} }
return session.createUniques(bean)
}
defer session.resetStatement() func (session *Session) createUniques(bean interface{}) error {
if session.IsAutoClose { v := rValue(bean)
defer session.Close() if err := session.statement.setRefValue(v); err != nil {
return err
} }
sqls := session.Statement.genUniqueSQL() sqls := session.statement.genUniqueSQL()
for _, sqlStr := range sqls { for _, sqlStr := range sqls {
_, err := session.exec(sqlStr) _, err := session.exec(sqlStr)
if err != nil { if err != nil {
@ -83,25 +93,22 @@ func (session *Session) CreateUniques(bean interface{}) error {
return nil return nil
} }
func (session *Session) createOneTable() error {
sqlStr := session.Statement.genCreateTableSQL()
_, err := session.exec(sqlStr)
return err
}
// DropIndexes drop indexes // DropIndexes drop indexes
func (session *Session) DropIndexes(bean interface{}) error { func (session *Session) DropIndexes(bean interface{}) error {
v := rValue(bean) if session.isAutoClose {
if err := session.Statement.setRefValue(v); err != nil { defer session.Close()
return err
} }
defer session.resetStatement() return session.dropIndexes(bean)
if session.IsAutoClose { }
defer session.Close()
func (session *Session) dropIndexes(bean interface{}) error {
v := rValue(bean)
if err := session.statement.setRefValue(v); err != nil {
return err
} }
sqls := session.Statement.genDelIndexSQL() sqls := session.statement.genDelIndexSQL()
for _, sqlStr := range sqls { for _, sqlStr := range sqls {
_, err := session.exec(sqlStr) _, err := session.exec(sqlStr)
if err != nil { if err != nil {
@ -113,15 +120,23 @@ func (session *Session) DropIndexes(bean interface{}) error {
// DropTable drop table will drop table if exist, if drop failed, it will return error // DropTable drop table will drop table if exist, if drop failed, it will return error
func (session *Session) DropTable(beanOrTableName interface{}) error { func (session *Session) DropTable(beanOrTableName interface{}) error {
tableName, err := session.Engine.tableName(beanOrTableName) if session.isAutoClose {
defer session.Close()
}
return session.dropTable(beanOrTableName)
}
func (session *Session) dropTable(beanOrTableName interface{}) error {
tableName, err := session.engine.tableName(beanOrTableName)
if err != nil { if err != nil {
return err return err
} }
var needDrop = true var needDrop = true
if !session.Engine.dialect.SupportDropIfExists() { if !session.engine.dialect.SupportDropIfExists() {
sqlStr, args := session.Engine.dialect.TableCheckSql(tableName) sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
results, err := session.query(sqlStr, args...) results, err := session.queryBytes(sqlStr, args...)
if err != nil { if err != nil {
return err return err
} }
@ -129,7 +144,7 @@ func (session *Session) DropTable(beanOrTableName interface{}) error {
} }
if needDrop { if needDrop {
sqlStr := session.Engine.Dialect().DropTableSql(tableName) sqlStr := session.engine.Dialect().DropTableSql(tableName)
_, err = session.exec(sqlStr) _, err = session.exec(sqlStr)
return err return err
} }
@ -138,7 +153,11 @@ func (session *Session) DropTable(beanOrTableName interface{}) error {
// IsTableExist if a table is exist // IsTableExist if a table is exist
func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) { func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
tableName, err := session.Engine.tableName(beanOrTableName) if session.isAutoClose {
defer session.Close()
}
tableName, err := session.engine.tableName(beanOrTableName)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -147,12 +166,8 @@ func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error)
} }
func (session *Session) isTableExist(tableName string) (bool, error) { func (session *Session) isTableExist(tableName string) (bool, error) {
defer session.resetStatement() sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
if session.IsAutoClose { results, err := session.queryBytes(sqlStr, args...)
defer session.Close()
}
sqlStr, args := session.Engine.dialect.TableCheckSql(tableName)
results, err := session.query(sqlStr, args...)
return len(results) > 0, err return len(results) > 0, err
} }
@ -162,6 +177,9 @@ func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
t := v.Type() t := v.Type()
if t.Kind() == reflect.String { if t.Kind() == reflect.String {
if session.isAutoClose {
defer session.Close()
}
return session.isTableEmpty(bean.(string)) return session.isTableEmpty(bean.(string))
} else if t.Kind() == reflect.Struct { } else if t.Kind() == reflect.Struct {
rows, err := session.Count(bean) rows, err := session.Count(bean)
@ -171,15 +189,9 @@ func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
} }
func (session *Session) isTableEmpty(tableName string) (bool, error) { func (session *Session) isTableEmpty(tableName string) (bool, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
var total int64 var total int64
sqlStr := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName)) sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName))
err := session.DB().QueryRow(sqlStr).Scan(&total) err := session.queryRow(sqlStr).Scan(&total)
session.saveLastSQL(sqlStr)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
err = nil err = nil
@ -192,12 +204,7 @@ func (session *Session) isTableEmpty(tableName string) (bool, error) {
// find if index is exist according cols // find if index is exist according cols
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) { func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
defer session.resetStatement() indexes, err := session.engine.dialect.GetIndexes(tableName)
if session.IsAutoClose {
defer session.Close()
}
indexes, err := session.Engine.dialect.GetIndexes(tableName)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -214,49 +221,46 @@ func (session *Session) isIndexExist2(tableName string, cols []string, unique bo
} }
func (session *Session) addColumn(colName string) error { func (session *Session) addColumn(colName string) error {
defer session.resetStatement() col := session.statement.RefTable.GetColumn(colName)
if session.IsAutoClose { sql, args := session.statement.genAddColumnStr(col)
defer session.Close()
}
col := session.Statement.RefTable.GetColumn(colName)
sql, args := session.Statement.genAddColumnStr(col)
_, err := session.exec(sql, args...) _, err := session.exec(sql, args...)
return err return err
} }
func (session *Session) addIndex(tableName, idxName string) error { func (session *Session) addIndex(tableName, idxName string) error {
defer session.resetStatement() index := session.statement.RefTable.Indexes[idxName]
if session.IsAutoClose { sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
defer session.Close()
}
index := session.Statement.RefTable.Indexes[idxName]
sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
_, err := session.exec(sqlStr) _, err := session.exec(sqlStr)
return err return err
} }
func (session *Session) addUnique(tableName, uqeName string) error { func (session *Session) addUnique(tableName, uqeName string) error {
defer session.resetStatement() index := session.statement.RefTable.Indexes[uqeName]
if session.IsAutoClose { sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
defer session.Close()
}
index := session.Statement.RefTable.Indexes[uqeName]
sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
_, err := session.exec(sqlStr) _, err := session.exec(sqlStr)
return err return err
} }
// Sync2 synchronize structs to database tables // Sync2 synchronize structs to database tables
func (session *Session) Sync2(beans ...interface{}) error { func (session *Session) Sync2(beans ...interface{}) error {
engine := session.Engine engine := session.engine
if session.isAutoClose {
session.isAutoClose = false
defer session.Close()
}
tables, err := engine.DBMetas() tables, err := engine.DBMetas()
if err != nil { if err != nil {
return err return err
} }
session.autoResetStatement = false
defer func() {
session.autoResetStatement = true
session.resetStatement()
}()
var structTables []*core.Table var structTables []*core.Table
for _, bean := range beans { for _, bean := range beans {
@ -277,17 +281,17 @@ func (session *Session) Sync2(beans ...interface{}) error {
} }
if oriTable == nil { if oriTable == nil {
err = session.StoreEngine(session.Statement.StoreEngine).CreateTable(bean) err = session.StoreEngine(session.statement.StoreEngine).createTable(bean)
if err != nil { if err != nil {
return err return err
} }
err = session.CreateUniques(bean) err = session.createUniques(bean)
if err != nil { if err != nil {
return err return err
} }
err = session.CreateIndexes(bean) err = session.createIndexes(bean)
if err != nil { if err != nil {
return err return err
} }
@ -312,7 +316,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
engine.dialect.DBType() == core.POSTGRES { engine.dialect.DBType() == core.POSTGRES {
engine.logger.Infof("Table %s column %s change type from %s to %s\n", engine.logger.Infof("Table %s column %s change type from %s to %s\n",
tbName, col.Name, curType, expectedType) tbName, col.Name, curType, expectedType)
_, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
} else { } else {
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
tbName, col.Name, curType, expectedType) tbName, col.Name, curType, expectedType)
@ -322,7 +326,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
if oriCol.Length < col.Length { if oriCol.Length < col.Length {
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
tbName, col.Name, oriCol.Length, col.Length) tbName, col.Name, oriCol.Length, col.Length)
_, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
} }
} }
} else { } else {
@ -336,7 +340,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
if oriCol.Length < col.Length { if oriCol.Length < col.Length {
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
tbName, col.Name, oriCol.Length, col.Length) tbName, col.Name, oriCol.Length, col.Length)
_, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
} }
} }
} }
@ -349,10 +353,8 @@ func (session *Session) Sync2(beans ...interface{}) error {
tbName, col.Name, oriCol.Nullable, col.Nullable) tbName, col.Name, oriCol.Nullable, col.Nullable)
} }
} else { } else {
session := engine.NewSession() session.statement.RefTable = table
session.Statement.RefTable = table session.statement.tableName = tbName
session.Statement.tableName = tbName
defer session.Close()
err = session.addColumn(col.Name) err = session.addColumn(col.Name)
} }
if err != nil { if err != nil {
@ -376,7 +378,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
if oriIndex != nil { if oriIndex != nil {
if oriIndex.Type != index.Type { if oriIndex.Type != index.Type {
sql := engine.dialect.DropIndexSql(tbName, oriIndex) sql := engine.dialect.DropIndexSql(tbName, oriIndex)
_, err = engine.Exec(sql) _, err = session.exec(sql)
if err != nil { if err != nil {
return err return err
} }
@ -392,7 +394,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
for name2, index2 := range oriTable.Indexes { for name2, index2 := range oriTable.Indexes {
if _, ok := foundIndexNames[name2]; !ok { if _, ok := foundIndexNames[name2]; !ok {
sql := engine.dialect.DropIndexSql(tbName, index2) sql := engine.dialect.DropIndexSql(tbName, index2)
_, err = engine.Exec(sql) _, err = session.exec(sql)
if err != nil { if err != nil {
return err return err
} }
@ -401,16 +403,12 @@ func (session *Session) Sync2(beans ...interface{}) error {
for name, index := range addedNames { for name, index := range addedNames {
if index.Type == core.UniqueType { if index.Type == core.UniqueType {
session := engine.NewSession() session.statement.RefTable = table
session.Statement.RefTable = table session.statement.tableName = tbName
session.Statement.tableName = tbName
defer session.Close()
err = session.addUnique(tbName, name) err = session.addUnique(tbName, name)
} else if index.Type == core.IndexType { } else if index.Type == core.IndexType {
session := engine.NewSession() session.statement.RefTable = table
session.Statement.RefTable = table session.statement.tableName = tbName
session.Statement.tableName = tbName
defer session.Close()
err = session.addIndex(tbName, name) err = session.addIndex(tbName, name)
} }
if err != nil { if err != nil {

98
vendor/github.com/go-xorm/xorm/session_stats.go generated vendored

@ -0,0 +1,98 @@
// Copyright 2016 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 (
"database/sql"
"errors"
"reflect"
)
// Count counts the records. bean's non-empty fields
// are conditions.
func (session *Session) Count(bean ...interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
sqlStr, args, err = session.statement.genCountSQL(bean...)
if err != nil {
return 0, err
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
var total int64
err = session.queryRow(sqlStr, args...).Scan(&total)
if err == sql.ErrNoRows || err == nil {
return total, nil
}
return 0, err
}
// sum call sum some column. bean's non-empty fields are conditions.
func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error {
if session.isAutoClose {
defer session.Close()
}
v := reflect.ValueOf(res)
if v.Kind() != reflect.Ptr {
return errors.New("need a pointer to a variable")
}
var isSlice = v.Elem().Kind() == reflect.Slice
var sqlStr string
var args []interface{}
var err error
if len(session.statement.RawSQL) == 0 {
sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...)
if err != nil {
return err
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
if isSlice {
err = session.queryRow(sqlStr, args...).ScanSlice(res)
} else {
err = session.queryRow(sqlStr, args...).Scan(res)
}
if err == sql.ErrNoRows || err == nil {
return nil
}
return err
}
// Sum call sum some column. bean's non-empty fields are conditions.
func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) {
return res, session.sum(&res, bean, columnName)
}
// SumInt call sum some column. bean's non-empty fields are conditions.
func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) {
return res, session.sum(&res, bean, columnName)
}
// Sums call sum some columns. bean's non-empty fields are conditions.
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
var res = make([]float64, len(columnNames), len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}
// SumsInt sum specify columns and return as []int64 instead of []float64
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
var res = make([]int64, len(columnNames), len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}

140
vendor/github.com/go-xorm/xorm/session_sum.go generated vendored

@ -1,140 +0,0 @@
// Copyright 2016 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 "database/sql"
// Count counts the records. bean's non-empty fields
// are conditions.
func (session *Session) Count(bean ...interface{}) (int64, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
if session.Statement.RawSQL == "" {
if len(bean) == 0 {
return 0, ErrTableNotFound
}
sqlStr, args = session.Statement.genCountSQL(bean[0])
} else {
sqlStr = session.Statement.RawSQL
args = session.Statement.RawParams
}
session.queryPreprocess(&sqlStr, args...)
var err error
var total int64
if session.IsAutoCommit {
err = session.DB().QueryRow(sqlStr, args...).Scan(&total)
} else {
err = session.Tx.QueryRow(sqlStr, args...).Scan(&total)
}
if err == sql.ErrNoRows || err == nil {
return total, nil
}
return 0, err
}
// Sum call sum some column. bean's non-empty fields are conditions.
func (session *Session) Sum(bean interface{}, columnName string) (float64, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
if len(session.Statement.RawSQL) == 0 {
sqlStr, args = session.Statement.genSumSQL(bean, columnName)
} else {
sqlStr = session.Statement.RawSQL
args = session.Statement.RawParams
}
session.queryPreprocess(&sqlStr, args...)
var err error
var res float64
if session.IsAutoCommit {
err = session.DB().QueryRow(sqlStr, args...).Scan(&res)
} else {
err = session.Tx.QueryRow(sqlStr, args...).Scan(&res)
}
if err == sql.ErrNoRows || err == nil {
return res, nil
}
return 0, err
}
// Sums call sum some columns. bean's non-empty fields are conditions.
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
if len(session.Statement.RawSQL) == 0 {
sqlStr, args = session.Statement.genSumSQL(bean, columnNames...)
} else {
sqlStr = session.Statement.RawSQL
args = session.Statement.RawParams
}
session.queryPreprocess(&sqlStr, args...)
var err error
var res = make([]float64, len(columnNames), len(columnNames))
if session.IsAutoCommit {
err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res)
} else {
err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res)
}
if err == sql.ErrNoRows || err == nil {
return res, nil
}
return nil, err
}
// SumsInt sum specify columns and return as []int64 instead of []float64
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
if len(session.Statement.RawSQL) == 0 {
sqlStr, args = session.Statement.genSumSQL(bean, columnNames...)
} else {
sqlStr = session.Statement.RawSQL
args = session.Statement.RawParams
}
session.queryPreprocess(&sqlStr, args...)
var err error
var res = make([]int64, len(columnNames), len(columnNames))
if session.IsAutoCommit {
err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res)
} else {
err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res)
}
if err == sql.ErrNoRows || err == nil {
return res, nil
}
return nil, err
}

24
vendor/github.com/go-xorm/xorm/session_tx.go generated vendored

@ -6,14 +6,14 @@ package xorm
// Begin a transaction // Begin a transaction
func (session *Session) Begin() error { func (session *Session) Begin() error {
if session.IsAutoCommit { if session.isAutoCommit {
tx, err := session.DB().Begin() tx, err := session.DB().Begin()
if err != nil { if err != nil {
return err return err
} }
session.IsAutoCommit = false session.isAutoCommit = false
session.IsCommitedOrRollbacked = false session.isCommitedOrRollbacked = false
session.Tx = tx session.tx = tx
session.saveLastSQL("BEGIN TRANSACTION") session.saveLastSQL("BEGIN TRANSACTION")
} }
return nil return nil
@ -21,25 +21,23 @@ func (session *Session) Begin() error {
// Rollback When using transaction, you can rollback if any error // Rollback When using transaction, you can rollback if any error
func (session *Session) Rollback() error { func (session *Session) Rollback() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { if !session.isAutoCommit && !session.isCommitedOrRollbacked {
session.saveLastSQL(session.Engine.dialect.RollBackStr()) session.saveLastSQL(session.engine.dialect.RollBackStr())
session.IsCommitedOrRollbacked = true session.isCommitedOrRollbacked = true
return session.Tx.Rollback() return session.tx.Rollback()
} }
return nil return nil
} }
// Commit When using transaction, Commit will commit all operations. // Commit When using transaction, Commit will commit all operations.
func (session *Session) Commit() error { func (session *Session) Commit() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { if !session.isAutoCommit && !session.isCommitedOrRollbacked {
session.saveLastSQL("COMMIT") session.saveLastSQL("COMMIT")
session.IsCommitedOrRollbacked = true session.isCommitedOrRollbacked = true
var err error var err error
if err = session.Tx.Commit(); err == nil { if err = session.tx.Commit(); err == nil {
// handle processors after tx committed // handle processors after tx committed
closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) { closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
if closuresPtr != nil { if closuresPtr != nil {
for _, closure := range *closuresPtr { for _, closure := range *closuresPtr {
closure(bean) closure(bean)

192
vendor/github.com/go-xorm/xorm/session_update.go generated vendored

@ -15,20 +15,20 @@ import (
"github.com/go-xorm/core" "github.com/go-xorm/core"
) )
func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
if session.Statement.RefTable == nil || if table == nil ||
session.Tx != nil { session.tx != nil {
return ErrCacheFailed return ErrCacheFailed
} }
oldhead, newsql := session.Statement.convertUpdateSQL(sqlStr) oldhead, newsql := session.statement.convertUpdateSQL(sqlStr)
if newsql == "" { if newsql == "" {
return ErrCacheFailed return ErrCacheFailed
} }
for _, filter := range session.Engine.dialect.Filters() { for _, filter := range session.engine.dialect.Filters() {
newsql = filter.Do(newsql, session.Engine.dialect, session.Statement.RefTable) newsql = filter.Do(newsql, session.engine.dialect, table)
} }
session.Engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql) session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql)
var nStart int var nStart int
if len(args) > 0 { if len(args) > 0 {
@ -39,13 +39,12 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
nStart = strings.Count(oldhead, "$") nStart = strings.Count(oldhead, "$")
} }
} }
table := session.Statement.RefTable
cacher := session.Engine.getCacher2(table) cacher := session.engine.getCacher2(table)
tableName := session.Statement.TableName() session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
session.Engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
if err != nil { if err != nil {
rows, err := session.DB().Query(newsql, args[nStart:]...) rows, err := session.NoCache().queryRows(newsql, args[nStart:]...)
if err != nil { if err != nil {
return err return err
} }
@ -75,9 +74,9 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
ids = append(ids, pk) ids = append(ids, pk)
} }
session.Engine.logger.Debug("[cacheUpdate] find updated id", ids) session.engine.logger.Debug("[cacheUpdate] find updated id", ids)
} /*else { } /*else {
session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args) session.engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
cacher.DelIds(tableName, genSqlKey(newsql, args)) cacher.DelIds(tableName, genSqlKey(newsql, args))
}*/ }*/
@ -103,36 +102,36 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
colName := sps2[len(sps2)-1] colName := sps2[len(sps2)-1]
if strings.Contains(colName, "`") { if strings.Contains(colName, "`") {
colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1)) colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1))
} else if strings.Contains(colName, session.Engine.QuoteStr()) { } else if strings.Contains(colName, session.engine.QuoteStr()) {
colName = strings.TrimSpace(strings.Replace(colName, session.Engine.QuoteStr(), "", -1)) colName = strings.TrimSpace(strings.Replace(colName, session.engine.QuoteStr(), "", -1))
} else { } else {
session.Engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName) session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName)
return ErrCacheFailed return ErrCacheFailed
} }
if col := table.GetColumn(colName); col != nil { if col := table.GetColumn(colName); col != nil {
fieldValue, err := col.ValueOf(bean) fieldValue, err := col.ValueOf(bean)
if err != nil { if err != nil {
session.Engine.logger.Error(err) session.engine.logger.Error(err)
} else { } else {
session.Engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface()) session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
if col.IsVersion && session.Statement.checkVersion { if col.IsVersion && session.statement.checkVersion {
fieldValue.SetInt(fieldValue.Int() + 1) fieldValue.SetInt(fieldValue.Int() + 1)
} else { } else {
fieldValue.Set(reflect.ValueOf(args[idx])) fieldValue.Set(reflect.ValueOf(args[idx]))
} }
} }
} else { } else {
session.Engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's", session.engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's",
colName, table.Name) colName, table.Name)
} }
} }
session.Engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean) session.engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean)
cacher.PutBean(tableName, sid, bean) cacher.PutBean(tableName, sid, bean)
} }
} }
session.Engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName) session.engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName)
cacher.ClearIds(tableName) cacher.ClearIds(tableName)
return nil return nil
} }
@ -144,8 +143,7 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
// You should call UseBool if you have bool to use. // You should call UseBool if you have bool to use.
// 2.float32 & float64 may be not inexact as conditions // 2.float32 & float64 may be not inexact as conditions
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
defer session.resetStatement() if session.isAutoClose {
if session.IsAutoClose {
defer session.Close() defer session.Close()
} }
@ -169,21 +167,21 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
var isMap = t.Kind() == reflect.Map var isMap = t.Kind() == reflect.Map
var isStruct = t.Kind() == reflect.Struct var isStruct = t.Kind() == reflect.Struct
if isStruct { if isStruct {
if err := session.Statement.setRefValue(v); err != nil { if err := session.statement.setRefValue(v); 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
} }
if session.Statement.ColumnStr == "" { if session.statement.ColumnStr == "" {
colNames, args = buildUpdates(session.Engine, session.Statement.RefTable, bean, false, false, colNames, args = buildUpdates(session.engine, session.statement.RefTable, bean, false, false,
false, false, session.Statement.allUseBool, session.Statement.useAllCols, false, false, session.statement.allUseBool, session.statement.useAllCols,
session.Statement.mustColumnMap, session.Statement.nullableMap, session.statement.mustColumnMap, session.statement.nullableMap,
session.Statement.columnMap, true, session.Statement.unscoped) session.statement.columnMap, true, session.statement.unscoped)
} else { } else {
colNames, args, err = genCols(session.Statement.RefTable, session, bean, true, true) colNames, args, err = genCols(session.statement.RefTable, session, bean, true, true)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -194,68 +192,84 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
bValue := reflect.Indirect(reflect.ValueOf(bean)) bValue := reflect.Indirect(reflect.ValueOf(bean))
for _, v := range bValue.MapKeys() { for _, v := range bValue.MapKeys() {
colNames = append(colNames, session.Engine.Quote(v.String())+" = ?") colNames = append(colNames, session.engine.Quote(v.String())+" = ?")
args = append(args, bValue.MapIndex(v).Interface()) args = append(args, bValue.MapIndex(v).Interface())
} }
} else { } else {
return 0, ErrParamsType return 0, ErrParamsType
} }
table := session.Statement.RefTable table := session.statement.RefTable
if session.Statement.UseAutoTime && table != nil && table.Updated != "" { if session.statement.UseAutoTime && table != nil && table.Updated != "" {
colNames = append(colNames, session.Engine.Quote(table.Updated)+" = ?") if _, ok := session.statement.columnMap[strings.ToLower(table.Updated)]; !ok {
col := table.UpdatedColumn() colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
val, t := session.Engine.NowTime2(col.SQLType.Name) col := table.UpdatedColumn()
args = append(args, val) val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
if isStruct { var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) { if isStruct {
col := table.GetColumn(colName) session.afterClosures = append(session.afterClosures, func(bean interface{}) {
setColumnTime(bean, col, t) col := table.GetColumn(colName)
}) setColumnTime(bean, col, t)
})
}
} }
} }
//for update action to like "column = column + ?" //for update action to like "column = column + ?"
incColumns := session.Statement.getInc() incColumns := session.statement.getInc()
for _, v := range incColumns { for _, v := range incColumns {
colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" + ?") colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?")
args = append(args, v.arg) args = append(args, v.arg)
} }
//for update action to like "column = column - ?" //for update action to like "column = column - ?"
decColumns := session.Statement.getDec() decColumns := session.statement.getDec()
for _, v := range decColumns { for _, v := range decColumns {
colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" - ?") colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?")
args = append(args, v.arg) args = append(args, v.arg)
} }
//for update action to like "column = expression" //for update action to like "column = expression"
exprColumns := session.Statement.getExpr() exprColumns := session.statement.getExpr()
for _, v := range exprColumns { for _, v := range exprColumns {
colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+v.expr) colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr)
} }
session.Statement.processIDParam() if err = session.statement.processIDParam(); err != nil {
return 0, err
}
var autoCond builder.Cond var autoCond builder.Cond
if !session.Statement.noAutoCondition && len(condiBean) > 0 { if !session.statement.noAutoCondition && len(condiBean) > 0 {
var err error if c, ok := condiBean[0].(map[string]interface{}); ok {
autoCond, err = session.Statement.buildConds(session.Statement.RefTable, condiBean[0], true, true, false, true, false) autoCond = builder.Eq(c)
if err != nil { } else {
return 0, err ct := reflect.TypeOf(condiBean[0])
k := ct.Kind()
if k == reflect.Ptr {
k = ct.Elem().Kind()
}
if k == reflect.Struct {
var err error
autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
if err != nil {
return 0, err
}
} else {
return 0, ErrConditionType
}
} }
} }
st := session.Statement st := &session.statement
defer session.resetStatement()
var sqlStr string var sqlStr string
var condArgs []interface{} var condArgs []interface{}
var condSQL string var condSQL string
cond := session.Statement.cond.And(autoCond) cond := session.statement.cond.And(autoCond)
var doIncVer = (table != nil && table.Version != "" && session.Statement.checkVersion) var doIncVer = (table != nil && table.Version != "" && session.statement.checkVersion)
var verValue *reflect.Value var verValue *reflect.Value
if doIncVer { if doIncVer {
verValue, err = table.VersionColumn().ValueOf(bean) verValue, err = table.VersionColumn().ValueOf(bean)
@ -263,11 +277,15 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
return 0, err return 0, err
} }
cond = cond.And(builder.Eq{session.Engine.Quote(table.Version): verValue.Interface()}) cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()})
colNames = append(colNames, session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1") colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1")
}
condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
} }
condSQL, condArgs, _ = builder.ToSQL(cond)
if len(condSQL) > 0 { if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL condSQL = "WHERE " + condSQL
} }
@ -276,6 +294,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr) condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
} }
var tableName = session.statement.TableName()
// TODO: Oracle support needed // TODO: Oracle support needed
var top string var top string
if st.LimitN > 0 { if st.LimitN > 0 {
@ -284,16 +303,23 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
} else if st.Engine.dialect.DBType() == core.SQLITE { } else if st.Engine.dialect.DBType() == core.SQLITE {
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
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)",
session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...)) session.engine.Quote(tableName), tempCondSQL), condArgs...))
condSQL, condArgs, _ = builder.ToSQL(cond) condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 { if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL condSQL = "WHERE " + condSQL
} }
} else if st.Engine.dialect.DBType() == core.POSTGRES { } else if st.Engine.dialect.DBType() == core.POSTGRES {
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...)) session.engine.Quote(tableName), tempCondSQL), condArgs...))
condSQL, condArgs, _ = builder.ToSQL(cond) condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 { if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL condSQL = "WHERE " + condSQL
} }
@ -302,9 +328,12 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
table != nil && len(table.PrimaryKeys) == 1 { table != nil && len(table.PrimaryKeys) == 1 {
cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)", cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)",
table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0], table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0],
session.Engine.Quote(session.Statement.TableName()), condSQL), condArgs...) session.engine.Quote(tableName), condSQL), condArgs...)
condSQL, condArgs, _ = builder.ToSQL(cond) condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 { if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL condSQL = "WHERE " + condSQL
} }
@ -314,9 +343,13 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
} }
} }
if len(colNames) <= 0 {
return 0, errors.New("No content found to be updated")
}
sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v", sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v",
top, top,
session.Engine.Quote(session.Statement.TableName()), session.engine.Quote(tableName),
strings.Join(colNames, ", "), strings.Join(colNames, ", "),
condSQL) condSQL)
@ -330,19 +363,20 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
} }
if table != nil { if table != nil {
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
cacher.ClearIds(session.Statement.TableName()) //session.cacheUpdate(table, tableName, sqlStr, args...)
cacher.ClearBeans(session.Statement.TableName()) cacher.ClearIds(tableName)
cacher.ClearBeans(tableName)
} }
} }
// handle after update processors // handle after update processors
if session.IsAutoCommit { if session.isAutoCommit {
for _, closure := range session.afterClosures { for _, closure := range session.afterClosures {
closure(bean) closure(bean)
} }
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
session.Engine.logger.Debug("[event]", session.Statement.TableName(), " has after update processor") session.engine.logger.Debug("[event]", tableName, " has after update processor")
processor.AfterUpdate() processor.AfterUpdate()
} }
} else { } else {

376
vendor/github.com/go-xorm/xorm/statement.go generated vendored

@ -73,6 +73,7 @@ type Statement struct {
decrColumns map[string]decrParam decrColumns map[string]decrParam
exprColumns map[string]exprParam exprColumns map[string]exprParam
cond builder.Cond cond builder.Cond
bufferSize int
} }
// Init reset all the statement's fields // Init reset all the statement's fields
@ -111,6 +112,7 @@ func (statement *Statement) Init() {
statement.decrColumns = make(map[string]decrParam) statement.decrColumns = make(map[string]decrParam)
statement.exprColumns = make(map[string]exprParam) statement.exprColumns = make(map[string]exprParam)
statement.cond = builder.NewCond() statement.cond = builder.NewCond()
statement.bufferSize = 0
} }
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function // NoAutoCondition if you do not want convert bean's field as query condition, then use this function
@ -158,6 +160,9 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme
case string: case string:
cond := builder.Expr(query.(string), args...) cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.And(cond) statement.cond = statement.cond.And(cond)
case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.And(cond)
case builder.Cond: case builder.Cond:
cond := query.(builder.Cond) cond := query.(builder.Cond)
statement.cond = statement.cond.And(cond) statement.cond = statement.cond.And(cond)
@ -179,6 +184,9 @@ func (statement *Statement) Or(query interface{}, args ...interface{}) *Statemen
case string: case string:
cond := builder.Expr(query.(string), args...) cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.Or(cond) statement.cond = statement.cond.Or(cond)
case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.Or(cond)
case builder.Cond: case builder.Cond:
cond := query.(builder.Cond) cond := query.(builder.Cond)
statement.cond = statement.cond.Or(cond) statement.cond = statement.cond.Or(cond)
@ -272,6 +280,9 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
fieldValue := *fieldValuePtr fieldValue := *fieldValuePtr
fieldType := reflect.TypeOf(fieldValue.Interface()) fieldType := reflect.TypeOf(fieldValue.Interface())
if fieldType == nil {
continue
}
requiredField := useAllCols requiredField := useAllCols
includeNil := useAllCols includeNil := useAllCols
@ -490,224 +501,6 @@ func (statement *Statement) colName(col *core.Column, tableName string) string {
return statement.Engine.Quote(col.Name) return statement.Engine.Quote(col.Name)
} }
func buildConds(engine *Engine, table *core.Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool,
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
var conds []builder.Cond
for _, col := range table.Columns() {
if !includeVersion && col.IsVersion {
continue
}
if !includeUpdated && col.IsUpdated {
continue
}
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
continue
}
if col.SQLType.IsJson() {
continue
}
var colName string
if addedTableName {
var nm = tableName
if len(aliasName) > 0 {
nm = aliasName
}
colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
} else {
colName = engine.Quote(col.Name)
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
engine.logger.Error(err)
continue
}
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
if engine.dialect.DBType() == core.MSSQL {
conds = append(conds, builder.IsNull{colName})
} else {
conds = append(conds, builder.IsNull{colName}.Or(builder.Eq{colName: "0001-01-01 00:00:00"}))
}
}
fieldValue := *fieldValuePtr
if fieldValue.Interface() == nil {
continue
}
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
if b {
requiredField = true
} else {
continue
}
}
if fieldType.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
if includeNil {
conds = append(conds, builder.Eq{colName: nil})
}
continue
} else if !fieldValue.IsValid() {
continue
} else {
// dereference ptr type to instance type
fieldValue = fieldValue.Elem()
fieldType = reflect.TypeOf(fieldValue.Interface())
requiredField = true
}
}
var val interface{}
switch fieldType.Kind() {
case reflect.Bool:
if allUseBool || requiredField {
val = fieldValue.Interface()
} else {
// if a bool in a struct, it will not be as a condition because it default is false,
// please use Where() instead
continue
}
case reflect.String:
if !requiredField && fieldValue.String() == "" {
continue
}
// for MyString, should convert to string or panic
if fieldType.String() != reflect.String.String() {
val = fieldValue.String()
} else {
val = fieldValue.Interface()
}
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
if !requiredField && fieldValue.Int() == 0 {
continue
}
val = fieldValue.Interface()
case reflect.Float32, reflect.Float64:
if !requiredField && fieldValue.Float() == 0.0 {
continue
}
val = fieldValue.Interface()
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
if !requiredField && fieldValue.Uint() == 0 {
continue
}
t := int64(fieldValue.Uint())
val = reflect.ValueOf(&t).Interface()
case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
continue
}
val = engine.formatColTime(col, t)
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
continue
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
val, _ = valNul.Value()
if val == nil {
continue
}
} else {
if col.SQLType.IsJson() {
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
if len(table.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
// fix non-int pk issues
//if pkField.Int() != 0 {
if pkField.IsValid() && !isZero(pkField.Interface()) {
val = pkField.Interface()
} else {
continue
}
} else {
//TODO: how to handler?
panic(fmt.Sprintln("not supported", fieldValue.Interface(), "as", table.PrimaryKeys))
}
} else {
val = fieldValue.Interface()
}
}
}
case reflect.Array:
continue
case reflect.Slice, reflect.Map:
if fieldValue == reflect.Zero(fieldType) {
continue
}
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
continue
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
fieldType.Elem().Kind() == reflect.Uint8 {
if fieldValue.Len() > 0 {
val = fieldValue.Bytes()
} else {
continue
}
} else {
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
continue
}
default:
val = fieldValue.Interface()
}
conds = append(conds, builder.Eq{colName: val})
}
return builder.And(conds...), nil
}
// TableName return current tableName // TableName return current tableName
func (statement *Statement) TableName() string { func (statement *Statement) TableName() string {
if statement.AltTableName != "" { if statement.AltTableName != "" {
@ -810,6 +603,22 @@ func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
return newColumns return newColumns
} }
func (statement *Statement) colmap2NewColsWithQuote() []string {
newColumns := make([]string, 0, len(statement.columnMap))
for col := range statement.columnMap {
fields := strings.Split(strings.TrimSpace(col), ".")
if len(fields) == 1 {
newColumns = append(newColumns, statement.Engine.quote(fields[0]))
} else if len(fields) == 2 {
newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+
statement.Engine.quote(fields[1]))
} else {
panic(errors.New("unwanted colnames"))
}
}
return newColumns
}
// Distinct generates "DISTINCT col1, col2 " statement // Distinct generates "DISTINCT col1, col2 " statement
func (statement *Statement) Distinct(columns ...string) *Statement { func (statement *Statement) Distinct(columns ...string) *Statement {
statement.IsDistinct = true statement.IsDistinct = true
@ -836,7 +645,7 @@ func (statement *Statement) Cols(columns ...string) *Statement {
statement.columnMap[strings.ToLower(nc)] = true statement.columnMap[strings.ToLower(nc)] = true
} }
newColumns := statement.col2NewColsWithQuote(columns...) newColumns := statement.colmap2NewColsWithQuote()
statement.ColumnStr = strings.Join(newColumns, ", ") statement.ColumnStr = strings.Join(newColumns, ", ")
statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1) statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1)
return statement return statement
@ -1098,32 +907,45 @@ func (statement *Statement) genDelIndexSQL() []string {
func (statement *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) { func (statement *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
quote := statement.Engine.Quote quote := statement.Engine.Quote
sql := fmt.Sprintf("ALTER TABLE %v ADD %v;", quote(statement.TableName()), sql := fmt.Sprintf("ALTER TABLE %v ADD %v", quote(statement.TableName()),
col.String(statement.Engine.dialect)) col.String(statement.Engine.dialect))
if statement.Engine.dialect.DBType() == core.MYSQL && len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ";"
return sql, []interface{}{} return sql, []interface{}{}
} }
func (statement *Statement) buildConds(table *core.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) { func (statement *Statement) buildConds(table *core.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) {
return buildConds(statement.Engine, table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols, return statement.Engine.buildConds(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
statement.unscoped, statement.mustColumnMap, statement.TableName(), statement.TableAlias, addedTableName) statement.unscoped, statement.mustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
} }
func (statement *Statement) genConds(bean interface{}) (string, []interface{}, error) { func (statement *Statement) mergeConds(bean interface{}) error {
if !statement.noAutoCondition { if !statement.noAutoCondition {
var addedTableName = (len(statement.JoinStr) > 0) var addedTableName = (len(statement.JoinStr) > 0)
autoCond, err := statement.buildConds(statement.RefTable, bean, true, true, false, true, addedTableName) autoCond, err := statement.buildConds(statement.RefTable, bean, true, true, false, true, addedTableName)
if err != nil { if err != nil {
return "", nil, err return err
} }
statement.cond = statement.cond.And(autoCond) statement.cond = statement.cond.And(autoCond)
} }
statement.processIDParam() if err := statement.processIDParam(); err != nil {
return err
}
return nil
}
func (statement *Statement) genConds(bean interface{}) (string, []interface{}, error) {
if err := statement.mergeConds(bean); err != nil {
return "", nil, err
}
return builder.ToSQL(statement.cond) return builder.ToSQL(statement.cond)
} }
func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}) { func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}, error) {
v := rValue(bean) v := rValue(bean)
isStruct := v.Kind() == reflect.Struct isStruct := v.Kind() == reflect.Struct
if isStruct { if isStruct {
@ -1156,21 +978,37 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{})
columnStr = "*" columnStr = "*"
} }
var condSQL string
var condArgs []interface{}
if isStruct { if isStruct {
condSQL, condArgs, _ = statement.genConds(bean) if err := statement.mergeConds(bean); err != nil {
} else { return "", nil, err
condSQL, condArgs, _ = builder.ToSQL(statement.cond) }
}
condSQL, condArgs, err := builder.ToSQL(statement.cond)
if err != nil {
return "", nil, err
} }
return statement.genSelectSQL(columnStr, condSQL), append(statement.joinArgs, condArgs...) sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true)
} if err != nil {
return "", nil, err
}
func (statement *Statement) genCountSQL(bean interface{}) (string, []interface{}) { return sqlStr, append(statement.joinArgs, condArgs...), nil
statement.setRefValue(rValue(bean)) }
condSQL, condArgs, _ := statement.genConds(bean) func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interface{}, error) {
var condSQL string
var condArgs []interface{}
var err error
if len(beans) > 0 {
statement.setRefValue(rValue(beans[0]))
condSQL, condArgs, err = statement.genConds(beans[0])
} else {
condSQL, condArgs, err = builder.ToSQL(statement.cond)
}
if err != nil {
return "", nil, err
}
var selectSQL = statement.selectStr var selectSQL = statement.selectStr
if len(selectSQL) <= 0 { if len(selectSQL) <= 0 {
@ -1180,10 +1018,15 @@ func (statement *Statement) genCountSQL(bean interface{}) (string, []interface{}
selectSQL = "count(*)" selectSQL = "count(*)"
} }
} }
return statement.genSelectSQL(selectSQL, condSQL), append(statement.joinArgs, condArgs...) sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false)
if err != nil {
return "", nil, err
}
return sqlStr, append(statement.joinArgs, condArgs...), nil
} }
func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}) { func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
statement.setRefValue(rValue(bean)) statement.setRefValue(rValue(bean))
var sumStrs = make([]string, 0, len(columns)) var sumStrs = make([]string, 0, len(columns))
@ -1195,12 +1038,20 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
} }
sumSelect := strings.Join(sumStrs, ", ") sumSelect := strings.Join(sumStrs, ", ")
condSQL, condArgs, _ := statement.genConds(bean) condSQL, condArgs, err := statement.genConds(bean)
if err != nil {
return "", nil, err
}
sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true)
if err != nil {
return "", nil, err
}
return statement.genSelectSQL(sumSelect, condSQL), append(statement.joinArgs, condArgs...) return sqlStr, append(statement.joinArgs, condArgs...), nil
} }
func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) { func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bool) (a string, err error) {
var distinct string var distinct string
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") { if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
distinct = "DISTINCT " distinct = "DISTINCT "
@ -1211,7 +1062,9 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
var top string var top string
var mssqlCondi string var mssqlCondi string
statement.processIDParam() if err := statement.processIDParam(); err != nil {
return "", err
}
var buf bytes.Buffer var buf bytes.Buffer
if len(condSQL) > 0 { if len(condSQL) > 0 {
@ -1296,15 +1149,17 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
if statement.OrderStr != "" { if statement.OrderStr != "" {
a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr) a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
} }
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE { if needLimit {
if statement.Start > 0 { if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start) if statement.Start > 0 {
} else if statement.LimitN > 0 { a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN) } else if statement.LimitN > 0 {
} a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
} else if dialect.DBType() == core.ORACLE { }
if statement.Start != 0 || statement.LimitN != 0 { } else if dialect.DBType() == core.ORACLE {
a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start) if statement.Start != 0 || statement.LimitN != 0 {
a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
}
} }
} }
if statement.IsForUpdate { if statement.IsForUpdate {
@ -1314,19 +1169,23 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
return return
} }
func (statement *Statement) processIDParam() { func (statement *Statement) processIDParam() error {
if statement.idParam == nil { if statement.idParam == nil {
return return nil
}
if len(statement.RefTable.PrimaryKeys) != len(*statement.idParam) {
return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d",
len(statement.RefTable.PrimaryKeys),
len(*statement.idParam),
)
} }
for i, col := range statement.RefTable.PKColumns() { for i, col := range statement.RefTable.PKColumns() {
var colName = statement.colName(col, statement.TableName()) var colName = statement.colName(col, statement.TableName())
if i < len(*(statement.idParam)) { statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]})
statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]})
} else {
statement.cond = statement.cond.And(builder.Eq{colName: ""})
}
} }
return nil
} }
func (statement *Statement) joinColumns(cols []*core.Column, includeTableName bool) string { func (statement *Statement) joinColumns(cols []*core.Column, includeTableName bool) string {
@ -1360,7 +1219,8 @@ func (statement *Statement) convertIDSQL(sqlStr string) string {
top = fmt.Sprintf("TOP %d ", statement.LimitN) top = fmt.Sprintf("TOP %d ", statement.LimitN)
} }
return fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1]) newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1])
return newsql
} }
return "" return ""
} }

9
vendor/github.com/go-xorm/xorm/tag.go generated vendored

@ -54,6 +54,7 @@ var (
"UNIQUE": UniqueTagHandler, "UNIQUE": UniqueTagHandler,
"CACHE": CacheTagHandler, "CACHE": CacheTagHandler,
"NOCACHE": NoCacheTagHandler, "NOCACHE": NoCacheTagHandler,
"COMMENT": CommentTagHandler,
} }
) )
@ -192,6 +193,14 @@ func UniqueTagHandler(ctx *tagContext) error {
return nil return nil
} }
// CommentTagHandler add comment to column
func CommentTagHandler(ctx *tagContext) error {
if len(ctx.params) > 0 {
ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
}
return nil
}
// SQLTypeTagHandler describes SQL Type tag handler // SQLTypeTagHandler describes SQL Type tag handler
func SQLTypeTagHandler(ctx *tagContext) error { func SQLTypeTagHandler(ctx *tagContext) error {
ctx.col.SQLType = core.SQLType{Name: ctx.tagName} ctx.col.SQLType = core.SQLType{Name: ctx.tagName}

1
vendor/github.com/go-xorm/xorm/test_mssql_cache.sh generated vendored

@ -0,0 +1 @@
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" -cache=true

1
vendor/github.com/go-xorm/xorm/test_mymysql.sh generated vendored

@ -0,0 +1 @@
go test -db=mymysql -conn_str="xorm_test/root/"

1
vendor/github.com/go-xorm/xorm/test_mymysql_cache.sh generated vendored

@ -0,0 +1 @@
go test -db=mymysql -conn_str="xorm_test/root/" -cache=true

1
vendor/github.com/go-xorm/xorm/test_mysql_cache.sh generated vendored

@ -0,0 +1 @@
go test -db=mysql -conn_str="root:@/xorm_test" -cache=true

1
vendor/github.com/go-xorm/xorm/test_postgres_cache.sh generated vendored

@ -0,0 +1 @@
go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" -cache=true

1
vendor/github.com/go-xorm/xorm/test_sqlite_cache.sh generated vendored

@ -0,0 +1 @@
go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" -cache=true

14
vendor/github.com/go-xorm/xorm/xorm.go generated vendored

@ -17,7 +17,7 @@ import (
const ( const (
// Version show the xorm's version // Version show the xorm's version
Version string = "0.6.2.0605" Version string = "0.6.4.0910"
) )
func regDrvsNDialects() bool { func regDrvsNDialects() bool {
@ -50,10 +50,13 @@ func close(engine *Engine) {
engine.Close() engine.Close()
} }
func init() {
regDrvsNDialects()
}
// NewEngine new a db manager according to the parameter. Currently support four // NewEngine new a db manager according to the parameter. Currently support four
// drivers // drivers
func NewEngine(driverName string, dataSourceName string) (*Engine, error) { func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
regDrvsNDialects()
driver := core.QueryDriver(driverName) driver := core.QueryDriver(driverName)
if driver == nil { if driver == nil {
return nil, fmt.Errorf("Unsupported driver name: %v", driverName) return nil, fmt.Errorf("Unsupported driver name: %v", driverName)
@ -105,6 +108,13 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
return engine, nil return engine, nil
} }
// NewEngineWithParams new a db manager with params. The params will be passed to dialect.
func NewEngineWithParams(driverName string, dataSourceName string, params map[string]string) (*Engine, error) {
engine, err := NewEngine(driverName, dataSourceName)
engine.dialect.SetParams(params)
return engine, err
}
// Clone clone an engine // Clone clone an engine
func (engine *Engine) Clone() (*Engine, error) { func (engine *Engine) Clone() (*Engine, error) {
return NewEngine(engine.DriverName(), engine.DataSourceName()) return NewEngine(engine.DriverName(), engine.DataSourceName())

6
vendor/vendor.json vendored

@ -165,10 +165,10 @@
"revisionTime": "2018-03-08T01:08:13Z" "revisionTime": "2018-03-08T01:08:13Z"
}, },
{ {
"checksumSHA1": "UN8r+3fuSzXJ1tXCe+M8g5eRpOI=", "checksumSHA1": "TLZlub4tqDx0a3BM8nXzuKksRwE=",
"path": "github.com/go-xorm/xorm", "path": "github.com/go-xorm/xorm",
"revision": "8a877636fdbbb0f7133b158fe5cde3588464b035", "revision": "11743c1a80897b0fdbf79d88ebcaa7dd5f9d3cf3",
"revisionTime": "2017-06-06T06:54:59Z" "revisionTime": "2018-03-08T01:30:38Z"
}, },
{ {
"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=", "checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=",

Loading…
Cancel
Save