fix migrate failed and org dashboard failed on MSSQL database (#1448)

This commit is contained in:
2017-04-06 18:47:25 -07:00
committed by GitHub
parent cf6699fb4f
commit 5acfc7c4bc
36 changed files with 1999 additions and 1634 deletions

View File

@ -670,13 +670,30 @@ func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*Repository, error)
Find(&repos) Find(&repos)
} }
func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) { func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
repos := make([]*Repository, 0, 10) repoIDs := make([]int64, 0, 10)
return repos, x. return repoIDs, x.
Select("`repository`.*"). Table("repository").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true). Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
Where(env.cond()). Where(env.cond()).
GroupBy("`repository`.id"). GroupBy("`repository`.id").
OrderBy("updated_unix DESC"). OrderBy("updated_unix DESC").
Cols("`repository`.id").
Find(&repoIDs)
}
func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) {
repoIDs, err := env.MirrorRepoIDs()
if err != nil {
return nil, fmt.Errorf("MirrorRepoIDs: %v", err)
}
repos := make([]*Repository, 0, len(repoIDs))
if len(repoIDs) <= 0 {
return repos, nil
}
return repos, x.
In("`repository`.id", repoIDs).
Find(&repos) Find(&repos)
} }

View File

@ -46,12 +46,15 @@ Drivers for Go's sql package which currently support database/sql includes:
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment) * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
# Changelog # Changelog
* **v0.6.2**
* refactor tag parse methods
* add Scan features to Get
* add QueryString method
* **v0.6.0** * **v0.6.0**
* remove support for ql * 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` * add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or`
@ -79,12 +82,6 @@ methods can use `builder.Cond` as parameter
# Installation # Installation
If you have [gopm](https://github.com/gpmgo/gopm) installed,
gopm get github.com/go-xorm/xorm
Or
go get github.com/go-xorm/xorm go get github.com/go-xorm/xorm
# Documents # Documents
@ -119,19 +116,21 @@ type User struct {
err := engine.Sync2(new(User)) err := engine.Sync2(new(User))
``` ```
* Query a SQL string, the returned results is []map[string][]byte * `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`.
```Go ```Go
results, err := engine.Query("select * from user") results, err := engine.Query("select * from user")
results, err := engine.QueryString("select * from user")
``` ```
* Execute a SQL string, the returned results * `Execute` runs a SQL string, it returns `affetcted` 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)
``` ```
* Insert one or multiple records to database * `Insert` one or multiple records to database
```Go ```Go
affected, err := engine.Insert(&user) affected, err := engine.Insert(&user)
@ -153,6 +152,18 @@ 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
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ?
var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
// SELECT id FROM user WHERE name = ?
var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
``` ```
* Query multiple records from database, also you can use join and extends * Query multiple records from database, also you can use join and extends

View File

@ -54,6 +54,11 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
## 更新日志 ## 更新日志
* **v0.6.2**
* 重构Tag解析方式
* Get方法新增类似Sacn的特性
* 新增 QueryString 方法
* **v0.6.0** * **v0.6.0**
* 去除对 ql 的支持 * 去除对 ql 的支持
* 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数 * 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数
@ -81,12 +86,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
## 安装 ## 安装
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
gopm get github.com/go-xorm/xorm
或者您也可以使用go工具进行安装
go get github.com/go-xorm/xorm go get github.com/go-xorm/xorm
## 文档 ## 文档
@ -121,13 +120,15 @@ type User struct {
err := engine.Sync2(new(User)) err := engine.Sync2(new(User))
``` ```
* 最原始的也支持SQL语句查询返回的结果类型为 []map[string][]byte * `Query` 最原始的也支持SQL语句查询返回的结果类型为 []map[string][]byte`QueryString` 返回 []map[string]string
```Go ```Go
results, err := engine.Query("select * from user") results, err := engine.Query("select * from user")
results, err := engine.QueryString("select * from user")
``` ```
* 执行一个SQL语句 * `Exec` 执行一个SQL语句
```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)
@ -155,6 +156,18 @@ 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
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ?
var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
// SELECT id FROM user WHERE name = ?
var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
``` ```
* 查询多条记录当然可以使用Join和extends来组合使用 * 查询多条记录当然可以使用Join和extends来组合使用

View File

@ -1 +0,0 @@
xorm v0.6.0.1022

View File

@ -247,3 +247,40 @@ func convertAssign(dest, src interface{}) error {
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
} }
func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
switch tp.Kind() {
case reflect.Int64:
return vv.Int(), nil
case reflect.Int:
return int(vv.Int()), nil
case reflect.Int32:
return int32(vv.Int()), nil
case reflect.Int16:
return int16(vv.Int()), nil
case reflect.Int8:
return int8(vv.Int()), nil
case reflect.Uint64:
return vv.Uint(), nil
case reflect.Uint:
return uint(vv.Uint()), nil
case reflect.Uint32:
return uint32(vv.Uint()), nil
case reflect.Uint16:
return uint16(vv.Uint()), nil
case reflect.Uint8:
return uint8(vv.Uint()), nil
case reflect.String:
return vv.String(), nil
case reflect.Slice:
if tp.Elem().Kind() == reflect.Uint8 {
v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
if err != nil {
return nil, err
}
return v, nil
}
}
return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
}

View File

@ -5,6 +5,7 @@
package xorm package xorm
import ( import (
"errors"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@ -215,9 +216,9 @@ func (db *mssql) SqlType(c *core.Column) string {
switch t := c.SQLType.Name; t { switch t := c.SQLType.Name; t {
case core.Bool: case core.Bool:
res = core.TinyInt res = core.TinyInt
if c.Default == "true" { if strings.EqualFold(c.Default, "true") {
c.Default = "1" c.Default = "1"
} else if c.Default == "false" { } else {
c.Default = "0" c.Default = "0"
} }
case core.Serial: case core.Serial:
@ -467,9 +468,10 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
} }
colName = strings.Trim(colName, "` ") colName = strings.Trim(colName, "` ")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):] indexName = indexName[5+len(tableName):]
isRegular = true
} }
var index *core.Index var index *core.Index
@ -478,6 +480,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
index = new(core.Index) index = new(core.Index)
index.Type = indexType index.Type = indexType
index.Name = indexName index.Name = indexName
index.IsRegular = isRegular
indexes[indexName] = index indexes[indexName] = index
} }
index.AddColumn(colName) index.AddColumn(colName)
@ -526,3 +529,25 @@ func (db *mssql) ForUpdateSql(query string) string {
func (db *mssql) Filters() []core.Filter { func (db *mssql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}} return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
} }
type odbcDriver struct {
}
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
kv := strings.Split(dataSourceName, ";")
var dbName string
for _, c := range kv {
vv := strings.Split(strings.TrimSpace(c), "=")
if len(vv) == 2 {
switch strings.ToLower(vv[0]) {
case "database":
dbName = vv[1]
}
}
}
if dbName == "" {
return nil, errors.New("no db name provided")
}
return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
}

View File

@ -6,7 +6,9 @@ package xorm
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -486,3 +488,93 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
func (db *mysql) Filters() []core.Filter { func (db *mysql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}} return []core.Filter{&core.IdFilter{}}
} }
type mymysqlDriver struct {
}
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.MYSQL}
pd := strings.SplitN(dataSourceName, "*", 2)
if len(pd) == 2 {
// Parse protocol part of URI
p := strings.SplitN(pd[0], ":", 2)
if len(p) != 2 {
return nil, errors.New("Wrong protocol part of URI")
}
db.Proto = p[0]
options := strings.Split(p[1], ",")
db.Raddr = options[0]
for _, o := range options[1:] {
kv := strings.SplitN(o, "=", 2)
var k, v string
if len(kv) == 2 {
k, v = kv[0], kv[1]
} else {
k, v = o, "true"
}
switch k {
case "laddr":
db.Laddr = v
case "timeout":
to, err := time.ParseDuration(v)
if err != nil {
return nil, err
}
db.Timeout = to
default:
return nil, errors.New("Unknown option: " + k)
}
}
// Remove protocol part
pd = pd[1:]
}
// Parse database part of URI
dup := strings.SplitN(pd[0], "/", 3)
if len(dup) != 3 {
return nil, errors.New("Wrong database part of URI")
}
db.DbName = dup[0]
db.User = dup[1]
db.Passwd = dup[2]
return db, nil
}
type mysqlDriver struct {
}
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
uri := &core.Uri{DbType: core.MYSQL}
for i, match := range matches {
switch names[i] {
case "dbname":
uri.DbName = match
case "params":
if len(match) > 0 {
kvs := strings.Split(match, "&")
for _, kv := range kvs {
splits := strings.Split(kv, "=")
if len(splits) == 2 {
switch splits[0] {
case "charset":
uri.Charset = splits[1]
}
}
}
}
}
}
return uri, nil
}

View File

@ -5,7 +5,9 @@
package xorm package xorm
import ( import (
"errors"
"fmt" "fmt"
"regexp"
"strconv" "strconv"
"strings" "strings"
@ -822,6 +824,12 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
indexName = strings.Trim(indexName, `" `) indexName = strings.Trim(indexName, `" `)
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):]
isRegular = true
}
if uniqueness == "UNIQUE" { if uniqueness == "UNIQUE" {
indexType = core.UniqueType indexType = core.UniqueType
} else { } else {
@ -834,6 +842,7 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
index = new(core.Index) index = new(core.Index)
index.Type = indexType index.Type = indexType
index.Name = indexName index.Name = indexName
index.IsRegular = isRegular
indexes[indexName] = index indexes[indexName] = index
} }
index.AddColumn(colName) index.AddColumn(colName)
@ -844,3 +853,54 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
func (db *oracle) Filters() []core.Filter { func (db *oracle) Filters() []core.Filter {
return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}} return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}}
} }
type goracleDriver struct {
}
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}
type oci8Driver struct {
}
//dataSourceName=user/password@ipv4:port/dbname
//dataSourceName=user/password@[ipv6]:port/dbname
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
`(?P<net>.*)` + // ip:port
`\/(?P<dbname>.*)`) // dbname
matches := dsnPattern.FindStringSubmatch(dataSourceName)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}

View File

@ -5,7 +5,10 @@
package xorm package xorm
import ( import (
"errors"
"fmt" "fmt"
"net/url"
"sort"
"strconv" "strconv"
"strings" "strings"
@ -1075,9 +1078,10 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
} }
cs := strings.Split(indexdef, "(") cs := strings.Split(indexdef, "(")
colNames = strings.Split(cs[1][0:len(cs[1])-1], ",") colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
newIdxName := indexName[5+len(tableName):] newIdxName := indexName[5+len(tableName):]
isRegular = true
if newIdxName != "" { if newIdxName != "" {
indexName = newIdxName indexName = newIdxName
} }
@ -1087,6 +1091,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
for _, colName := range colNames { for _, colName := range colNames {
index.Cols = append(index.Cols, strings.Trim(colName, `" `)) index.Cols = append(index.Cols, strings.Trim(colName, `" `))
} }
index.IsRegular = isRegular
indexes[index.Name] = index indexes[index.Name] = index
} }
return indexes, nil return indexes, nil
@ -1095,3 +1100,107 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
func (db *postgres) Filters() []core.Filter { func (db *postgres) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}} return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}}
} }
type pqDriver struct {
}
type values map[string]string
func (vs values) Set(k, v string) {
vs[k] = v
}
func (vs values) Get(k string) (v string) {
return vs[k]
}
func errorf(s string, args ...interface{}) {
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
}
func parseURL(connstr string) (string, error) {
u, err := url.Parse(connstr)
if err != nil {
return "", err
}
if u.Scheme != "postgresql" && u.Scheme != "postgres" {
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
}
var kvs []string
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 != "" {
accrue("dbname", u.Path[1:])
}
q := u.Query()
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) {
if len(name) == 0 {
return
}
name = strings.TrimSpace(name)
ps := strings.Split(name, " ")
for _, p := range ps {
kv := strings.Split(p, "=")
if len(kv) < 2 {
errorf("invalid option: %q", p)
}
o.Set(kv[0], kv[1])
}
}
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.POSTGRES}
o := make(values)
var err error
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
dataSourceName, err = parseURL(dataSourceName)
if err != nil {
return nil, err
}
}
parseOpts(dataSourceName, o)
db.DbName = o.Get("dbname")
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
/*db.Schema = o.Get("schema")
if len(db.Schema) == 0 {
db.Schema = "public"
}*/
return db, nil
}

View File

@ -405,8 +405,10 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
} }
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []") indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
index.Name = indexName[5+len(tableName):] index.Name = indexName[5+len(tableName):]
isRegular = true
} else { } else {
index.Name = indexName index.Name = indexName
} }
@ -425,6 +427,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
for _, col := range colIndexes { for _, col := range colIndexes {
index.Cols = append(index.Cols, strings.Trim(col, "` []")) index.Cols = append(index.Cols, strings.Trim(col, "` []"))
} }
index.IsRegular = isRegular
indexes[index.Name] = index indexes[index.Name] = index
} }
@ -434,3 +437,10 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
func (db *sqlite3) Filters() []core.Filter { func (db *sqlite3) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}} return []core.Filter{&core.IdFilter{}}
} }
type sqlite3Driver struct {
}
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
}

View File

@ -24,7 +24,7 @@ Generally, one engine for an application is enough. You can set it as package va
Raw Methods Raw Methods
Xorm also support raw sql execution: XORM also support raw SQL execution:
1. query a SQL string, the returned results is []map[string][]byte 1. query a SQL string, the returned results is []map[string][]byte
@ -36,7 +36,7 @@ Xorm also support raw sql execution:
ORM Methods ORM Methods
There are 7 major ORM methods and many helpful methods to use to operate database. There are 8 major ORM methods and many helpful methods to use to operate database.
1. Insert one or multiple records to database 1. Insert one or multiple records to database
@ -58,10 +58,18 @@ There are 7 major ORM methods and many helpful methods to use to operate databas
3. Query multiple records from database 3. Query multiple records from database
sliceOfStructs := new(Struct) var sliceOfStructs []Struct
err := engine.Find(sliceOfStructs) err := engine.Find(&sliceOfStructs)
// SELECT * FROM user // SELECT * FROM user
var mapOfStructs = make(map[int64]Struct)
err := engine.Find(&mapOfStructs)
// SELECT * FROM user
var int64s []int64
err := engine.Table("user").Cols("id").Find(&int64s)
// SELECT id FROM user
4. Query multiple records and record by record handle, there two methods, one is Iterate, 4. Query multiple records and record by record handle, there two methods, one is Iterate,
another is Rows another is Rows
@ -91,20 +99,31 @@ another is Rows
counts, err := engine.Count(&user) counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user // SELECT count(*) AS total FROM user
8. Sum records
sumFloat64, err := engine.Sum(&user, "id")
// SELECT sum(id) from user
sumFloat64s, err := engine.Sums(&user, "id1", "id2")
// SELECT sum(id1), sum(id2) from user
sumInt64s, err := engine.SumsInt(&user, "id1", "id2")
// SELECT sum(id1), sum(id2) from user
Conditions Conditions
The above 7 methods could use with condition methods chainable. The above 8 methods could use with condition methods chainable.
Attention: the above 7 methods should be the last chainable method. Attention: the above 8 methods should be the last chainable method.
1. Id, In 1. ID, In
engine.Id(1).Get(&user) // for single primary key engine.ID(1).Get(&user) // for single primary key
// SELECT * FROM user WHERE id = 1 // SELECT * FROM user WHERE id = 1
engine.Id(core.PK{1, 2}).Get(&user) // for composite primary keys engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
// SELECT * FROM user WHERE id1 = 1 AND id2 = 2 // SELECT * FROM user WHERE id1 = 1 AND id2 = 2
engine.In("id", 1, 2, 3).Find(&users) engine.In("id", 1, 2, 3).Find(&users)
// SELECT * FROM user WHERE id IN (1, 2, 3) // SELECT * FROM user WHERE id IN (1, 2, 3)
engine.In("id", []int{1, 2, 3}) engine.In("id", []int{1, 2, 3}).Find(&users)
// SELECT * FROM user WHERE id IN (1, 2, 3) // SELECT * FROM user WHERE id IN (1, 2, 3)
2. Where, And, Or 2. Where, And, Or
@ -127,10 +146,10 @@ Attention: the above 7 methods should be the last chainable method.
// SELECT TOP 5 * FROM user // for mssql // SELECT TOP 5 * FROM user // for mssql
// SELECT * FROM user LIMIT .. OFFSET 0 //for other databases // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases
5. Sql, let you custom SQL 5. SQL, let you custom SQL
var users []User var users []User
engine.Sql("select * from user").Find(&users) engine.SQL("select * from user").Find(&users)
6. Cols, Omit, Distinct 6. Cols, Omit, Distinct

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
// Copyright 2015 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"
"regexp"
"github.com/go-xorm/core"
)
// func init() {
// core.RegisterDriver("goracle", &goracleDriver{})
// }
type goracleDriver struct {
}
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}

View File

@ -180,6 +180,20 @@ func isStructZero(v reflect.Value) bool {
return true return true
} }
func isArrayValueZero(v reflect.Value) bool {
if !v.IsValid() || v.Len() == 0 {
return true
}
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i).Interface()) {
return false
}
}
return true
}
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value { func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
var v interface{} var v interface{}
switch tp.Kind() { switch tp.Kind() {

View File

@ -1,65 +0,0 @@
// Copyright 2015 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"
"strings"
"time"
"github.com/go-xorm/core"
)
type mymysqlDriver struct {
}
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.MYSQL}
pd := strings.SplitN(dataSourceName, "*", 2)
if len(pd) == 2 {
// Parse protocol part of URI
p := strings.SplitN(pd[0], ":", 2)
if len(p) != 2 {
return nil, errors.New("Wrong protocol part of URI")
}
db.Proto = p[0]
options := strings.Split(p[1], ",")
db.Raddr = options[0]
for _, o := range options[1:] {
kv := strings.SplitN(o, "=", 2)
var k, v string
if len(kv) == 2 {
k, v = kv[0], kv[1]
} else {
k, v = o, "true"
}
switch k {
case "laddr":
db.Laddr = v
case "timeout":
to, err := time.ParseDuration(v)
if err != nil {
return nil, err
}
db.Timeout = to
default:
return nil, errors.New("Unknown option: " + k)
}
}
// Remove protocol part
pd = pd[1:]
}
// Parse database part of URI
dup := strings.SplitN(pd[0], "/", 3)
if len(dup) != 3 {
return nil, errors.New("Wrong database part of URI")
}
db.DbName = dup[0]
db.User = dup[1]
db.Passwd = dup[2]
return db, nil
}

View File

@ -1,50 +0,0 @@
// Copyright 2015 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 (
"regexp"
"strings"
"github.com/go-xorm/core"
)
type mysqlDriver struct {
}
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
uri := &core.Uri{DbType: core.MYSQL}
for i, match := range matches {
switch names[i] {
case "dbname":
uri.DbName = match
case "params":
if len(match) > 0 {
kvs := strings.Split(match, "&")
for _, kv := range kvs {
splits := strings.Split(kv, "=")
if len(splits) == 2 {
switch splits[0] {
case "charset":
uri.Charset = splits[1]
}
}
}
}
}
}
return uri, nil
}

View File

@ -1,37 +0,0 @@
// Copyright 2015 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"
"regexp"
"github.com/go-xorm/core"
)
type oci8Driver struct {
}
//dataSourceName=user/password@ipv4:port/dbname
//dataSourceName=user/password@[ipv6]:port/dbname
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
`(?P<net>.*)` + // ip:port
`\/(?P<dbname>.*)`) // dbname
matches := dsnPattern.FindStringSubmatch(dataSourceName)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}

View File

@ -1,34 +0,0 @@
// Copyright 2015 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"
"strings"
"github.com/go-xorm/core"
)
type odbcDriver struct {
}
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
kv := strings.Split(dataSourceName, ";")
var dbName string
for _, c := range kv {
vv := strings.Split(strings.TrimSpace(c), "=")
if len(vv) == 2 {
switch strings.ToLower(vv[0]) {
case "database":
dbName = vv[1]
}
}
}
if dbName == "" {
return nil, errors.New("no db name provided")
}
return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
}

View File

@ -1,119 +0,0 @@
// Copyright 2015 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"
"net/url"
"sort"
"strings"
"github.com/go-xorm/core"
)
type pqDriver struct {
}
type values map[string]string
func (vs values) Set(k, v string) {
vs[k] = v
}
func (vs values) Get(k string) (v string) {
return vs[k]
}
func errorf(s string, args ...interface{}) {
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
}
func parseURL(connstr string) (string, error) {
u, err := url.Parse(connstr)
if err != nil {
return "", err
}
if u.Scheme != "postgresql" && u.Scheme != "postgres" {
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
}
var kvs []string
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 != "" {
accrue("dbname", u.Path[1:])
}
q := u.Query()
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) {
if len(name) == 0 {
return
}
name = strings.TrimSpace(name)
ps := strings.Split(name, " ")
for _, p := range ps {
kv := strings.Split(p, "=")
if len(kv) < 2 {
errorf("invalid option: %q", p)
}
o.Set(kv[0], kv[1])
}
}
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.POSTGRES}
o := make(values)
var err error
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
dataSourceName, err = parseURL(dataSourceName)
if err != nil {
return nil, err
}
}
parseOpts(dataSourceName, o)
db.DbName = o.Get("dbname")
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
/*db.Schema = o.Get("schema")
if len(db.Schema) == 0 {
db.Schema = "public"
}*/
return db, nil
}

View File

@ -16,13 +16,12 @@ import (
type Rows struct { type Rows struct {
NoTypeCheck bool NoTypeCheck bool
session *Session session *Session
stmt *core.Stmt stmt *core.Stmt
rows *core.Rows rows *core.Rows
fields []string fields []string
fieldsCount int beanType reflect.Type
beanType reflect.Type lastError error
lastError error
} }
func newRows(session *Session, bean interface{}) (*Rows, error) { func newRows(session *Session, bean interface{}) (*Rows, error) {
@ -82,7 +81,6 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
rows.Close() rows.Close()
return nil, err return nil, err
} }
rows.fieldsCount = len(rows.fields)
return rows, nil return rows, nil
} }
@ -114,7 +112,10 @@ func (rows *Rows) Scan(bean interface{}) error {
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType) return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
} }
_, err := rows.session.row2Bean(rows.rows, rows.fields, rows.fieldsCount, bean) dataStruct := rValue(bean)
rows.session.Statement.setRefValue(dataStruct)
_, err := rows.session.row2Bean(rows.rows, rows.fields, len(rows.fields), bean, &dataStruct, rows.session.Statement.RefTable)
return err return err
} }

File diff suppressed because it is too large Load Diff

84
vendor/github.com/go-xorm/xorm/session_cols.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
// 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
// Incr provides a query string like "count = count + 1"
func (session *Session) Incr(column string, arg ...interface{}) *Session {
session.Statement.Incr(column, arg...)
return session
}
// Decr provides a query string like "count = count - 1"
func (session *Session) Decr(column string, arg ...interface{}) *Session {
session.Statement.Decr(column, arg...)
return session
}
// SetExpr provides a query string like "column = {expression}"
func (session *Session) SetExpr(column string, expression string) *Session {
session.Statement.SetExpr(column, expression)
return session
}
// Select provides some columns to special
func (session *Session) Select(str string) *Session {
session.Statement.Select(str)
return session
}
// Cols provides some columns to special
func (session *Session) Cols(columns ...string) *Session {
session.Statement.Cols(columns...)
return session
}
// AllCols ask all columns
func (session *Session) AllCols() *Session {
session.Statement.AllCols()
return session
}
// MustCols specify some columns must use even if they are empty
func (session *Session) MustCols(columns ...string) *Session {
session.Statement.MustCols(columns...)
return session
}
// UseBool automatically retrieve condition according struct, but
// if struct has bool field, it will ignore them. So use UseBool
// to tell system to do not ignore them.
// If no parameters, it will use all the bool field of struct, or
// it will use parameters's columns
func (session *Session) UseBool(columns ...string) *Session {
session.Statement.UseBool(columns...)
return session
}
// Distinct use for distinct columns. Caution: when you are using cache,
// distinct will not be cached because cache system need id,
// but distinct will not provide id
func (session *Session) Distinct(columns ...string) *Session {
session.Statement.Distinct(columns...)
return session
}
// Omit Only not use the parameters as select or update columns
func (session *Session) Omit(columns ...string) *Session {
session.Statement.Omit(columns...)
return session
}
// Nullable Set null when column is zero-value and nullable for update
func (session *Session) Nullable(columns ...string) *Session {
session.Statement.Nullable(columns...)
return session
}
// NoAutoTime means do not automatically give created field and updated field
// the current time on the current session temporarily
func (session *Session) NoAutoTime() *Session {
session.Statement.UseAutoTime = false
return session
}

70
vendor/github.com/go-xorm/xorm/session_cond.go generated vendored Normal file
View File

@ -0,0 +1,70 @@
// 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/builder"
// 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.
//
// Deprecated: use SQL instead.
func (session *Session) Sql(query string, args ...interface{}) *Session {
return session.SQL(query, args...)
}
// 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.
func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
session.Statement.SQL(query, args...)
return session
}
// Where provides custom query condition.
func (session *Session) Where(query interface{}, args ...interface{}) *Session {
session.Statement.Where(query, args...)
return session
}
// And provides custom query condition.
func (session *Session) And(query interface{}, args ...interface{}) *Session {
session.Statement.And(query, args...)
return session
}
// Or provides custom query condition.
func (session *Session) Or(query interface{}, args ...interface{}) *Session {
session.Statement.Or(query, args...)
return session
}
// Id provides converting id as a query condition
//
// Deprecated: use ID instead
func (session *Session) Id(id interface{}) *Session {
return session.ID(id)
}
// ID provides converting id as a query condition
func (session *Session) ID(id interface{}) *Session {
session.Statement.ID(id)
return session
}
// In provides a query string like "id in (1, 2, 3)"
func (session *Session) In(column string, args ...interface{}) *Session {
session.Statement.In(column, args...)
return session
}
// NotIn provides a query string like "id in (1, 2, 3)"
func (session *Session) NotIn(column string, args ...interface{}) *Session {
session.Statement.NotIn(column, args...)
return session
}
// Conds returns session query conditions
func (session *Session) Conds() builder.Cond {
return session.Statement.cond
}

673
vendor/github.com/go-xorm/xorm/session_convert.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -169,31 +169,43 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
return err return err
} }
var newElemFunc func() reflect.Value var newElemFunc func(fields []string) reflect.Value
elemType := containerValue.Type().Elem() elemType := containerValue.Type().Elem()
var isPointer bool
if elemType.Kind() == reflect.Ptr { if elemType.Kind() == reflect.Ptr {
newElemFunc = func() reflect.Value { isPointer = true
return reflect.New(elemType.Elem()) elemType = elemType.Elem()
} }
} else { if elemType.Kind() == reflect.Ptr {
newElemFunc = func() reflect.Value { return errors.New("pointer to pointer is not supported")
return reflect.New(elemType) }
newElemFunc = func(fields []string) reflect.Value {
switch elemType.Kind() {
case reflect.Slice:
slice := reflect.MakeSlice(elemType, len(fields), len(fields))
x := reflect.New(slice.Type())
x.Elem().Set(slice)
return x
case reflect.Map:
mp := reflect.MakeMap(elemType)
x := reflect.New(mp.Type())
x.Elem().Set(mp)
return x
} }
return reflect.New(elemType)
} }
var containerValueSetFunc func(*reflect.Value, core.PK) error var containerValueSetFunc func(*reflect.Value, core.PK) error
if containerValue.Kind() == reflect.Slice { if containerValue.Kind() == reflect.Slice {
if elemType.Kind() == reflect.Ptr { containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error { if isPointer {
containerValue.Set(reflect.Append(containerValue, reflect.ValueOf(newValue.Interface()))) containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
return nil } else {
} containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
} else {
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
containerValue.Set(reflect.Append(containerValue, reflect.Indirect(reflect.ValueOf(newValue.Interface()))))
return nil
} }
return nil
} }
} else { } else {
keyType := containerValue.Type().Key() keyType := containerValue.Type().Key()
@ -204,40 +216,45 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
return errors.New("don't support multiple primary key's map has non-slice key type") return errors.New("don't support multiple primary key's map has non-slice key type")
} }
if elemType.Kind() == reflect.Ptr { containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error { keyValue := reflect.New(keyType)
keyValue := reflect.New(keyType) err := convertPKToValue(table, keyValue.Interface(), pk)
err := convertPKToValue(table, keyValue.Interface(), pk) if err != nil {
if err != nil { return err
return err
}
containerValue.SetMapIndex(keyValue.Elem(), reflect.ValueOf(newValue.Interface()))
return nil
} }
} else { if isPointer {
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error { containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
keyValue := reflect.New(keyType) } else {
err := convertPKToValue(table, keyValue.Interface(), pk) containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
if err != nil {
return err
}
containerValue.SetMapIndex(keyValue.Elem(), reflect.Indirect(reflect.ValueOf(newValue.Interface())))
return nil
} }
return nil
} }
} }
var newValue = newElemFunc() if elemType.Kind() == reflect.Struct {
dataStruct := rValue(newValue.Interface()) var newValue = newElemFunc(fields)
if dataStruct.Kind() == reflect.Struct { dataStruct := rValue(newValue.Interface())
return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, containerValueSetFunc) tb, err := session.Engine.autoMapType(dataStruct)
if err != nil {
return err
}
return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc)
} }
for rawRows.Next() { for rawRows.Next() {
var newValue = newElemFunc() var newValue = newElemFunc(fields)
bean := newValue.Interface() bean := newValue.Interface()
if err := rawRows.Scan(bean); err != nil { switch elemType.Kind() {
case reflect.Slice:
err = rawRows.ScanSlice(bean)
case reflect.Map:
err = rawRows.ScanMap(bean)
default:
err = rawRows.Scan(bean)
}
if err != nil {
return err return err
} }
@ -394,7 +411,10 @@ 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 := session.Engine.IdOfV(rv) id, err := session.Engine.idOfV(rv)
if err != nil {
return err
}
sid, err := id.ToString() sid, err := id.ToString()
if err != nil { if err != nil {
return err return err

View File

@ -20,7 +20,14 @@ func (session *Session) Get(bean interface{}) (bool, error) {
defer session.Close() defer session.Close()
} }
session.Statement.setRefValue(rValue(bean)) beanValue := reflect.ValueOf(bean)
if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer")
}
if beanValue.Elem().Kind() == reflect.Struct {
session.Statement.setRefValue(beanValue.Elem())
}
var sqlStr string var sqlStr string
var args []interface{} var args []interface{}
@ -36,7 +43,7 @@ func (session *Session) Get(bean interface{}) (bool, error) {
args = session.Statement.RawParams args = session.Statement.RawParams
} }
if session.canCache() { if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil &&
!session.Statement.unscoped { !session.Statement.unscoped {
has, err := session.cacheGet(bean, sqlStr, args...) has, err := session.cacheGet(bean, sqlStr, args...)
@ -46,13 +53,14 @@ func (session *Session) Get(bean interface{}) (bool, error) {
} }
} }
return session.nocacheGet(bean, sqlStr, args...) return session.nocacheGet(beanValue.Elem().Kind(), bean, sqlStr, args...)
} }
func (session *Session) nocacheGet(bean interface{}, sqlStr string, args ...interface{}) (bool, error) { func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
session.queryPreprocess(&sqlStr, args...)
var rawRows *core.Rows var rawRows *core.Rows
var err error var err error
session.queryPreprocess(&sqlStr, args...)
if session.IsAutoCommit { if session.IsAutoCommit {
_, rawRows, err = session.innerQuery(sqlStr, args...) _, rawRows, err = session.innerQuery(sqlStr, args...)
} else { } else {
@ -65,10 +73,24 @@ func (session *Session) nocacheGet(bean interface{}, sqlStr string, args ...inte
defer rawRows.Close() defer rawRows.Close()
if rawRows.Next() { if rawRows.Next() {
fields, err := rawRows.Columns() switch beanKind {
if err == nil { case reflect.Struct:
_, err = session.row2Bean(rawRows, fields, len(fields), bean) fields, err := rawRows.Columns()
if err != nil {
// WARN: Alougth rawRows return true, but get fields failed
return true, err
}
dataStruct := rValue(bean)
session.Statement.setRefValue(dataStruct)
_, err = session.row2Bean(rawRows, fields, len(fields), bean, &dataStruct, session.Statement.RefTable)
case reflect.Slice:
err = rawRows.ScanSlice(bean)
case reflect.Map:
err = rawRows.ScanMap(bean)
default:
err = rawRows.Scan(bean)
} }
return true, err return true, err
} }
return false, nil return false, nil
@ -145,20 +167,8 @@ 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 {
/*newSession := session.Engine.NewSession()
defer newSession.Close()
cacheBean = reflect.New(structValue.Type()).Interface()
newSession.Id(id).NoCache()
if session.Statement.AltTableName != "" {
newSession.Table(session.Statement.AltTableName)
}
if !session.Statement.UseCascade {
newSession.NoCascade()
}
has, err = newSession.Get(cacheBean)
*/
cacheBean = bean cacheBean = bean
has, err = session.nocacheGet(cacheBean, sqlStr, args...) has, err = session.nocacheGet(reflect.Struct, cacheBean, sqlStr, args...)
if err != nil || !has { if err != nil || !has {
return has, err return has, err
} }

View File

@ -210,13 +210,29 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
} }
cleanupProcessorsClosures(&session.beforeClosures) cleanupProcessorsClosures(&session.beforeClosures)
statement := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
session.Engine.Quote(session.Statement.TableName()), var statement string
session.Engine.QuoteStr(), if session.Engine.dialect.DBType() == core.ORACLE {
strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
session.Engine.QuoteStr(), temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
strings.Join(colMultiPlaces, "),(")) session.Engine.Quote(session.Statement.TableName()),
session.Engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
session.Engine.QuoteStr())
statement = fmt.Sprintf(sql,
session.Engine.Quote(session.Statement.TableName()),
session.Engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
session.Engine.QuoteStr(),
strings.Join(colMultiPlaces, temp))
} else {
statement = fmt.Sprintf(sql,
session.Engine.Quote(session.Statement.TableName()),
session.Engine.QuoteStr(),
strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
session.Engine.QuoteStr(),
strings.Join(colMultiPlaces, "),("))
}
res, err := session.exec(statement, args...) res, err := session.exec(statement, args...)
if err != nil { if err != nil {
return 0, err return 0, err
@ -309,8 +325,8 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
// remove the expr columns // remove the expr columns
for i, colName := range colNames { for i, colName := range colNames {
if colName == v.colName { if colName == v.colName {
colNames = append(colNames[:i], colNames[i+1:]...) colNames = append(colNames[:i], colNames[i + 1:]...)
args = append(args[:i], args[i+1:]...) args = append(args[:i], args[i + 1:]...)
} }
} }
@ -319,11 +335,11 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
exprColVals = append(exprColVals, v.expr) exprColVals = append(exprColVals, v.expr)
} }
colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns)) colPlaces := strings.Repeat("?, ", len(colNames) - len(exprColumns))
if len(exprColVals) > 0 { if len(exprColVals) > 0 {
colPlaces = colPlaces + strings.Join(exprColVals, ", ") colPlaces = colPlaces + strings.Join(exprColVals, ", ")
} else { } else {
colPlaces = colPlaces[0 : len(colPlaces)-2] colPlaces = colPlaces[0 : len(colPlaces) - 2]
} }
sqlStr := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", sqlStr := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",

View File

@ -70,7 +70,7 @@ func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map
return rows2maps(rows) return rows2maps(rows)
} }
// Query a raw sql and return records as []map[string][]byte // Query runs a raw sql and return records as []map[string][]byte
func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
defer session.resetStatement() defer session.resetStatement()
if session.IsAutoClose { if session.IsAutoClose {
@ -80,6 +80,15 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl
return session.query(sqlStr, paramStr...) return session.query(sqlStr, paramStr...)
} }
// QueryString runs a raw sql and return records as []map[string]string
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
return session.query2(sqlStr, args...)
}
// ============================= // =============================
// for string // for string
// ============================= // =============================

View File

@ -306,7 +306,10 @@ func (session *Session) Sync2(beans ...interface{}) error {
for _, bean := range beans { for _, bean := range beans {
v := rValue(bean) v := rValue(bean)
table := engine.mapType(v) table, err := engine.mapType(v)
if err != nil {
return err
}
structTables = append(structTables, table) structTables = append(structTables, table)
var tbName = session.tbNameNoSchema(table) var tbName = session.tbNameNoSchema(table)

View File

@ -123,7 +123,7 @@ func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int6
session.queryPreprocess(&sqlStr, args...) session.queryPreprocess(&sqlStr, args...)
var err error var err error
var res = make([]int64, 0, len(columnNames)) var res = make([]int64, len(columnNames), len(columnNames))
if session.IsAutoCommit { if session.IsAutoCommit {
err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res) err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res)
} else { } else {

Some files were not shown because too many files have changed in this diff Show More