浏览代码

vendor: update xorm version for fix git clone error build with golang 1.8.1 (#4460)

peter zhang 7 年之前
父节点
当前提交
10ee2e0dad
共有 36 个文件被更改,包括 2439 次插入1807 次删除
  1. 22 11
      vendor/github.com/go-xorm/xorm/README.md
  2. 21 8
      vendor/github.com/go-xorm/xorm/README_CN.md
  3. 0 1
      vendor/github.com/go-xorm/xorm/VERSION
  4. 336 0
      vendor/github.com/go-xorm/xorm/convert.go
  5. 28 3
      vendor/github.com/go-xorm/xorm/dialect_mssql.go
  6. 92 0
      vendor/github.com/go-xorm/xorm/dialect_mysql.go
  7. 60 0
      vendor/github.com/go-xorm/xorm/dialect_oracle.go
  8. 110 1
      vendor/github.com/go-xorm/xorm/dialect_postgres.go
  9. 10 0
      vendor/github.com/go-xorm/xorm/dialect_sqlite3.go
  10. 31 12
      vendor/github.com/go-xorm/xorm/doc.go
  11. 142 193
      vendor/github.com/go-xorm/xorm/engine.go
  12. 0 42
      vendor/github.com/go-xorm/xorm/goracle_driver.go
  13. 40 23
      vendor/github.com/go-xorm/xorm/helpers.go
  14. 0 65
      vendor/github.com/go-xorm/xorm/mymysql_driver.go
  15. 0 50
      vendor/github.com/go-xorm/xorm/mysql_driver.go
  16. 0 37
      vendor/github.com/go-xorm/xorm/oci8_driver.go
  17. 0 34
      vendor/github.com/go-xorm/xorm/odbc_driver.go
  18. 0 119
      vendor/github.com/go-xorm/xorm/pq_driver.go
  19. 17 10
      vendor/github.com/go-xorm/xorm/rows.go
  20. 114 974
      vendor/github.com/go-xorm/xorm/session.go
  21. 84 0
      vendor/github.com/go-xorm/xorm/session_cols.go
  22. 70 0
      vendor/github.com/go-xorm/xorm/session_cond.go
  23. 673 0
      vendor/github.com/go-xorm/xorm/session_convert.go
  24. 3 1
      vendor/github.com/go-xorm/xorm/session_delete.go
  25. 97 83
      vendor/github.com/go-xorm/xorm/session_find.go
  26. 35 21
      vendor/github.com/go-xorm/xorm/session_get.go
  27. 29 9
      vendor/github.com/go-xorm/xorm/session_insert.go
  28. 14 11
      vendor/github.com/go-xorm/xorm/session_raw.go
  29. 16 5
      vendor/github.com/go-xorm/xorm/session_schema.go
  30. 1 1
      vendor/github.com/go-xorm/xorm/session_sum.go
  31. 42 29
      vendor/github.com/go-xorm/xorm/session_update.go
  32. 0 20
      vendor/github.com/go-xorm/xorm/sqlite3_driver.go
  33. 66 40
      vendor/github.com/go-xorm/xorm/statement.go
  34. 281 0
      vendor/github.com/go-xorm/xorm/tag.go
  35. 2 1
      vendor/github.com/go-xorm/xorm/xorm.go
  36. 3 3
      vendor/vendor.json

+ 22 - 11
vendor/github.com/go-xorm/xorm/README.md

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

+ 21 - 8
vendor/github.com/go-xorm/xorm/README_CN.md

@@ -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来组合使用

+ 0 - 1
vendor/github.com/go-xorm/xorm/VERSION

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

+ 336 - 0
vendor/github.com/go-xorm/xorm/convert.go

@@ -0,0 +1,336 @@
+// 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"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+
+func strconvErr(err error) error {
+	if ne, ok := err.(*strconv.NumError); ok {
+		return ne.Err
+	}
+	return err
+}
+
+func cloneBytes(b []byte) []byte {
+	if b == nil {
+		return nil
+	} else {
+		c := make([]byte, len(b))
+		copy(c, b)
+		return c
+	}
+}
+
+func asString(src interface{}) string {
+	switch v := src.(type) {
+	case string:
+		return v
+	case []byte:
+		return string(v)
+	}
+	rv := reflect.ValueOf(src)
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.FormatInt(rv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.FormatUint(rv.Uint(), 10)
+	case reflect.Float64:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+	case reflect.Float32:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+	case reflect.Bool:
+		return strconv.FormatBool(rv.Bool())
+	}
+	return fmt.Sprintf("%v", src)
+}
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.AppendInt(buf, rv.Int(), 10), true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.AppendUint(buf, rv.Uint(), 10), true
+	case reflect.Float32:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+	case reflect.Float64:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+	case reflect.Bool:
+		return strconv.AppendBool(buf, rv.Bool()), true
+	case reflect.String:
+		s := rv.String()
+		return append(buf, s...), true
+	}
+	return
+}
+
+// convertAssign copies to dest the value in src, converting it if possible.
+// An error is returned if the copy would result in loss of information.
+// dest should be a pointer type.
+func convertAssign(dest, src interface{}) error {
+	// Common cases, without reflect.
+	switch s := src.(type) {
+	case string:
+		switch d := dest.(type) {
+		case *string:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = s
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = []byte(s)
+			return nil
+		}
+	case []byte:
+		switch d := dest.(type) {
+		case *string:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = string(s)
+			return nil
+		case *interface{}:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = cloneBytes(s)
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = cloneBytes(s)
+			return nil
+		}
+
+	case time.Time:
+		switch d := dest.(type) {
+		case *string:
+			*d = s.Format(time.RFC3339Nano)
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = []byte(s.Format(time.RFC3339Nano))
+			return nil
+		}
+	case nil:
+		switch d := dest.(type) {
+		case *interface{}:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = nil
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = nil
+			return nil
+		}
+	}
+
+	var sv reflect.Value
+
+	switch d := dest.(type) {
+	case *string:
+		sv = reflect.ValueOf(src)
+		switch sv.Kind() {
+		case reflect.Bool,
+			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+			reflect.Float32, reflect.Float64:
+			*d = asString(src)
+			return nil
+		}
+	case *[]byte:
+		sv = reflect.ValueOf(src)
+		if b, ok := asBytes(nil, sv); ok {
+			*d = b
+			return nil
+		}
+	case *bool:
+		bv, err := driver.Bool.ConvertValue(src)
+		if err == nil {
+			*d = bv.(bool)
+		}
+		return err
+	case *interface{}:
+		*d = src
+		return nil
+	}
+
+	dpv := reflect.ValueOf(dest)
+	if dpv.Kind() != reflect.Ptr {
+		return errors.New("destination not a pointer")
+	}
+	if dpv.IsNil() {
+		return errNilPtr
+	}
+
+	if !sv.IsValid() {
+		sv = reflect.ValueOf(src)
+	}
+
+	dv := reflect.Indirect(dpv)
+	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
+		switch b := src.(type) {
+		case []byte:
+			dv.Set(reflect.ValueOf(cloneBytes(b)))
+		default:
+			dv.Set(sv)
+		}
+		return nil
+	}
+
+	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
+		dv.Set(sv.Convert(dv.Type()))
+		return nil
+	}
+
+	switch dv.Kind() {
+	case reflect.Ptr:
+		if src == nil {
+			dv.Set(reflect.Zero(dv.Type()))
+			return nil
+		} else {
+			dv.Set(reflect.New(dv.Type().Elem()))
+			return convertAssign(dv.Interface(), src)
+		}
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		s := asString(src)
+		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetInt(i64)
+		return nil
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		s := asString(src)
+		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetUint(u64)
+		return nil
+	case reflect.Float32, reflect.Float64:
+		s := asString(src)
+		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetFloat(f64)
+		return nil
+	case reflect.String:
+		dv.SetString(asString(src))
+		return nil
+	}
+
+	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)
+}
+
+func convertFloat(v interface{}) (float64, error) {
+	switch v.(type) {
+	case float32:
+		return float64(v.(float32)), nil
+	case float64:
+		return v.(float64), nil
+	case string:
+		i, err := strconv.ParseFloat(v.(string), 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	case []byte:
+		i, err := strconv.ParseFloat(string(v.([]byte)), 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	}
+	return 0, fmt.Errorf("unsupported type: %v", v)
+}
+
+func convertInt(v interface{}) (int64, error) {
+	switch v.(type) {
+	case int:
+		return int64(v.(int)), nil
+	case int8:
+		return int64(v.(int8)), nil
+	case int16:
+		return int64(v.(int16)), nil
+	case int32:
+		return int64(v.(int32)), nil
+	case int64:
+		return v.(int64), nil
+	case []byte:
+		i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	case string:
+		i, err := strconv.ParseInt(v.(string), 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	}
+	return 0, fmt.Errorf("unsupported type: %v", v)
+}

+ 28 - 3
vendor/github.com/go-xorm/xorm/mssql_dialect.go → vendor/github.com/go-xorm/xorm/dialect_mssql.go

@@ -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
+}

+ 92 - 0
vendor/github.com/go-xorm/xorm/mysql_dialect.go → vendor/github.com/go-xorm/xorm/dialect_mysql.go

@@ -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
+}

+ 60 - 0
vendor/github.com/go-xorm/xorm/oracle_dialect.go → vendor/github.com/go-xorm/xorm/dialect_oracle.go

@@ -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
+}

+ 110 - 1
vendor/github.com/go-xorm/xorm/postgres_dialect.go → vendor/github.com/go-xorm/xorm/dialect_postgres.go

@@ -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
+}

+ 10 - 0
vendor/github.com/go-xorm/xorm/sqlite3_dialect.go → vendor/github.com/go-xorm/xorm/dialect_sqlite3.go

@@ -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
+}

+ 31 - 12
vendor/github.com/go-xorm/xorm/doc.go

@@ -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)
-    err := engine.Find(sliceOfStructs)
+    var sliceOfStructs []Struct
+    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.
-Attention: the above 7 methods should be the last chainable method.
+The above 8 methods could use with condition methods chainable.
+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
 
 

+ 142 - 193
vendor/github.com/go-xorm/xorm/engine.go

@@ -44,6 +44,8 @@ type Engine struct {
 	DatabaseTZ *time.Location // The timezone of the database
 	DatabaseTZ *time.Location // The timezone of the database
 
 
 	disableGlobalCache bool
 	disableGlobalCache bool
+
+	tagHandlers map[string]tagHandler
 }
 }
 
 
 // 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
@@ -215,10 +217,15 @@ func (engine *Engine) NoCascade() *Session {
 }
 }
 
 
 // MapCacher Set a table use a special cacher
 // MapCacher Set a table use a special cacher
-func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
+func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error {
 	v := rValue(bean)
 	v := rValue(bean)
-	tb := engine.autoMapType(v)
+	tb, err := engine.autoMapType(v)
+	if err != nil {
+		return err
+	}
+
 	tb.Cacher = cacher
 	tb.Cacher = cacher
+	return nil
 }
 }
 
 
 // NewDB provides an interface to operate database directly
 // NewDB provides an interface to operate database directly
@@ -260,9 +267,9 @@ 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 [args] %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)
 		}
 		}
 	}
 	}
 }
 }
@@ -273,9 +280,9 @@ func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executi
 		stmt, res, err := executionBlock()
 		stmt, res, err := executionBlock()
 		execDuration := time.Since(b4ExecTime)
 		execDuration := time.Since(b4ExecTime)
 		if len(args) > 0 {
 		if len(args) > 0 {
-			engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration)
+			engine.logger.Infof("[SQL] %s %v - took: %v", sqlStr, args, execDuration)
 		} else {
 		} else {
-			engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration)
+			engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
 		}
 		}
 		return stmt, res, err
 		return stmt, res, err
 	}
 	}
@@ -774,13 +781,18 @@ func (engine *Engine) Having(conditions string) *Session {
 	return session.Having(conditions)
 	return session.Having(conditions)
 }
 }
 
 
-func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
+func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) {
 	t := v.Type()
 	t := v.Type()
 	engine.mutex.Lock()
 	engine.mutex.Lock()
 	defer engine.mutex.Unlock()
 	defer engine.mutex.Unlock()
 	table, ok := engine.Tables[t]
 	table, ok := engine.Tables[t]
 	if !ok {
 	if !ok {
-		table = engine.mapType(v)
+		var err error
+		table, err = engine.mapType(v)
+		if err != nil {
+			return nil, err
+		}
+
 		engine.Tables[t] = table
 		engine.Tables[t] = table
 		if engine.Cacher != nil {
 		if engine.Cacher != nil {
 			if v.CanAddr() {
 			if v.CanAddr() {
@@ -790,12 +802,11 @@ func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
 			}
 			}
 		}
 		}
 	}
 	}
-	return table
+	return table, nil
 }
 }
 
 
 // GobRegister register one struct to gob for cache use
 // GobRegister register one struct to gob for cache use
 func (engine *Engine) GobRegister(v interface{}) *Engine {
 func (engine *Engine) GobRegister(v interface{}) *Engine {
-	//fmt.Printf("Type: %[1]T => Data: %[1]#v\n", v)
 	gob.Register(v)
 	gob.Register(v)
 	return engine
 	return engine
 }
 }
@@ -806,10 +817,19 @@ type Table struct {
 	Name string
 	Name string
 }
 }
 
 
+// IsValid if table is valid
+func (t *Table) IsValid() bool {
+	return t.Table != nil && len(t.Name) > 0
+}
+
 // TableInfo get table info according to bean's content
 // TableInfo get table info according to bean's content
 func (engine *Engine) TableInfo(bean interface{}) *Table {
 func (engine *Engine) TableInfo(bean interface{}) *Table {
 	v := rValue(bean)
 	v := rValue(bean)
-	return &Table{engine.autoMapType(v), engine.tbName(v)}
+	tb, err := engine.autoMapType(v)
+	if err != nil {
+		engine.logger.Error(err)
+	}
+	return &Table{tb, engine.tbName(v)}
 }
 }
 
 
 func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
 func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
@@ -842,7 +862,7 @@ var (
 	tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
 	tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
 )
 )
 
 
-func (engine *Engine) mapType(v reflect.Value) *core.Table {
+func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
 	t := v.Type()
 	t := v.Type()
 	table := engine.newTable()
 	table := engine.newTable()
 	if tb, ok := v.Interface().(TableName); ok {
 	if tb, ok := v.Interface().(TableName); ok {
@@ -861,7 +881,6 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 	table.Type = t
 	table.Type = t
 
 
 	var idFieldColName string
 	var idFieldColName string
-	var err error
 	var hasCacheTag, hasNoCacheTag bool
 	var hasCacheTag, hasNoCacheTag bool
 
 
 	for i := 0; i < t.NumField(); i++ {
 	for i := 0; i < t.NumField(); i++ {
@@ -881,186 +900,95 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 				if tags[0] == "-" {
 				if tags[0] == "-" {
 					continue
 					continue
 				}
 				}
+
+				var ctx = tagContext{
+					table:      table,
+					col:        col,
+					fieldValue: fieldValue,
+					indexNames: make(map[string]int),
+					engine:     engine,
+				}
+
 				if strings.ToUpper(tags[0]) == "EXTENDS" {
 				if strings.ToUpper(tags[0]) == "EXTENDS" {
-					switch fieldValue.Kind() {
-					case reflect.Ptr:
-						f := fieldValue.Type().Elem()
-						if f.Kind() == reflect.Struct {
-							fieldPtr := fieldValue
-							fieldValue = fieldValue.Elem()
-							if !fieldValue.IsValid() || fieldPtr.IsNil() {
-								fieldValue = reflect.New(f).Elem()
-							}
-						}
-						fallthrough
-					case reflect.Struct:
-						parentTable := engine.mapType(fieldValue)
-						for _, col := range parentTable.Columns() {
-							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
-							table.AddColumn(col)
-							for indexName, indexType := range col.Indexes {
-								addIndex(indexName, table, col, indexType)
-							}
-						}
-						continue
-					default:
-						//TODO: warning
+					if err := ExtendsTagHandler(&ctx); err != nil {
+						return nil, err
 					}
 					}
+					continue
 				}
 				}
 
 
-				indexNames := make(map[string]int)
-				var isIndex, isUnique bool
-				var preKey string
 				for j, key := range tags {
 				for j, key := range tags {
+					if ctx.ignoreNext {
+						ctx.ignoreNext = false
+						continue
+					}
+
 					k := strings.ToUpper(key)
 					k := strings.ToUpper(key)
-					switch {
-					case k == "<-":
-						col.MapType = core.ONLYFROMDB
-					case k == "->":
-						col.MapType = core.ONLYTODB
-					case k == "PK":
-						col.IsPrimaryKey = true
-						col.Nullable = false
-					case k == "NULL":
-						if j == 0 {
-							col.Nullable = true
-						} else {
-							col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT")
-						}
-					// TODO: for postgres how add autoincr?
-					/*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"):
-					col.IsAutoIncrement = true
+					ctx.tagName = k
+					ctx.params = []string{}
 
 
-					autoStart := k[len("AUTOINCR")+1 : len(k)-1]
-					autoStartInt, err := strconv.Atoi(autoStart)
-					if err != nil {
-						engine.LogError(err)
+					pStart := strings.Index(k, "(")
+					if pStart == 0 {
+						return nil, errors.New("( could not be the first charactor")
 					}
 					}
-					col.AutoIncrStart = autoStartInt*/
-					case k == "AUTOINCR":
-						col.IsAutoIncrement = true
-						//col.AutoIncrStart = 1
-					case k == "DEFAULT":
-						col.Default = tags[j+1]
-					case k == "CREATED":
-						col.IsCreated = true
-					case k == "VERSION":
-						col.IsVersion = true
-						col.Default = "1"
-					case k == "UTC":
-						col.TimeZone = time.UTC
-					case k == "LOCAL":
-						col.TimeZone = time.Local
-					case strings.HasPrefix(k, "LOCALE(") && strings.HasSuffix(k, ")"):
-						location := k[len("LOCALE")+1 : len(k)-1]
-						col.TimeZone, err = time.LoadLocation(location)
-						if err != nil {
-							engine.logger.Error(err)
+					if pStart > -1 {
+						if !strings.HasSuffix(k, ")") {
+							return nil, errors.New("cannot match ) charactor")
 						}
 						}
-					case k == "UPDATED":
-						col.IsUpdated = true
-					case k == "DELETED":
-						col.IsDeleted = true
-					case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
-						indexName := k[len("INDEX")+1 : len(k)-1]
-						indexNames[indexName] = core.IndexType
-					case k == "INDEX":
-						isIndex = true
-					case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
-						indexName := k[len("UNIQUE")+1 : len(k)-1]
-						indexNames[indexName] = core.UniqueType
-					case k == "UNIQUE":
-						isUnique = true
-					case k == "NOTNULL":
-						col.Nullable = false
-					case k == "CACHE":
-						if !hasCacheTag {
-							hasCacheTag = true
-						}
-					case k == "NOCACHE":
-						if !hasNoCacheTag {
-							hasNoCacheTag = true
+
+						ctx.tagName = k[:pStart]
+						ctx.params = strings.Split(key[pStart+1:len(k)-1], ",")
+					}
+
+					if j > 0 {
+						ctx.preTag = strings.ToUpper(tags[j-1])
+					}
+					if j < len(tags)-1 {
+						ctx.nextTag = tags[j+1]
+					} else {
+						ctx.nextTag = ""
+					}
+
+					if h, ok := engine.tagHandlers[ctx.tagName]; ok {
+						if err := h(&ctx); err != nil {
+							return nil, err
 						}
 						}
-					case k == "NOT":
-					default:
-						if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") {
-							if preKey != "DEFAULT" {
-								col.Name = key[1 : len(key)-1]
-							}
-						} else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") {
-							fs := strings.Split(k, "(")
-
-							if _, ok := core.SqlTypes[fs[0]]; !ok {
-								preKey = k
-								continue
-							}
-							col.SQLType = core.SQLType{Name: fs[0]}
-							if fs[0] == core.Enum && fs[1][0] == '\'' { //enum
-								options := strings.Split(fs[1][0:len(fs[1])-1], ",")
-								col.EnumOptions = make(map[string]int)
-								for k, v := range options {
-									v = strings.TrimSpace(v)
-									v = strings.Trim(v, "'")
-									col.EnumOptions[v] = k
-								}
-							} else if fs[0] == core.Set && fs[1][0] == '\'' { //set
-								options := strings.Split(fs[1][0:len(fs[1])-1], ",")
-								col.SetOptions = make(map[string]int)
-								for k, v := range options {
-									v = strings.TrimSpace(v)
-									v = strings.Trim(v, "'")
-									col.SetOptions[v] = k
-								}
-							} else {
-								fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",")
-								if len(fs2) == 2 {
-									col.Length, err = strconv.Atoi(fs2[0])
-									if err != nil {
-										engine.logger.Error(err)
-									}
-									col.Length2, err = strconv.Atoi(fs2[1])
-									if err != nil {
-										engine.logger.Error(err)
-									}
-								} else if len(fs2) == 1 {
-									col.Length, err = strconv.Atoi(fs2[0])
-									if err != nil {
-										engine.logger.Error(err)
-									}
-								}
-							}
+					} else {
+						if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") {
+							col.Name = key[1 : len(key)-1]
 						} else {
 						} else {
-							if _, ok := core.SqlTypes[k]; ok {
-								col.SQLType = core.SQLType{Name: k}
-							} else if key != col.Default {
-								col.Name = key
-							}
+							col.Name = key
 						}
 						}
-						engine.dialect.SqlType(col)
 					}
 					}
-					preKey = k
+
+					if ctx.hasCacheTag {
+						hasCacheTag = true
+					}
+					if ctx.hasNoCacheTag {
+						hasNoCacheTag = true
+					}
 				}
 				}
+
 				if col.SQLType.Name == "" {
 				if col.SQLType.Name == "" {
 					col.SQLType = core.Type2SQLType(fieldType)
 					col.SQLType = core.Type2SQLType(fieldType)
 				}
 				}
+				engine.dialect.SqlType(col)
 				if col.Length == 0 {
 				if col.Length == 0 {
 					col.Length = col.SQLType.DefaultLength
 					col.Length = col.SQLType.DefaultLength
 				}
 				}
 				if col.Length2 == 0 {
 				if col.Length2 == 0 {
 					col.Length2 = col.SQLType.DefaultLength2
 					col.Length2 = col.SQLType.DefaultLength2
 				}
 				}
-
 				if col.Name == "" {
 				if col.Name == "" {
 					col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
 					col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
 				}
 				}
 
 
-				if isUnique {
-					indexNames[col.Name] = core.UniqueType
-				} else if isIndex {
-					indexNames[col.Name] = core.IndexType
+				if ctx.isUnique {
+					ctx.indexNames[col.Name] = core.UniqueType
+				} else if ctx.isIndex {
+					ctx.indexNames[col.Name] = core.IndexType
 				}
 				}
 
 
-				for indexName, indexType := range indexNames {
+				for indexName, indexType := range ctx.indexNames {
 					addIndex(indexName, table, col, indexType)
 					addIndex(indexName, table, col, indexType)
 				}
 				}
 			}
 			}
@@ -1114,7 +1042,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 		table.Cacher = nil
 		table.Cacher = nil
 	}
 	}
 
 
-	return table
+	return table, nil
 }
 }
 
 
 // IsTableEmpty if a table has any reocrd
 // IsTableEmpty if a table has any reocrd
@@ -1152,8 +1080,21 @@ func (engine *Engine) IdOfV(rv reflect.Value) core.PK {
 
 
 // IDOfV get id from one value of struct
 // IDOfV get id from one value of struct
 func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
 func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
+	pk, err := engine.idOfV(rv)
+	if err != nil {
+		engine.logger.Error(err)
+		return nil
+	}
+	return pk
+}
+
+func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
 	v := reflect.Indirect(rv)
 	v := reflect.Indirect(rv)
-	table := engine.autoMapType(v)
+	table, err := engine.autoMapType(v)
+	if err != nil {
+		return nil, err
+	}
+
 	pk := make([]interface{}, len(table.PrimaryKeys))
 	pk := make([]interface{}, len(table.PrimaryKeys))
 	for i, col := range table.PKColumns() {
 	for i, col := range table.PKColumns() {
 		pkField := v.FieldByName(col.FieldName)
 		pkField := v.FieldByName(col.FieldName)
@@ -1166,7 +1107,7 @@ func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
 			pk[i] = pkField.Uint()
 			pk[i] = pkField.Uint()
 		}
 		}
 	}
 	}
-	return core.PK(pk)
+	return core.PK(pk), nil
 }
 }
 
 
 // CreateIndexes create indexes
 // CreateIndexes create indexes
@@ -1187,13 +1128,6 @@ func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
 	return table.Cacher
 	return table.Cacher
 }
 }
 
 
-func (engine *Engine) getCacher(v reflect.Value) core.Cacher {
-	if table := engine.autoMapType(v); table != nil {
-		return table.Cacher
-	}
-	return engine.Cacher
-}
-
 // ClearCacheBean if enabled cache, clear the cache bean
 // ClearCacheBean if enabled cache, clear the cache bean
 func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 	v := rValue(bean)
 	v := rValue(bean)
@@ -1202,7 +1136,10 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 		return errors.New("error params")
 		return errors.New("error params")
 	}
 	}
 	tableName := engine.tbName(v)
 	tableName := engine.tbName(v)
-	table := engine.autoMapType(v)
+	table, err := engine.autoMapType(v)
+	if err != nil {
+		return err
+	}
 	cacher := table.Cacher
 	cacher := table.Cacher
 	if cacher == nil {
 	if cacher == nil {
 		cacher = engine.Cacher
 		cacher = engine.Cacher
@@ -1223,7 +1160,11 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
 			return errors.New("error params")
 			return errors.New("error params")
 		}
 		}
 		tableName := engine.tbName(v)
 		tableName := engine.tbName(v)
-		table := engine.autoMapType(v)
+		table, err := engine.autoMapType(v)
+		if err != nil {
+			return err
+		}
+
 		cacher := table.Cacher
 		cacher := table.Cacher
 		if cacher == nil {
 		if cacher == nil {
 			cacher = engine.Cacher
 			cacher = engine.Cacher
@@ -1243,7 +1184,10 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 	for _, bean := range beans {
 	for _, bean := range beans {
 		v := rValue(bean)
 		v := rValue(bean)
 		tableName := engine.tbName(v)
 		tableName := engine.tbName(v)
-		table := engine.autoMapType(v)
+		table, err := engine.autoMapType(v)
+		if err != nil {
+			return err
+		}
 
 
 		s := engine.NewSession()
 		s := engine.NewSession()
 		defer s.Close()
 		defer s.Close()
@@ -1279,8 +1223,10 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 				}
 				}
 				if !isExist {
 				if !isExist {
 					session := engine.NewSession()
 					session := engine.NewSession()
-					session.Statement.setRefValue(v)
 					defer session.Close()
 					defer session.Close()
+					if err := session.Statement.setRefValue(v); err != nil {
+						return err
+					}
 					err = session.addColumn(col.Name)
 					err = session.addColumn(col.Name)
 					if err != nil {
 					if err != nil {
 						return err
 						return err
@@ -1290,8 +1236,10 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 
 
 			for name, index := range table.Indexes {
 			for name, index := range table.Indexes {
 				session := engine.NewSession()
 				session := engine.NewSession()
-				session.Statement.setRefValue(v)
 				defer session.Close()
 				defer session.Close()
+				if err := session.Statement.setRefValue(v); err != nil {
+					return err
+				}
 				if index.Type == core.UniqueType {
 				if index.Type == core.UniqueType {
 					//isExist, err := session.isIndexExist(table.Name, name, true)
 					//isExist, err := session.isIndexExist(table.Name, name, true)
 					isExist, err := session.isIndexExist2(tableName, index.Cols, true)
 					isExist, err := session.isIndexExist2(tableName, index.Cols, true)
@@ -1300,8 +1248,11 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 					}
 					}
 					if !isExist {
 					if !isExist {
 						session := engine.NewSession()
 						session := engine.NewSession()
-						session.Statement.setRefValue(v)
 						defer session.Close()
 						defer session.Close()
+						if err := session.Statement.setRefValue(v); err != nil {
+							return err
+						}
+
 						err = session.addUnique(tableName, name)
 						err = session.addUnique(tableName, name)
 						if err != nil {
 						if err != nil {
 							return err
 							return err
@@ -1314,8 +1265,11 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 					}
 					}
 					if !isExist {
 					if !isExist {
 						session := engine.NewSession()
 						session := engine.NewSession()
-						session.Statement.setRefValue(v)
 						defer session.Close()
 						defer session.Close()
+						if err := session.Statement.setRefValue(v); err != nil {
+							return err
+						}
+
 						err = session.addIndex(tableName, name)
 						err = session.addIndex(tableName, name)
 						if err != nil {
 						if err != nil {
 							return err
 							return err
@@ -1337,18 +1291,6 @@ func (engine *Engine) Sync2(beans ...interface{}) error {
 	return s.Sync2(beans...)
 	return s.Sync2(beans...)
 }
 }
 
 
-func (engine *Engine) unMap(beans ...interface{}) (e error) {
-	engine.mutex.Lock()
-	defer engine.mutex.Unlock()
-	for _, bean := range beans {
-		t := rType(bean)
-		if _, ok := engine.Tables[t]; ok {
-			delete(engine.Tables, t)
-		}
-	}
-	return
-}
-
 // Drop all mapped table
 // Drop all mapped table
 func (engine *Engine) dropAll() error {
 func (engine *Engine) dropAll() error {
 	session := engine.NewSession()
 	session := engine.NewSession()
@@ -1426,6 +1368,13 @@ func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice [
 	return session.Query(sql, paramStr...)
 	return session.Query(sql, paramStr...)
 }
 }
 
 
+// QueryString runs a raw sql and return records as []map[string]string
+func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryString(sqlStr, args...)
+}
+
 // Insert one or more records
 // Insert one or more records
 func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
 func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
 	session := engine.NewSession()
 	session := engine.NewSession()

+ 0 - 42
vendor/github.com/go-xorm/xorm/goracle_driver.go

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

+ 40 - 23
vendor/github.com/go-xorm/xorm/helpers.go

@@ -17,74 +17,83 @@ import (
 )
 )
 
 
 // str2PK convert string value to primary key value according to tp
 // str2PK convert string value to primary key value according to tp
-func str2PK(s string, tp reflect.Type) (interface{}, error) {
+func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
 	var err error
 	var err error
 	var result interface{}
 	var result interface{}
+	var defReturn = reflect.Zero(tp)
+
 	switch tp.Kind() {
 	switch tp.Kind() {
 	case reflect.Int:
 	case reflect.Int:
 		result, err = strconv.Atoi(s)
 		result, err = strconv.Atoi(s)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as int: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
 		}
 		}
 	case reflect.Int8:
 	case reflect.Int8:
 		x, err := strconv.Atoi(s)
 		x, err := strconv.Atoi(s)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as int16: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
 		}
 		}
 		result = int8(x)
 		result = int8(x)
 	case reflect.Int16:
 	case reflect.Int16:
 		x, err := strconv.Atoi(s)
 		x, err := strconv.Atoi(s)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as int16: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
 		}
 		}
 		result = int16(x)
 		result = int16(x)
 	case reflect.Int32:
 	case reflect.Int32:
 		x, err := strconv.Atoi(s)
 		x, err := strconv.Atoi(s)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as int32: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
 		}
 		}
 		result = int32(x)
 		result = int32(x)
 	case reflect.Int64:
 	case reflect.Int64:
 		result, err = strconv.ParseInt(s, 10, 64)
 		result, err = strconv.ParseInt(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as int64: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
 		}
 		}
 	case reflect.Uint:
 	case reflect.Uint:
 		x, err := strconv.ParseUint(s, 10, 64)
 		x, err := strconv.ParseUint(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as uint: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
 		}
 		}
 		result = uint(x)
 		result = uint(x)
 	case reflect.Uint8:
 	case reflect.Uint8:
 		x, err := strconv.ParseUint(s, 10, 64)
 		x, err := strconv.ParseUint(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as uint8: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
 		}
 		}
 		result = uint8(x)
 		result = uint8(x)
 	case reflect.Uint16:
 	case reflect.Uint16:
 		x, err := strconv.ParseUint(s, 10, 64)
 		x, err := strconv.ParseUint(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as uint16: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
 		}
 		}
 		result = uint16(x)
 		result = uint16(x)
 	case reflect.Uint32:
 	case reflect.Uint32:
 		x, err := strconv.ParseUint(s, 10, 64)
 		x, err := strconv.ParseUint(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as uint32: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
 		}
 		}
 		result = uint32(x)
 		result = uint32(x)
 	case reflect.Uint64:
 	case reflect.Uint64:
 		result, err = strconv.ParseUint(s, 10, 64)
 		result, err = strconv.ParseUint(s, 10, 64)
 		if err != nil {
 		if err != nil {
-			return nil, errors.New("convert " + s + " as uint64: " + err.Error())
+			return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
 		}
 		}
 	case reflect.String:
 	case reflect.String:
 		result = s
 		result = s
 	default:
 	default:
-		panic("unsupported convert type")
+		return defReturn, errors.New("unsupported convert type")
 	}
 	}
-	result = reflect.ValueOf(result).Convert(tp).Interface()
-	return result, nil
+	return reflect.ValueOf(result).Convert(tp), nil
+}
+
+func str2PK(s string, tp reflect.Type) (interface{}, error) {
+	v, err := str2PKValue(s, tp)
+	if err != nil {
+		return nil, err
+	}
+	return v.Interface(), nil
 }
 }
 
 
 func splitTag(tag string) (tags []string) {
 func splitTag(tag string) (tags []string) {
@@ -171,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() {
@@ -429,7 +452,7 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string,
 	return result, nil
 	return result, nil
 }
 }
 
 
-func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
+func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) {
 	rows, err := tx.Query(sqlStr, params...)
 	rows, err := tx.Query(sqlStr, params...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -439,13 +462,8 @@ func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice [
 	return rows2Strings(rows)
 	return rows2Strings(rows)
 }
 }
 
 
-func query2(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
-	s, err := db.Prepare(sqlStr)
-	if err != nil {
-		return nil, err
-	}
-	defer s.Close()
-	rows, err := s.Query(params...)
+func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) {
+	rows, err := db.Query(sqlStr, params...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -579,7 +597,6 @@ func indexName(tableName, idxName string) string {
 }
 }
 
 
 func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
 func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
-
 	if len(m) == 0 {
 	if len(m) == 0 {
 		return false, false
 		return false, false
 	}
 	}

+ 0 - 65
vendor/github.com/go-xorm/xorm/mymysql_driver.go

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

+ 0 - 50
vendor/github.com/go-xorm/xorm/mysql_driver.go

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

+ 0 - 37
vendor/github.com/go-xorm/xorm/oci8_driver.go

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

+ 0 - 34
vendor/github.com/go-xorm/xorm/odbc_driver.go

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

+ 0 - 119
vendor/github.com/go-xorm/xorm/pq_driver.go

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

+ 17 - 10
vendor/github.com/go-xorm/xorm/rows.go

@@ -16,13 +16,12 @@ import (
 type Rows struct {
 type Rows struct {
 	NoTypeCheck bool
 	NoTypeCheck bool
 
 
-	session     *Session
-	stmt        *core.Stmt
-	rows        *core.Rows
-	fields      []string
-	fieldsCount int
-	beanType    reflect.Type
-	lastError   error
+	session   *Session
+	stmt      *core.Stmt
+	rows      *core.Rows
+	fields    []string
+	beanType  reflect.Type
+	lastError error
 }
 }
 
 
 func newRows(session *Session, bean interface{}) (*Rows, error) {
 func newRows(session *Session, bean interface{}) (*Rows, error) {
@@ -35,7 +34,10 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 	var sqlStr string
 	var sqlStr string
 	var args []interface{}
 	var args []interface{}
 
 
-	rows.session.Statement.setRefValue(rValue(bean))
+	if err := rows.session.Statement.setRefValue(rValue(bean)); err != nil {
+		return nil, err
+	}
+
 	if len(session.Statement.TableName()) <= 0 {
 	if len(session.Statement.TableName()) <= 0 {
 		return nil, ErrTableNotFound
 		return nil, ErrTableNotFound
 	}
 	}
@@ -82,7 +84,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 +115,13 @@ 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)
 	}
 	}
 
 
-	return rows.session.row2Bean(rows.rows, rows.fields, rows.fieldsCount, bean)
+	dataStruct := rValue(bean)
+	if err := rows.session.Statement.setRefValue(dataStruct); err != nil {
+		return err
+	}
+	_, err := rows.session.row2Bean(rows.rows, rows.fields, len(rows.fields), bean, &dataStruct, rows.session.Statement.RefTable)
+
+	return err
 }
 }
 
 
 // Close session if session.IsAutoClose is true, and claimed any opened resources
 // Close session if session.IsAutoClose is true, and claimed any opened resources

+ 114 - 974
vendor/github.com/go-xorm/xorm/session.go

@@ -6,17 +6,14 @@ package xorm
 
 
 import (
 import (
 	"database/sql"
 	"database/sql"
-	"database/sql/driver"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"hash/crc32"
 	"hash/crc32"
 	"reflect"
 	"reflect"
-	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/go-xorm/builder"
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
 )
 )
 
 
@@ -29,7 +26,6 @@ type Session struct {
 	Statement              Statement
 	Statement              Statement
 	IsAutoCommit           bool
 	IsAutoCommit           bool
 	IsCommitedOrRollbacked bool
 	IsCommitedOrRollbacked bool
-	TransType              string
 	IsAutoClose            bool
 	IsAutoClose            bool
 
 
 	// Automatically reset the statement after operations that execute a SQL
 	// Automatically reset the statement after operations that execute a SQL
@@ -47,7 +43,6 @@ type Session struct {
 
 
 	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))
-	cascadeDeep int
 
 
 	// !evalphobia! stored the last executed query on this session
 	// !evalphobia! stored the last executed query on this session
 	//beforeSQLExec func(string, ...interface{})
 	//beforeSQLExec func(string, ...interface{})
@@ -113,52 +108,6 @@ func (session *Session) Prepare() *Session {
 	return session
 	return session
 }
 }
 
 
-// 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
-}
-
 // Before Apply before Processor, affected bean is passed to closure arg
 // Before Apply before Processor, affected bean is passed to closure arg
 func (session *Session) Before(closures func(interface{})) *Session {
 func (session *Session) Before(closures func(interface{})) *Session {
 	if closures != nil {
 	if closures != nil {
@@ -187,109 +136,18 @@ func (session *Session) Alias(alias string) *Session {
 	return session
 	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
-}
-
-// 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
-}
-
 // 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
 }
 }
 
 
-// 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
-}
-
 // 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
 }
 }
 
 
-// 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
-}
-
 // 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...)
@@ -375,63 +233,12 @@ func (session *Session) DB() *core.DB {
 	return session.db
 	return session.db
 }
 }
 
 
-// Conds returns session query conditions
-func (session *Session) Conds() builder.Cond {
-	return session.Statement.cond
-}
-
 func cleanupProcessorsClosures(slices *[]func(interface{})) {
 func cleanupProcessorsClosures(slices *[]func(interface{})) {
 	if len(*slices) > 0 {
 	if len(*slices) > 0 {
 		*slices = make([]func(interface{}), 0)
 		*slices = make([]func(interface{}), 0)
 	}
 	}
 }
 }
 
 
-func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error {
-	dataStruct := rValue(obj)
-	if dataStruct.Kind() != reflect.Struct {
-		return errors.New("Expected a pointer to a struct")
-	}
-
-	var col *core.Column
-	session.Statement.setRefValue(dataStruct)
-	table := session.Statement.RefTable
-	tableName := session.Statement.tableName
-
-	for key, data := range objMap {
-		if col = table.GetColumn(key); col == nil {
-			session.Engine.logger.Warnf("struct %v's has not field %v. %v",
-				table.Type.Name(), key, table.ColumnsSeq())
-			continue
-		}
-
-		fieldName := col.FieldName
-		fieldPath := strings.Split(fieldName, ".")
-		var fieldValue reflect.Value
-		if len(fieldPath) > 2 {
-			session.Engine.logger.Error("Unsupported mutliderive", fieldName)
-			continue
-		} else if len(fieldPath) == 2 {
-			parentField := dataStruct.FieldByName(fieldPath[0])
-			if parentField.IsValid() {
-				fieldValue = parentField.FieldByName(fieldPath[1])
-			}
-		} else {
-			fieldValue = dataStruct.FieldByName(fieldName)
-		}
-		if !fieldValue.IsValid() || !fieldValue.CanSet() {
-			session.Engine.logger.Warnf("table %v's column %v is not valid or cannot set", tableName, key)
-			continue
-		}
-
-		err := session.bytes2Value(col, &fieldValue, data)
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
 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 != "" ||
@@ -484,40 +291,38 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c
 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, fieldsCount int,
-	table *core.Table, newElemFunc func() reflect.Value,
-	sliceValueSetFunc func(*reflect.Value)) error {
+	table *core.Table, newElemFunc func([]string) reflect.Value,
+	sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
 	for rows.Next() {
 	for rows.Next() {
-		var newValue = newElemFunc()
+		var newValue = newElemFunc(fields)
 		bean := newValue.Interface()
 		bean := newValue.Interface()
 		dataStruct := rValue(bean)
 		dataStruct := rValue(bean)
-		err := session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
+		pk, err := session.row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
+		if err != nil {
+			return err
+		}
+
+		err = sliceValueSetFunc(&newValue, pk)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		sliceValueSetFunc(&newValue)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
-	dataStruct := rValue(bean)
-	if dataStruct.Kind() != reflect.Struct {
-		return errors.New("Expected a pointer to a struct")
+func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
+	// handle beforeClosures
+	for _, closure := range session.beforeClosures {
+		closure(bean)
 	}
 	}
 
 
-	session.Statement.setRefValue(dataStruct)
-
-	return session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, session.Statement.RefTable)
-}
-
-func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error {
 	scanResults := make([]interface{}, fieldsCount)
 	scanResults := make([]interface{}, fieldsCount)
 	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
 	}
 	}
 	if err := rows.Scan(scanResults...); err != nil {
 	if err := rows.Scan(scanResults...); err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
 	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
 	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
@@ -532,9 +337,24 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 				b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
 				b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
 			}
 			}
 		}
 		}
+
+		// handle afterClosures
+		for _, closure := range session.afterClosures {
+			closure(bean)
+		}
 	}()
 	}()
 
 
+	dbTZ := session.Engine.DatabaseTZ
+	if dbTZ == nil {
+		if session.Engine.dialect.DBType() == core.SQLITE {
+			dbTZ = time.UTC
+		} else {
+			dbTZ = time.Local
+		}
+	}
+
 	var tempMap = make(map[string]int)
 	var tempMap = make(map[string]int)
+	var pk core.PK
 	for ii, key := range fields {
 	for ii, key := range fields {
 		var idx int
 		var idx int
 		var ok bool
 		var ok bool
@@ -557,9 +377,11 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 			if fieldValue.CanAddr() {
 			if fieldValue.CanAddr() {
 				if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 				if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 					if data, err := value2Bytes(&rawValue); err == nil {
 					if data, err := value2Bytes(&rawValue); err == nil {
-						structConvert.FromDB(data)
+						if err := structConvert.FromDB(data); err != nil {
+							return nil, err
+						}
 					} else {
 					} else {
-						session.Engine.logger.Error(err)
+						return nil, err
 					}
 					}
 					continue
 					continue
 				}
 				}
@@ -572,17 +394,19 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					}
 					}
 					fieldValue.Interface().(core.Conversion).FromDB(data)
 					fieldValue.Interface().(core.Conversion).FromDB(data)
 				} else {
 				} else {
-					session.Engine.logger.Error(err)
+					return nil, err
 				}
 				}
 				continue
 				continue
 			}
 			}
 
 
 			rawValueType := reflect.TypeOf(rawValue.Interface())
 			rawValueType := reflect.TypeOf(rawValue.Interface())
 			vv := reflect.ValueOf(rawValue.Interface())
 			vv := reflect.ValueOf(rawValue.Interface())
-
+			col := table.GetColumnIdx(key, idx)
+			if col.IsPrimaryKey {
+				pk = append(pk, rawValue.Interface())
+			}
 			fieldType := fieldValue.Type()
 			fieldType := fieldValue.Type()
 			hasAssigned := false
 			hasAssigned := false
-			col := table.GetColumnIdx(key, idx)
 
 
 			if col.SQLType.IsJson() {
 			if col.SQLType.IsJson() {
 				var bs []byte
 				var bs []byte
@@ -591,7 +415,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 				} else if rawValueType.ConvertibleTo(core.BytesType) {
 				} else if rawValueType.ConvertibleTo(core.BytesType) {
 					bs = vv.Bytes()
 					bs = vv.Bytes()
 				} else {
 				} else {
-					return fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
+					return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
 				}
 				}
 
 
 				hasAssigned = true
 				hasAssigned = true
@@ -600,15 +424,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					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 {
-							session.Engine.logger.Error(key, err)
-							return err
+							return nil, err
 						}
 						}
 					} else {
 					} else {
 						x := reflect.New(fieldType)
 						x := reflect.New(fieldType)
 						err := json.Unmarshal(bs, x.Interface())
 						err := json.Unmarshal(bs, x.Interface())
 						if err != nil {
 						if err != nil {
-							session.Engine.logger.Error(key, err)
-							return err
+							return nil, err
 						}
 						}
 						fieldValue.Set(x.Elem())
 						fieldValue.Set(x.Elem())
 					}
 					}
@@ -632,15 +454,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					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 {
-							session.Engine.logger.Error(err)
-							return err
+							return nil, err
 						}
 						}
 					} else {
 					} else {
 						x := reflect.New(fieldType)
 						x := reflect.New(fieldType)
 						err := json.Unmarshal(bs, x.Interface())
 						err := json.Unmarshal(bs, x.Interface())
 						if err != nil {
 						if err != nil {
-							session.Engine.logger.Error(err)
-							return err
+							return nil, err
 						}
 						}
 						fieldValue.Set(x.Elem())
 						fieldValue.Set(x.Elem())
 					}
 					}
@@ -652,7 +472,26 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					case reflect.Uint8:
 					case reflect.Uint8:
 						if fieldType.Elem().Kind() == reflect.Uint8 {
 						if fieldType.Elem().Kind() == reflect.Uint8 {
 							hasAssigned = true
 							hasAssigned = true
-							fieldValue.Set(vv)
+							if col.SQLType.IsText() {
+								x := reflect.New(fieldType)
+								err := json.Unmarshal(vv.Bytes(), x.Interface())
+								if err != nil {
+									return nil, err
+								}
+								fieldValue.Set(x.Elem())
+							} else {
+								if fieldValue.Len() > 0 {
+									for i := 0; i < fieldValue.Len(); i++ {
+										if i < vv.Len() {
+											fieldValue.Index(i).Set(vv.Index(i))
+										}
+									}
+								} else {
+									for i := 0; i < vv.Len(); i++ {
+										fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
+									}
+								}
+							}
 						}
 						}
 					}
 					}
 				}
 				}
@@ -689,21 +528,19 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 				}
 				}
 			case reflect.Struct:
 			case reflect.Struct:
 				if fieldType.ConvertibleTo(core.TimeType) {
 				if fieldType.ConvertibleTo(core.TimeType) {
+					var tz *time.Location
+					if col.TimeZone == nil {
+						tz = session.Engine.TZLocation
+					} else {
+						tz = col.TimeZone
+					}
+
 					if rawValueType == core.TimeType {
 					if rawValueType == core.TimeType {
 						hasAssigned = true
 						hasAssigned = true
 
 
 						t := vv.Convert(core.TimeType).Interface().(time.Time)
 						t := vv.Convert(core.TimeType).Interface().(time.Time)
 
 
 						z, _ := t.Zone()
 						z, _ := t.Zone()
-						dbTZ := session.Engine.DatabaseTZ
-						if dbTZ == nil {
-							if session.Engine.dialect.DBType() == core.SQLITE {
-								dbTZ = time.UTC
-							} else {
-								dbTZ = time.Local
-							}
-						}
-
 						// 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())
@@ -712,27 +549,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 						}
 						}
 
 
 						// !nashtsai! convert to engine location
 						// !nashtsai! convert to engine location
-						if col.TimeZone == nil {
-							t = t.In(session.Engine.TZLocation)
-						} else {
-							t = t.In(col.TimeZone)
-						}
+						t = t.In(tz)
 						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
-
-						// t = fieldValue.Interface().(time.Time)
-						// z, _ = t.Zone()
-						// session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
 					} 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
-						var tz *time.Location
-						if col.TimeZone == nil {
-							tz = session.Engine.TZLocation
-						} else {
-							tz = col.TimeZone
-						}
+
 						t := time.Unix(vv.Int(), 0).In(tz)
 						t := time.Unix(vv.Int(), 0).In(tz)
-						//vv = reflect.ValueOf(t)
 						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 {
@@ -771,8 +594,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 						if len([]byte(vv.String())) > 0 {
 						if len([]byte(vv.String())) > 0 {
 							err := json.Unmarshal([]byte(vv.String()), x.Interface())
 							err := json.Unmarshal([]byte(vv.String()), x.Interface())
 							if err != nil {
 							if err != nil {
-								session.Engine.logger.Error(err)
-								return err
+								return nil, err
 							}
 							}
 							fieldValue.Set(x.Elem())
 							fieldValue.Set(x.Elem())
 						}
 						}
@@ -782,76 +604,47 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 						if len(vv.Bytes()) > 0 {
 						if len(vv.Bytes()) > 0 {
 							err := json.Unmarshal(vv.Bytes(), x.Interface())
 							err := json.Unmarshal(vv.Bytes(), x.Interface())
 							if err != nil {
 							if err != nil {
-								session.Engine.logger.Error(err)
-								return err
+								return nil, err
 							}
 							}
 							fieldValue.Set(x.Elem())
 							fieldValue.Set(x.Elem())
 						}
 						}
 					}
 					}
 				} else if session.Statement.UseCascade {
 				} else if session.Statement.UseCascade {
-					table := session.Engine.autoMapType(*fieldValue)
-					if table != nil {
-						hasAssigned = true
-						if len(table.PrimaryKeys) != 1 {
-							panic("unsupported non or composited primary key cascade")
-						}
-						var pk = make(core.PK, len(table.PrimaryKeys))
-
-						switch rawValueType.Kind() {
-						case reflect.Int64:
-							pk[0] = vv.Int()
-						case reflect.Int:
-							pk[0] = int(vv.Int())
-						case reflect.Int32:
-							pk[0] = int32(vv.Int())
-						case reflect.Int16:
-							pk[0] = int16(vv.Int())
-						case reflect.Int8:
-							pk[0] = int8(vv.Int())
-						case reflect.Uint64:
-							pk[0] = vv.Uint()
-						case reflect.Uint:
-							pk[0] = uint(vv.Uint())
-						case reflect.Uint32:
-							pk[0] = uint32(vv.Uint())
-						case reflect.Uint16:
-							pk[0] = uint16(vv.Uint())
-						case reflect.Uint8:
-							pk[0] = uint8(vv.Uint())
-						case reflect.String:
-							pk[0] = vv.String()
-						case reflect.Slice:
-							pk[0], _ = strconv.ParseInt(string(rawValue.Interface().([]byte)), 10, 64)
-						default:
-							panic(fmt.Sprintf("unsupported primary key type: %v, %v", rawValueType, fieldValue))
-						}
+					table, err := session.Engine.autoMapType(*fieldValue)
+					if err != nil {
+						return nil, err
+					}
 
 
-						if !isPKZero(pk) {
-							// !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
-							// property to be fetched lazily
-							structInter := reflect.New(fieldValue.Type())
-							newsession := session.Engine.NewSession()
-							defer newsession.Close()
-							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-							if err != nil {
-								return err
-							}
-							if has {
-								//v := structInter.Elem().Interface()
-								//fieldValue.Set(reflect.ValueOf(v))
-								fieldValue.Set(structInter.Elem())
-							} else {
-								return errors.New("cascade obj is not exist")
-							}
+					hasAssigned = true
+					if len(table.PrimaryKeys) != 1 {
+						panic("unsupported non or composited primary key cascade")
+					}
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					pk[0], err = asKind(vv, rawValueType)
+					if err != nil {
+						return nil, err
+					}
+
+					if !isPKZero(pk) {
+						// !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
+						// property to be fetched lazily
+						structInter := reflect.New(fieldValue.Type())
+						newsession := session.Engine.NewSession()
+						defer newsession.Close()
+						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+						if err != nil {
+							return nil, err
+						}
+						if has {
+							fieldValue.Set(structInter.Elem())
+						} else {
+							return nil, errors.New("cascade obj is not exist")
 						}
 						}
-					} else {
-						session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String())
 					}
 					}
 				}
 				}
 			case reflect.Ptr:
 			case reflect.Ptr:
 				// !nashtsai! TODO merge duplicated codes above
 				// !nashtsai! TODO merge duplicated codes above
-				//typeStr := fieldType.String()
 				switch fieldType {
 				switch fieldType {
 				// following types case matching ptr's native type, therefore assign ptr directly
 				// following types case matching ptr's native type, therefore assign ptr directly
 				case core.PtrStringType:
 				case core.PtrStringType:
@@ -949,10 +742,9 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					if len([]byte(vv.String())) > 0 {
 					if len([]byte(vv.String())) > 0 {
 						err := json.Unmarshal([]byte(vv.String()), &x)
 						err := json.Unmarshal([]byte(vv.String()), &x)
 						if err != nil {
 						if err != nil {
-							session.Engine.logger.Error(err)
-						} else {
-							fieldValue.Set(reflect.ValueOf(&x))
+							return nil, err
 						}
 						}
+						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 					hasAssigned = true
 					hasAssigned = true
 				case core.Complex128Type:
 				case core.Complex128Type:
@@ -960,29 +752,28 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
 					if len([]byte(vv.String())) > 0 {
 					if len([]byte(vv.String())) > 0 {
 						err := json.Unmarshal([]byte(vv.String()), &x)
 						err := json.Unmarshal([]byte(vv.String()), &x)
 						if err != nil {
 						if err != nil {
-							session.Engine.logger.Error(err)
-						} else {
-							fieldValue.Set(reflect.ValueOf(&x))
+							return nil, err
 						}
 						}
+						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 					hasAssigned = true
 					hasAssigned = true
 				} // switch fieldType
 				} // switch fieldType
-				// default:
-				// 	session.Engine.LogError("unsupported type in Scan: ", reflect.TypeOf(v).String())
 			} // switch fieldType.Kind()
 			} // switch fieldType.Kind()
 
 
 			// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
 			// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
 			if !hasAssigned {
 			if !hasAssigned {
 				data, err := value2Bytes(&rawValue)
 				data, err := value2Bytes(&rawValue)
-				if err == nil {
-					session.bytes2Value(col, fieldValue, data)
-				} else {
-					session.Engine.logger.Error(err.Error())
+				if err != nil {
+					return nil, err
+				}
+
+				if err = session.bytes2Value(col, fieldValue, data); err != nil {
+					return nil, err
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
-	return nil
+	return pk, nil
 }
 }
 
 
 func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
 func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
@@ -993,657 +784,6 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{})
 	session.saveLastSQL(*sqlStr, paramStr...)
 	session.saveLastSQL(*sqlStr, paramStr...)
 }
 }
 
 
-func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
-	sdata := strings.TrimSpace(data)
-	var x time.Time
-	var err error
-
-	if sdata == "0000-00-00 00:00:00" ||
-		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
-		// time stamp
-		sd, err := strconv.ParseInt(sdata, 10, 64)
-		if err == nil {
-			x = time.Unix(sd, 0)
-			// !nashtsai! HACK mymysql driver is causing Local location being change to CHAT and cause wrong time conversion
-			if col.TimeZone == nil {
-				x = x.In(session.Engine.TZLocation)
-			} else {
-				x = x.In(col.TimeZone)
-			}
-			session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-		} else {
-			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, "-") {
-		x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation)
-		session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-		if err != nil {
-			x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation)
-			session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-		}
-		if err != nil {
-			x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation)
-			session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-		}
-
-	} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
-		x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation)
-		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] == '-' {
-		x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation)
-		session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-	} else if col.SQLType.Name == core.Time {
-		if strings.Contains(sdata, " ") {
-			ssd := strings.Split(sdata, " ")
-			sdata = ssd[1]
-		}
-
-		sdata = strings.TrimSpace(sdata)
-		if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
-			sdata = sdata[len(sdata)-8:]
-		}
-
-		st := fmt.Sprintf("2006-01-02 %v", sdata)
-		x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
-		session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
-	} else {
-		outErr = fmt.Errorf("unsupported time format %v", sdata)
-		return
-	}
-	if err != nil {
-		outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
-		return
-	}
-	outTime = x
-	return
-}
-
-func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
-	return session.str2Time(col, string(data))
-}
-
-// convert a db data([]byte) to a field value
-func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
-	if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
-		return structConvert.FromDB(data)
-	}
-
-	if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
-		return structConvert.FromDB(data)
-	}
-
-	var v interface{}
-	key := col.Name
-	fieldType := fieldValue.Type()
-
-	switch fieldType.Kind() {
-	case reflect.Complex64, reflect.Complex128:
-		x := reflect.New(fieldType)
-		if len(data) > 0 {
-			err := json.Unmarshal(data, x.Interface())
-			if err != nil {
-				session.Engine.logger.Error(err)
-				return err
-			}
-			fieldValue.Set(x.Elem())
-		}
-	case reflect.Slice, reflect.Array, reflect.Map:
-		v = data
-		t := fieldType.Elem()
-		k := t.Kind()
-		if col.SQLType.IsText() {
-			x := reflect.New(fieldType)
-			if len(data) > 0 {
-				err := json.Unmarshal(data, x.Interface())
-				if err != nil {
-					session.Engine.logger.Error(err)
-					return err
-				}
-				fieldValue.Set(x.Elem())
-			}
-		} else if col.SQLType.IsBlob() {
-			if k == reflect.Uint8 {
-				fieldValue.Set(reflect.ValueOf(v))
-			} else {
-				x := reflect.New(fieldType)
-				if len(data) > 0 {
-					err := json.Unmarshal(data, x.Interface())
-					if err != nil {
-						session.Engine.logger.Error(err)
-						return err
-					}
-					fieldValue.Set(x.Elem())
-				}
-			}
-		} else {
-			return ErrUnSupportedType
-		}
-	case reflect.String:
-		fieldValue.SetString(string(data))
-	case reflect.Bool:
-		d := string(data)
-		v, err := strconv.ParseBool(d)
-		if err != nil {
-			return fmt.Errorf("arg %v as bool: %s", key, err.Error())
-		}
-		fieldValue.Set(reflect.ValueOf(v))
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		sdata := string(data)
-		var x int64
-		var err error
-		// for mysql, when use bit, it returned \x01
-		if col.SQLType.Name == core.Bit &&
-			session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
-			if len(data) == 1 {
-				x = int64(data[0])
-			} else {
-				x = 0
-			}
-		} else if strings.HasPrefix(sdata, "0x") {
-			x, err = strconv.ParseInt(sdata, 16, 64)
-		} else if strings.HasPrefix(sdata, "0") {
-			x, err = strconv.ParseInt(sdata, 8, 64)
-		} else if strings.EqualFold(sdata, "true") {
-			x = 1
-		} else if strings.EqualFold(sdata, "false") {
-			x = 0
-		} else {
-			x, err = strconv.ParseInt(sdata, 10, 64)
-		}
-		if err != nil {
-			return fmt.Errorf("arg %v as int: %s", key, err.Error())
-		}
-		fieldValue.SetInt(x)
-	case reflect.Float32, reflect.Float64:
-		x, err := strconv.ParseFloat(string(data), 64)
-		if err != nil {
-			return fmt.Errorf("arg %v as float64: %s", key, err.Error())
-		}
-		fieldValue.SetFloat(x)
-	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
-		x, err := strconv.ParseUint(string(data), 10, 64)
-		if err != nil {
-			return fmt.Errorf("arg %v as int: %s", key, err.Error())
-		}
-		fieldValue.SetUint(x)
-	//Currently only support Time type
-	case reflect.Struct:
-		// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
-		if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
-			if err := nulVal.Scan(data); err != nil {
-				return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
-			}
-		} else {
-			if fieldType.ConvertibleTo(core.TimeType) {
-				x, err := session.byte2Time(col, data)
-				if err != nil {
-					return err
-				}
-				v = x
-				fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
-			} else if session.Statement.UseCascade {
-				table := session.Engine.autoMapType(*fieldValue)
-				if table != nil {
-					// TODO: current only support 1 primary key
-					if len(table.PrimaryKeys) > 1 {
-						panic("unsupported composited primary key cascade")
-					}
-					var pk = make(core.PK, len(table.PrimaryKeys))
-					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
-					var err error
-					pk[0], err = str2PK(string(data), rawValueType)
-					if err != nil {
-						return err
-					}
-
-					if !isPKZero(pk) {
-						// !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
-						// property to be fetched lazily
-						structInter := reflect.New(fieldValue.Type())
-						newsession := session.Engine.NewSession()
-						defer newsession.Close()
-						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-						if err != nil {
-							return err
-						}
-						if has {
-							v = structInter.Elem().Interface()
-							fieldValue.Set(reflect.ValueOf(v))
-						} else {
-							return errors.New("cascade obj is not exist")
-						}
-					}
-				} else {
-					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
-				}
-			}
-		}
-	case reflect.Ptr:
-		// !nashtsai! TODO merge duplicated codes above
-		//typeStr := fieldType.String()
-		switch fieldType.Elem().Kind() {
-		// case "*string":
-		case core.StringType.Kind():
-			x := string(data)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*bool":
-		case core.BoolType.Kind():
-			d := string(data)
-			v, err := strconv.ParseBool(d)
-			if err != nil {
-				return fmt.Errorf("arg %v as bool: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
-		// case "*complex64":
-		case core.Complex64Type.Kind():
-			var x complex64
-			if len(data) > 0 {
-				err := json.Unmarshal(data, &x)
-				if err != nil {
-					session.Engine.logger.Error(err)
-					return err
-				}
-				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-			}
-		// case "*complex128":
-		case core.Complex128Type.Kind():
-			var x complex128
-			if len(data) > 0 {
-				err := json.Unmarshal(data, &x)
-				if err != nil {
-					session.Engine.logger.Error(err)
-					return err
-				}
-				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-			}
-		// case "*float64":
-		case core.Float64Type.Kind():
-			x, err := strconv.ParseFloat(string(data), 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as float64: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*float32":
-		case core.Float32Type.Kind():
-			var x float32
-			x1, err := strconv.ParseFloat(string(data), 32)
-			if err != nil {
-				return fmt.Errorf("arg %v as float32: %s", key, err.Error())
-			}
-			x = float32(x1)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*uint64":
-		case core.Uint64Type.Kind():
-			var x uint64
-			x, err := strconv.ParseUint(string(data), 10, 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*uint":
-		case core.UintType.Kind():
-			var x uint
-			x1, err := strconv.ParseUint(string(data), 10, 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			x = uint(x1)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*uint32":
-		case core.Uint32Type.Kind():
-			var x uint32
-			x1, err := strconv.ParseUint(string(data), 10, 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			x = uint32(x1)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*uint8":
-		case core.Uint8Type.Kind():
-			var x uint8
-			x1, err := strconv.ParseUint(string(data), 10, 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			x = uint8(x1)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*uint16":
-		case core.Uint16Type.Kind():
-			var x uint16
-			x1, err := strconv.ParseUint(string(data), 10, 64)
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			x = uint16(x1)
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*int64":
-		case core.Int64Type.Kind():
-			sdata := string(data)
-			var x int64
-			var err error
-			// for mysql, when use bit, it returned \x01
-			if col.SQLType.Name == core.Bit &&
-				strings.Contains(session.Engine.DriverName(), "mysql") {
-				if len(data) == 1 {
-					x = int64(data[0])
-				} else {
-					x = 0
-				}
-			} else if strings.HasPrefix(sdata, "0x") {
-				x, err = strconv.ParseInt(sdata, 16, 64)
-			} else if strings.HasPrefix(sdata, "0") {
-				x, err = strconv.ParseInt(sdata, 8, 64)
-			} else {
-				x, err = strconv.ParseInt(sdata, 10, 64)
-			}
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*int":
-		case core.IntType.Kind():
-			sdata := string(data)
-			var x int
-			var x1 int64
-			var err error
-			// for mysql, when use bit, it returned \x01
-			if col.SQLType.Name == core.Bit &&
-				strings.Contains(session.Engine.DriverName(), "mysql") {
-				if len(data) == 1 {
-					x = int(data[0])
-				} else {
-					x = 0
-				}
-			} else if strings.HasPrefix(sdata, "0x") {
-				x1, err = strconv.ParseInt(sdata, 16, 64)
-				x = int(x1)
-			} else if strings.HasPrefix(sdata, "0") {
-				x1, err = strconv.ParseInt(sdata, 8, 64)
-				x = int(x1)
-			} else {
-				x1, err = strconv.ParseInt(sdata, 10, 64)
-				x = int(x1)
-			}
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*int32":
-		case core.Int32Type.Kind():
-			sdata := string(data)
-			var x int32
-			var x1 int64
-			var err error
-			// for mysql, when use bit, it returned \x01
-			if col.SQLType.Name == core.Bit &&
-				session.Engine.dialect.DBType() == core.MYSQL {
-				if len(data) == 1 {
-					x = int32(data[0])
-				} else {
-					x = 0
-				}
-			} else if strings.HasPrefix(sdata, "0x") {
-				x1, err = strconv.ParseInt(sdata, 16, 64)
-				x = int32(x1)
-			} else if strings.HasPrefix(sdata, "0") {
-				x1, err = strconv.ParseInt(sdata, 8, 64)
-				x = int32(x1)
-			} else {
-				x1, err = strconv.ParseInt(sdata, 10, 64)
-				x = int32(x1)
-			}
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*int8":
-		case core.Int8Type.Kind():
-			sdata := string(data)
-			var x int8
-			var x1 int64
-			var err error
-			// for mysql, when use bit, it returned \x01
-			if col.SQLType.Name == core.Bit &&
-				strings.Contains(session.Engine.DriverName(), "mysql") {
-				if len(data) == 1 {
-					x = int8(data[0])
-				} else {
-					x = 0
-				}
-			} else if strings.HasPrefix(sdata, "0x") {
-				x1, err = strconv.ParseInt(sdata, 16, 64)
-				x = int8(x1)
-			} else if strings.HasPrefix(sdata, "0") {
-				x1, err = strconv.ParseInt(sdata, 8, 64)
-				x = int8(x1)
-			} else {
-				x1, err = strconv.ParseInt(sdata, 10, 64)
-				x = int8(x1)
-			}
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*int16":
-		case core.Int16Type.Kind():
-			sdata := string(data)
-			var x int16
-			var x1 int64
-			var err error
-			// for mysql, when use bit, it returned \x01
-			if col.SQLType.Name == core.Bit &&
-				strings.Contains(session.Engine.DriverName(), "mysql") {
-				if len(data) == 1 {
-					x = int16(data[0])
-				} else {
-					x = 0
-				}
-			} else if strings.HasPrefix(sdata, "0x") {
-				x1, err = strconv.ParseInt(sdata, 16, 64)
-				x = int16(x1)
-			} else if strings.HasPrefix(sdata, "0") {
-				x1, err = strconv.ParseInt(sdata, 8, 64)
-				x = int16(x1)
-			} else {
-				x1, err = strconv.ParseInt(sdata, 10, 64)
-				x = int16(x1)
-			}
-			if err != nil {
-				return fmt.Errorf("arg %v as int: %s", key, err.Error())
-			}
-			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
-		// case "*SomeStruct":
-		case reflect.Struct:
-			switch fieldType {
-			// case "*.time.Time":
-			case core.PtrTimeType:
-				x, err := session.byte2Time(col, data)
-				if err != nil {
-					return err
-				}
-				v = x
-				fieldValue.Set(reflect.ValueOf(&x))
-			default:
-				if session.Statement.UseCascade {
-					structInter := reflect.New(fieldType.Elem())
-					table := session.Engine.autoMapType(structInter.Elem())
-					if table != nil {
-						if len(table.PrimaryKeys) > 1 {
-							panic("unsupported composited primary key cascade")
-						}
-						var pk = make(core.PK, len(table.PrimaryKeys))
-						var err error
-						rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
-						pk[0], err = str2PK(string(data), rawValueType)
-						if err != nil {
-							return err
-						}
-
-						if !isPKZero(pk) {
-							// !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
-							// property to be fetched lazily
-							newsession := session.Engine.NewSession()
-							defer newsession.Close()
-							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-							if err != nil {
-								return err
-							}
-							if has {
-								v = structInter.Interface()
-								fieldValue.Set(reflect.ValueOf(v))
-							} else {
-								return errors.New("cascade obj is not exist")
-							}
-						}
-					}
-				} else {
-					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
-				}
-			}
-		default:
-			return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
-		}
-	default:
-		return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
-	}
-
-	return nil
-}
-
-// convert a field value of a struct to interface for put into db
-func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
-	if fieldValue.CanAddr() {
-		if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
-			data, err := fieldConvert.ToDB()
-			if err != nil {
-				return 0, err
-			}
-			if col.SQLType.IsBlob() {
-				return data, nil
-			}
-			return string(data), nil
-		}
-	}
-
-	if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
-		data, err := fieldConvert.ToDB()
-		if err != nil {
-			return 0, err
-		}
-		if col.SQLType.IsBlob() {
-			return data, nil
-		}
-		return string(data), nil
-	}
-
-	fieldType := fieldValue.Type()
-	k := fieldType.Kind()
-	if k == reflect.Ptr {
-		if fieldValue.IsNil() {
-			return nil, nil
-		} else if !fieldValue.IsValid() {
-			session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid")
-			return nil, nil
-		} else {
-			// !nashtsai! deference pointer type to instance type
-			fieldValue = fieldValue.Elem()
-			fieldType = fieldValue.Type()
-			k = fieldType.Kind()
-		}
-	}
-
-	switch k {
-	case reflect.Bool:
-		return fieldValue.Bool(), nil
-	case reflect.String:
-		return fieldValue.String(), nil
-	case reflect.Struct:
-		if fieldType.ConvertibleTo(core.TimeType) {
-			t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
-			if session.Engine.dialect.DBType() == core.MSSQL {
-				if t.IsZero() {
-					return nil, nil
-				}
-			}
-			tf := session.Engine.FormatTime(col.SQLType.Name, t)
-			return tf, nil
-		}
-
-		if !col.SQLType.IsJson() {
-			// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
-			if v, ok := fieldValue.Interface().(driver.Valuer); ok {
-				return v.Value()
-			}
-
-			fieldTable := session.Engine.autoMapType(fieldValue)
-			if len(fieldTable.PrimaryKeys) == 1 {
-				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
-				return pkField.Interface(), nil
-			}
-			return 0, fmt.Errorf("no primary key for col %v", col.Name)
-		}
-
-		if col.SQLType.IsText() {
-			bytes, err := json.Marshal(fieldValue.Interface())
-			if err != nil {
-				session.Engine.logger.Error(err)
-				return 0, err
-			}
-			return string(bytes), nil
-		} else if col.SQLType.IsBlob() {
-			bytes, err := json.Marshal(fieldValue.Interface())
-			if err != nil {
-				session.Engine.logger.Error(err)
-				return 0, err
-			}
-			return bytes, nil
-		}
-		return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
-	case reflect.Complex64, reflect.Complex128:
-		bytes, err := json.Marshal(fieldValue.Interface())
-		if err != nil {
-			session.Engine.logger.Error(err)
-			return 0, err
-		}
-		return string(bytes), nil
-	case reflect.Array, reflect.Slice, reflect.Map:
-		if !fieldValue.IsValid() {
-			return fieldValue.Interface(), nil
-		}
-
-		if col.SQLType.IsText() {
-			bytes, err := json.Marshal(fieldValue.Interface())
-			if err != nil {
-				session.Engine.logger.Error(err)
-				return 0, err
-			}
-			return string(bytes), nil
-		} else if col.SQLType.IsBlob() {
-			var bytes []byte
-			var err error
-			if (k == reflect.Array || k == reflect.Slice) &&
-				(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
-				bytes = fieldValue.Bytes()
-			} else {
-				bytes, err = json.Marshal(fieldValue.Interface())
-				if err != nil {
-					session.Engine.logger.Error(err)
-					return 0, err
-				}
-			}
-			return bytes, nil
-		}
-		return nil, ErrUnSupportedType
-	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
-		return int64(fieldValue.Uint()), nil
-	default:
-		return fieldValue.Interface(), nil
-	}
-}
-
 // 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

+ 84 - 0
vendor/github.com/go-xorm/xorm/session_cols.go

@@ -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 - 0
vendor/github.com/go-xorm/xorm/session_cond.go

@@ -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 - 0
vendor/github.com/go-xorm/xorm/session_convert.go

@@ -0,0 +1,673 @@
+// 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"
+	"database/sql/driver"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-xorm/core"
+)
+
+func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
+	sdata := strings.TrimSpace(data)
+	var x time.Time
+	var err error
+
+	if sdata == "0000-00-00 00:00:00" ||
+		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
+		// time stamp
+		sd, err := strconv.ParseInt(sdata, 10, 64)
+		if err == nil {
+			x = time.Unix(sd, 0)
+			// !nashtsai! HACK mymysql driver is causing Local location being change to CHAT and cause wrong time conversion
+			if col.TimeZone == nil {
+				x = x.In(session.Engine.TZLocation)
+			} else {
+				x = x.In(col.TimeZone)
+			}
+			session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		} else {
+			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, "-") {
+		x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation)
+		session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		if err != nil {
+			x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation)
+			session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		}
+		if err != nil {
+			x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation)
+			session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		}
+
+	} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
+		x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation)
+		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] == '-' {
+		x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation)
+		session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+	} else if col.SQLType.Name == core.Time {
+		if strings.Contains(sdata, " ") {
+			ssd := strings.Split(sdata, " ")
+			sdata = ssd[1]
+		}
+
+		sdata = strings.TrimSpace(sdata)
+		if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
+			sdata = sdata[len(sdata)-8:]
+		}
+
+		st := fmt.Sprintf("2006-01-02 %v", sdata)
+		x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
+		session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+	} else {
+		outErr = fmt.Errorf("unsupported time format %v", sdata)
+		return
+	}
+	if err != nil {
+		outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
+		return
+	}
+	outTime = x
+	return
+}
+
+func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
+	return session.str2Time(col, string(data))
+}
+
+// convert a db data([]byte) to a field value
+func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
+	if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+		return structConvert.FromDB(data)
+	}
+
+	if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
+		return structConvert.FromDB(data)
+	}
+
+	var v interface{}
+	key := col.Name
+	fieldType := fieldValue.Type()
+
+	switch fieldType.Kind() {
+	case reflect.Complex64, reflect.Complex128:
+		x := reflect.New(fieldType)
+		if len(data) > 0 {
+			err := json.Unmarshal(data, x.Interface())
+			if err != nil {
+				session.Engine.logger.Error(err)
+				return err
+			}
+			fieldValue.Set(x.Elem())
+		}
+	case reflect.Slice, reflect.Array, reflect.Map:
+		v = data
+		t := fieldType.Elem()
+		k := t.Kind()
+		if col.SQLType.IsText() {
+			x := reflect.New(fieldType)
+			if len(data) > 0 {
+				err := json.Unmarshal(data, x.Interface())
+				if err != nil {
+					session.Engine.logger.Error(err)
+					return err
+				}
+				fieldValue.Set(x.Elem())
+			}
+		} else if col.SQLType.IsBlob() {
+			if k == reflect.Uint8 {
+				fieldValue.Set(reflect.ValueOf(v))
+			} else {
+				x := reflect.New(fieldType)
+				if len(data) > 0 {
+					err := json.Unmarshal(data, x.Interface())
+					if err != nil {
+						session.Engine.logger.Error(err)
+						return err
+					}
+					fieldValue.Set(x.Elem())
+				}
+			}
+		} else {
+			return ErrUnSupportedType
+		}
+	case reflect.String:
+		fieldValue.SetString(string(data))
+	case reflect.Bool:
+		d := string(data)
+		v, err := strconv.ParseBool(d)
+		if err != nil {
+			return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+		}
+		fieldValue.Set(reflect.ValueOf(v))
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		sdata := string(data)
+		var x int64
+		var err error
+		// for mysql, when use bit, it returned \x01
+		if col.SQLType.Name == core.Bit &&
+			session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
+			if len(data) == 1 {
+				x = int64(data[0])
+			} else {
+				x = 0
+			}
+		} else if strings.HasPrefix(sdata, "0x") {
+			x, err = strconv.ParseInt(sdata, 16, 64)
+		} else if strings.HasPrefix(sdata, "0") {
+			x, err = strconv.ParseInt(sdata, 8, 64)
+		} else if strings.EqualFold(sdata, "true") {
+			x = 1
+		} else if strings.EqualFold(sdata, "false") {
+			x = 0
+		} else {
+			x, err = strconv.ParseInt(sdata, 10, 64)
+		}
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetInt(x)
+	case reflect.Float32, reflect.Float64:
+		x, err := strconv.ParseFloat(string(data), 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+		}
+		fieldValue.SetFloat(x)
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+		x, err := strconv.ParseUint(string(data), 10, 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetUint(x)
+	//Currently only support Time type
+	case reflect.Struct:
+		// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
+		if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
+			if err := nulVal.Scan(data); err != nil {
+				return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
+			}
+		} else {
+			if fieldType.ConvertibleTo(core.TimeType) {
+				x, err := session.byte2Time(col, data)
+				if err != nil {
+					return err
+				}
+				v = x
+				fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
+			} else if session.Statement.UseCascade {
+				table, err := session.Engine.autoMapType(*fieldValue)
+				if err != nil {
+					return err
+				}
+
+				// TODO: current only support 1 primary key
+				if len(table.PrimaryKeys) > 1 {
+					panic("unsupported composited primary key cascade")
+				}
+				var pk = make(core.PK, len(table.PrimaryKeys))
+				rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+				pk[0], err = str2PK(string(data), rawValueType)
+				if err != nil {
+					return err
+				}
+
+				if !isPKZero(pk) {
+					// !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
+					// property to be fetched lazily
+					structInter := reflect.New(fieldValue.Type())
+					newsession := session.Engine.NewSession()
+					defer newsession.Close()
+					has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+					if err != nil {
+						return err
+					}
+					if has {
+						v = structInter.Elem().Interface()
+						fieldValue.Set(reflect.ValueOf(v))
+					} else {
+						return errors.New("cascade obj is not exist")
+					}
+				}
+			}
+		}
+	case reflect.Ptr:
+		// !nashtsai! TODO merge duplicated codes above
+		//typeStr := fieldType.String()
+		switch fieldType.Elem().Kind() {
+		// case "*string":
+		case core.StringType.Kind():
+			x := string(data)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*bool":
+		case core.BoolType.Kind():
+			d := string(data)
+			v, err := strconv.ParseBool(d)
+			if err != nil {
+				return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
+		// case "*complex64":
+		case core.Complex64Type.Kind():
+			var x complex64
+			if len(data) > 0 {
+				err := json.Unmarshal(data, &x)
+				if err != nil {
+					session.Engine.logger.Error(err)
+					return err
+				}
+				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+			}
+		// case "*complex128":
+		case core.Complex128Type.Kind():
+			var x complex128
+			if len(data) > 0 {
+				err := json.Unmarshal(data, &x)
+				if err != nil {
+					session.Engine.logger.Error(err)
+					return err
+				}
+				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+			}
+		// case "*float64":
+		case core.Float64Type.Kind():
+			x, err := strconv.ParseFloat(string(data), 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*float32":
+		case core.Float32Type.Kind():
+			var x float32
+			x1, err := strconv.ParseFloat(string(data), 32)
+			if err != nil {
+				return fmt.Errorf("arg %v as float32: %s", key, err.Error())
+			}
+			x = float32(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint64":
+		case core.Uint64Type.Kind():
+			var x uint64
+			x, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint":
+		case core.UintType.Kind():
+			var x uint
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint32":
+		case core.Uint32Type.Kind():
+			var x uint32
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint32(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint8":
+		case core.Uint8Type.Kind():
+			var x uint8
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint8(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint16":
+		case core.Uint16Type.Kind():
+			var x uint16
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint16(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int64":
+		case core.Int64Type.Kind():
+			sdata := string(data)
+			var x int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int64(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x, err = strconv.ParseInt(sdata, 16, 64)
+			} else if strings.HasPrefix(sdata, "0") {
+				x, err = strconv.ParseInt(sdata, 8, 64)
+			} else {
+				x, err = strconv.ParseInt(sdata, 10, 64)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int":
+		case core.IntType.Kind():
+			sdata := string(data)
+			var x int
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int32":
+		case core.Int32Type.Kind():
+			sdata := string(data)
+			var x int32
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				session.Engine.dialect.DBType() == core.MYSQL {
+				if len(data) == 1 {
+					x = int32(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int32(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int32(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int32(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int8":
+		case core.Int8Type.Kind():
+			sdata := string(data)
+			var x int8
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int8(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int8(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int8(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int8(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int16":
+		case core.Int16Type.Kind():
+			sdata := string(data)
+			var x int16
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int16(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int16(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int16(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int16(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*SomeStruct":
+		case reflect.Struct:
+			switch fieldType {
+			// case "*.time.Time":
+			case core.PtrTimeType:
+				x, err := session.byte2Time(col, data)
+				if err != nil {
+					return err
+				}
+				v = x
+				fieldValue.Set(reflect.ValueOf(&x))
+			default:
+				if session.Statement.UseCascade {
+					structInter := reflect.New(fieldType.Elem())
+					table, err := session.Engine.autoMapType(structInter.Elem())
+					if err != nil {
+						return err
+					}
+
+					if len(table.PrimaryKeys) > 1 {
+						panic("unsupported composited primary key cascade")
+					}
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+					pk[0], err = str2PK(string(data), rawValueType)
+					if err != nil {
+						return err
+					}
+
+					if !isPKZero(pk) {
+						// !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
+						// property to be fetched lazily
+						newsession := session.Engine.NewSession()
+						defer newsession.Close()
+						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+						if err != nil {
+							return err
+						}
+						if has {
+							v = structInter.Interface()
+							fieldValue.Set(reflect.ValueOf(v))
+						} else {
+							return errors.New("cascade obj is not exist")
+						}
+					}
+				} else {
+					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
+				}
+			}
+		default:
+			return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
+		}
+	default:
+		return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
+	}
+
+	return nil
+}
+
+// convert a field value of a struct to interface for put into db
+func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
+	if fieldValue.CanAddr() {
+		if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+			data, err := fieldConvert.ToDB()
+			if err != nil {
+				return 0, err
+			}
+			if col.SQLType.IsBlob() {
+				return data, nil
+			}
+			return string(data), nil
+		}
+	}
+
+	if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
+		data, err := fieldConvert.ToDB()
+		if err != nil {
+			return 0, err
+		}
+		if col.SQLType.IsBlob() {
+			return data, nil
+		}
+		return string(data), nil
+	}
+
+	fieldType := fieldValue.Type()
+	k := fieldType.Kind()
+	if k == reflect.Ptr {
+		if fieldValue.IsNil() {
+			return nil, nil
+		} else if !fieldValue.IsValid() {
+			session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid")
+			return nil, nil
+		} else {
+			// !nashtsai! deference pointer type to instance type
+			fieldValue = fieldValue.Elem()
+			fieldType = fieldValue.Type()
+			k = fieldType.Kind()
+		}
+	}
+
+	switch k {
+	case reflect.Bool:
+		return fieldValue.Bool(), nil
+	case reflect.String:
+		return fieldValue.String(), nil
+	case reflect.Struct:
+		if fieldType.ConvertibleTo(core.TimeType) {
+			t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
+			if session.Engine.dialect.DBType() == core.MSSQL {
+				if t.IsZero() {
+					return nil, nil
+				}
+			}
+			tf := session.Engine.FormatTime(col.SQLType.Name, t)
+			return tf, nil
+		}
+
+		if !col.SQLType.IsJson() {
+			// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
+			if v, ok := fieldValue.Interface().(driver.Valuer); ok {
+				return v.Value()
+			}
+
+			fieldTable, err := session.Engine.autoMapType(fieldValue)
+			if err != nil {
+				return nil, err
+			}
+			if len(fieldTable.PrimaryKeys) == 1 {
+				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
+				return pkField.Interface(), nil
+			}
+			return 0, fmt.Errorf("no primary key for col %v", col.Name)
+		}
+
+		if col.SQLType.IsText() {
+			bytes, err := json.Marshal(fieldValue.Interface())
+			if err != nil {
+				session.Engine.logger.Error(err)
+				return 0, err
+			}
+			return string(bytes), nil
+		} else if col.SQLType.IsBlob() {
+			bytes, err := json.Marshal(fieldValue.Interface())
+			if err != nil {
+				session.Engine.logger.Error(err)
+				return 0, err
+			}
+			return bytes, nil
+		}
+		return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
+	case reflect.Complex64, reflect.Complex128:
+		bytes, err := json.Marshal(fieldValue.Interface())
+		if err != nil {
+			session.Engine.logger.Error(err)
+			return 0, err
+		}
+		return string(bytes), nil
+	case reflect.Array, reflect.Slice, reflect.Map:
+		if !fieldValue.IsValid() {
+			return fieldValue.Interface(), nil
+		}
+
+		if col.SQLType.IsText() {
+			bytes, err := json.Marshal(fieldValue.Interface())
+			if err != nil {
+				session.Engine.logger.Error(err)
+				return 0, err
+			}
+			return string(bytes), nil
+		} else if col.SQLType.IsBlob() {
+			var bytes []byte
+			var err error
+			if (k == reflect.Array || k == reflect.Slice) &&
+				(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
+				bytes = fieldValue.Bytes()
+			} else {
+				bytes, err = json.Marshal(fieldValue.Interface())
+				if err != nil {
+					session.Engine.logger.Error(err)
+					return 0, err
+				}
+			}
+			return bytes, nil
+		}
+		return nil, ErrUnSupportedType
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+		return int64(fieldValue.Uint()), nil
+	default:
+		return fieldValue.Interface(), nil
+	}
+}

+ 3 - 1
vendor/github.com/go-xorm/xorm/session_delete.go

@@ -83,7 +83,9 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
 		defer session.Close()
 		defer session.Close()
 	}
 	}
 
 
-	session.Statement.setRefValue(rValue(bean))
+	if err := session.Statement.setRefValue(rValue(bean)); err != nil {
+		return 0, err
+	}
 	var table = session.Statement.RefTable
 	var table = session.Statement.RefTable
 
 
 	// handle before delete processors
 	// handle before delete processors

+ 97 - 83
vendor/github.com/go-xorm/xorm/session_find.go

@@ -41,16 +41,18 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
 		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())
-				session.Statement.setRefValue(pv.Elem())
+				if err := session.Statement.setRefValue(pv.Elem()); err != nil {
+					return err
+				}
 			} else {
 			} else {
-				//return errors.New("slice type")
 				tp = tpNonStruct
 				tp = tpNonStruct
 			}
 			}
 		} else if sliceElementType.Kind() == reflect.Struct {
 		} else if sliceElementType.Kind() == reflect.Struct {
 			pv := reflect.New(sliceElementType)
 			pv := reflect.New(sliceElementType)
-			session.Statement.setRefValue(pv.Elem())
+			if err := session.Statement.setRefValue(pv.Elem()); err != nil {
+				return err
+			}
 		} else {
 		} else {
-			//return errors.New("slice type")
 			tp = tpNonStruct
 			tp = tpNonStruct
 		}
 		}
 	}
 	}
@@ -148,62 +150,10 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
 		}
 		}
 	}
 	}
 
 
-	if sliceValue.Kind() != reflect.Map {
-		return session.noCacheFind(sliceValue, sqlStr, args...)
-	}
-
-	resultsSlice, err := session.query(sqlStr, args...)
-	if err != nil {
-		return err
-	}
-
-	keyType := sliceValue.Type().Key()
-
-	for _, results := range resultsSlice {
-		var newValue reflect.Value
-		if sliceElementType.Kind() == reflect.Ptr {
-			newValue = reflect.New(sliceElementType.Elem())
-		} else {
-			newValue = reflect.New(sliceElementType)
-		}
-		err := session.scanMapIntoStruct(newValue.Interface(), results)
-		if err != nil {
-			return err
-		}
-		var key interface{}
-		// if there is only one pk, we can put the id as map key.
-		if len(table.PrimaryKeys) == 1 {
-			key, err = str2PK(string(results[table.PrimaryKeys[0]]), keyType)
-			if err != nil {
-				return err
-			}
-		} else {
-			if keyType.Kind() != reflect.Slice {
-				panic("don't support multiple primary key's map has non-slice key type")
-			} else {
-				var keys core.PK = make([]interface{}, 0, len(table.PrimaryKeys))
-				for _, pk := range table.PrimaryKeys {
-					skey, err := str2PK(string(results[pk]), keyType)
-					if err != nil {
-						return err
-					}
-					keys = append(keys, skey)
-				}
-				key = keys
-			}
-		}
-
-		if sliceElementType.Kind() == reflect.Ptr {
-			sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(newValue.Interface()))
-		} else {
-			sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.Indirect(reflect.ValueOf(newValue.Interface())))
-		}
-	}
-
-	return nil
+	return session.noCacheFind(table, sliceValue, sqlStr, args...)
 }
 }
 
 
-func (session *Session) noCacheFind(sliceValue 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
 	var rawRows *core.Rows
 	var err error
 	var err error
 
 
@@ -223,51 +173,112 @@ func (session *Session) noCacheFind(sliceValue reflect.Value, sqlStr string, arg
 		return err
 		return err
 	}
 	}
 
 
-	var newElemFunc func() reflect.Value
-	sliceElementType := sliceValue.Type().Elem()
-	if sliceElementType.Kind() == reflect.Ptr {
-		newElemFunc = func() reflect.Value {
-			return reflect.New(sliceElementType.Elem())
-		}
-	} else {
-		newElemFunc = func() reflect.Value {
-			return reflect.New(sliceElementType)
+	var newElemFunc func(fields []string) reflect.Value
+	elemType := containerValue.Type().Elem()
+	var isPointer bool
+	if elemType.Kind() == reflect.Ptr {
+		isPointer = true
+		elemType = elemType.Elem()
+	}
+	if elemType.Kind() == reflect.Ptr {
+		return errors.New("pointer to pointer is not supported")
+	}
+
+	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 sliceValueSetFunc func(*reflect.Value)
+	var containerValueSetFunc func(*reflect.Value, core.PK) error
 
 
-	if sliceValue.Kind() == reflect.Slice {
-		if sliceElementType.Kind() == reflect.Ptr {
-			sliceValueSetFunc = func(newValue *reflect.Value) {
-				sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(newValue.Interface())))
+	if containerValue.Kind() == reflect.Slice {
+		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
+			if isPointer {
+				containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
+			} else {
+				containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
 			}
 			}
-		} else {
-			sliceValueSetFunc = func(newValue *reflect.Value) {
-				sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface()))))
+			return nil
+		}
+	} else {
+		keyType := containerValue.Type().Key()
+		if len(table.PrimaryKeys) == 0 {
+			return errors.New("don't support multiple primary key's map has non-slice key type")
+		}
+		if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
+			return errors.New("don't support multiple primary key's map has non-slice key type")
+		}
+
+		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
+			keyValue := reflect.New(keyType)
+			err := convertPKToValue(table, keyValue.Interface(), pk)
+			if err != nil {
+				return err
 			}
 			}
+			if isPointer {
+				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
+			} else {
+				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
+			}
+			return nil
 		}
 		}
 	}
 	}
 
 
-	var newValue = newElemFunc()
-	dataStruct := rValue(newValue.Interface())
-	if dataStruct.Kind() == reflect.Struct {
-		return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, sliceValueSetFunc)
+	if elemType.Kind() == reflect.Struct {
+		var newValue = newElemFunc(fields)
+		dataStruct := rValue(newValue.Interface())
+		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
 		}
 		}
 
 
-		sliceValueSetFunc(&newValue)
+		if err := containerValueSetFunc(&newValue, nil); err != nil {
+			return err
+		}
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
+func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
+	cols := table.PKColumns()
+	if len(cols) == 1 {
+		return convertAssign(dst, pk[0])
+	}
+
+	dst = pk
+	return nil
+}
+
 func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
 func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
 	if !session.canCache() ||
 	if !session.canCache() ||
 		indexNoCase(sqlStr, "having") != -1 ||
 		indexNoCase(sqlStr, "having") != -1 ||
@@ -404,7 +415,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

+ 35 - 21
vendor/github.com/go-xorm/xorm/session_get.go

@@ -20,7 +20,16 @@ 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 {
+		if err := session.Statement.setRefValue(beanValue.Elem()); err != nil {
+			return false, err
+		}
+	}
 
 
 	var sqlStr string
 	var sqlStr string
 	var args []interface{}
 	var args []interface{}
@@ -36,7 +45,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 +55,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 +75,26 @@ 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()
-		if err == nil {
-			err = session.row2Bean(rawRows, fields, len(fields), bean)
+		switch beanKind {
+		case reflect.Struct:
+			fields, err := rawRows.Columns()
+			if err != nil {
+				// WARN: Alougth rawRows return true, but get fields failed
+				return true, err
+			}
+			dataStruct := rValue(bean)
+			if err := session.Statement.setRefValue(dataStruct); err != nil {
+				return false, err
+			}
+			_, 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 +171,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
 			}
 			}

+ 29 - 9
vendor/github.com/go-xorm/xorm/session_insert.go

@@ -67,7 +67,9 @@ 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")
 	}
 	}
 
 
-	session.Statement.setRefValue(sliceValue.Index(0))
+	if err := session.Statement.setRefValue(sliceValue.Index(0)); err != nil {
+		return 0, err
+	}
 
 
 	if len(session.Statement.TableName()) <= 0 {
 	if len(session.Statement.TableName()) <= 0 {
 		return 0, ErrTableNotFound
 		return 0, ErrTableNotFound
@@ -210,13 +212,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)",
-		session.Engine.Quote(session.Statement.TableName()),
-		session.Engine.QuoteStr(),
-		strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()),
-		session.Engine.QuoteStr(),
-		strings.Join(colMultiPlaces, "),("))
-
+	var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
+	var statement string
+	if session.Engine.dialect.DBType() == core.ORACLE {
+		sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
+		temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
+			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
@@ -281,7 +299,9 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
 }
 }
 
 
 func (session *Session) innerInsert(bean interface{}) (int64, error) {
 func (session *Session) innerInsert(bean interface{}) (int64, error) {
-	session.Statement.setRefValue(rValue(bean))
+	if err := session.Statement.setRefValue(rValue(bean)); err != nil {
+		return 0, err
+	}
 	if len(session.Statement.TableName()) <= 0 {
 	if len(session.Statement.TableName()) <= 0 {
 		return 0, ErrTableNotFound
 		return 0, ErrTableNotFound
 	}
 	}

+ 14 - 11
vendor/github.com/go-xorm/xorm/session_raw.go

@@ -10,7 +10,7 @@ import (
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
 )
 )
 
 
-func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+func (session *Session) query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) {
 	session.queryPreprocess(&sqlStr, paramStr...)
 	session.queryPreprocess(&sqlStr, paramStr...)
 
 
 	if session.IsAutoCommit {
 	if session.IsAutoCommit {
@@ -19,7 +19,7 @@ func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSl
 	return session.txQuery(session.Tx, sqlStr, paramStr...)
 	return session.txQuery(session.Tx, sqlStr, paramStr...)
 }
 }
 
 
-func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) {
+func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
 	rows, err := tx.Query(sqlStr, params...)
 	rows, err := tx.Query(sqlStr, params...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -70,8 +70,8 @@ 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
-func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+// 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()
 	defer session.resetStatement()
 	if session.IsAutoClose {
 	if session.IsAutoClose {
 		defer session.Close()
 		defer session.Close()
@@ -80,16 +80,19 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl
 	return session.query(sqlStr, paramStr...)
 	return session.query(sqlStr, paramStr...)
 }
 }
 
 
-// =============================
-// for string
-// =============================
-func (session *Session) query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) {
-	session.queryPreprocess(&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()
+	}
+
+	session.queryPreprocess(&sqlStr, args...)
 
 
 	if session.IsAutoCommit {
 	if session.IsAutoCommit {
-		return query2(session.DB(), sqlStr, paramStr...)
+		return query2(session.DB(), sqlStr, args...)
 	}
 	}
-	return txQuery2(session.Tx, sqlStr, paramStr...)
+	return txQuery2(session.Tx, sqlStr, args...)
 }
 }
 
 
 // Execute sql
 // Execute sql

+ 16 - 5
vendor/github.com/go-xorm/xorm/session_schema.go

@@ -27,7 +27,9 @@ func (session *Session) Ping() error {
 // 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 {
 	v := rValue(bean)
 	v := rValue(bean)
-	session.Statement.setRefValue(v)
+	if err := session.Statement.setRefValue(v); err != nil {
+		return err
+	}
 
 
 	defer session.resetStatement()
 	defer session.resetStatement()
 	if session.IsAutoClose {
 	if session.IsAutoClose {
@@ -40,7 +42,9 @@ func (session *Session) CreateTable(bean interface{}) error {
 // CreateIndexes create indexes
 // CreateIndexes create indexes
 func (session *Session) CreateIndexes(bean interface{}) error {
 func (session *Session) CreateIndexes(bean interface{}) error {
 	v := rValue(bean)
 	v := rValue(bean)
-	session.Statement.setRefValue(v)
+	if err := session.Statement.setRefValue(v); err != nil {
+		return err
+	}
 
 
 	defer session.resetStatement()
 	defer session.resetStatement()
 	if session.IsAutoClose {
 	if session.IsAutoClose {
@@ -60,7 +64,9 @@ 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)
 	v := rValue(bean)
-	session.Statement.setRefValue(v)
+	if err := session.Statement.setRefValue(v); err != nil {
+		return err
+	}
 
 
 	defer session.resetStatement()
 	defer session.resetStatement()
 	if session.IsAutoClose {
 	if session.IsAutoClose {
@@ -104,7 +110,9 @@ func (session *Session) createAll() error {
 // DropIndexes drop indexes
 // DropIndexes drop indexes
 func (session *Session) DropIndexes(bean interface{}) error {
 func (session *Session) DropIndexes(bean interface{}) error {
 	v := rValue(bean)
 	v := rValue(bean)
-	session.Statement.setRefValue(v)
+	if err := session.Statement.setRefValue(v); err != nil {
+		return err
+	}
 
 
 	defer session.resetStatement()
 	defer session.resetStatement()
 	if session.IsAutoClose {
 	if session.IsAutoClose {
@@ -306,7 +314,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)
 
 

+ 1 - 1
vendor/github.com/go-xorm/xorm/session_sum.go

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

+ 42 - 29
vendor/github.com/go-xorm/xorm/session_update.go

@@ -169,7 +169,9 @@ 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 {
-		session.Statement.setRefValue(v)
+		if err := session.Statement.setRefValue(v); err != nil {
+			return 0, err
+		}
 
 
 		if len(session.Statement.TableName()) <= 0 {
 		if len(session.Statement.TableName()) <= 0 {
 			return 0, ErrTableNotFound
 			return 0, ErrTableNotFound
@@ -253,48 +255,59 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 	var condSQL string
 	var condSQL string
 	cond := session.Statement.cond.And(autoCond)
 	cond := session.Statement.cond.And(autoCond)
 
 
-	doIncVer := false
+	var doIncVer = (table != nil && table.Version != "" && session.Statement.checkVersion)
 	var verValue *reflect.Value
 	var verValue *reflect.Value
-	if table != nil && table.Version != "" && session.Statement.checkVersion {
+	if doIncVer {
 		verValue, err = table.VersionColumn().ValueOf(bean)
 		verValue, err = table.VersionColumn().ValueOf(bean)
 		if err != nil {
 		if err != nil {
 			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()})
-		condSQL, condArgs, _ = builder.ToSQL(cond)
-
-		if len(condSQL) > 0 {
-			condSQL = "WHERE " + condSQL
-		}
-
-		if st.LimitN > 0 {
-			condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
-		}
+		colNames = append(colNames, session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1")
+	}
 
 
-		sqlStr = fmt.Sprintf("UPDATE %v SET %v, %v %v",
-			session.Engine.Quote(session.Statement.TableName()),
-			strings.Join(colNames, ", "),
-			session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1",
-			condSQL)
+	condSQL, condArgs, _ = builder.ToSQL(cond)
+	if len(condSQL) > 0 {
+		condSQL = "WHERE " + condSQL
+	}
 
 
-		doIncVer = true
-	} else {
-		condSQL, condArgs, _ = builder.ToSQL(cond)
-		if len(condSQL) > 0 {
-			condSQL = "WHERE " + condSQL
-		}
+	if st.OrderStr != "" {
+		condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
+	}
 
 
-		if st.LimitN > 0 {
+	// TODO: Oracle support needed
+	var top string
+	if st.LimitN > 0 {
+		if st.Engine.dialect.DBType() == core.MYSQL {
 			condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
 			condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+		} else if st.Engine.dialect.DBType() == core.SQLITE {
+			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+			cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",
+				session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...))
+			condSQL, condArgs, _ = builder.ToSQL(cond)
+			if len(condSQL) > 0 {
+				condSQL = "WHERE " + condSQL
+			}
+		} else if st.Engine.dialect.DBType() == core.POSTGRES {
+			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+			cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
+				session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...))
+			condSQL, condArgs, _ = builder.ToSQL(cond)
+			if len(condSQL) > 0 {
+				condSQL = "WHERE " + condSQL
+			}
+		} else if st.Engine.dialect.DBType() == core.MSSQL {
+			top = fmt.Sprintf("top (%d) ", st.LimitN)
 		}
 		}
-
-		sqlStr = fmt.Sprintf("UPDATE %v SET %v %v",
-			session.Engine.Quote(session.Statement.TableName()),
-			strings.Join(colNames, ", "),
-			condSQL)
 	}
 	}
 
 
+	sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v",
+		top,
+		session.Engine.Quote(session.Statement.TableName()),
+		strings.Join(colNames, ", "),
+		condSQL)
+
 	res, err := session.exec(sqlStr, append(args, condArgs...)...)
 	res, err := session.exec(sqlStr, append(args, condArgs...)...)
 	if err != nil {
 	if err != nil {
 		return 0, err
 		return 0, err

+ 0 - 20
vendor/github.com/go-xorm/xorm/sqlite3_driver.go

@@ -1,20 +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 (
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("sqlite3", &sqlite3Driver{})
-// }
-
-type sqlite3Driver struct {
-}
-
-func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
-}

+ 66 - 40
vendor/github.com/go-xorm/xorm/statement.go

@@ -39,7 +39,7 @@ type Statement struct {
 	Engine          *Engine
 	Engine          *Engine
 	Start           int
 	Start           int
 	LimitN          int
 	LimitN          int
-	IdParam         *core.PK
+	idParam         *core.PK
 	OrderStr        string
 	OrderStr        string
 	JoinStr         string
 	JoinStr         string
 	joinArgs        []interface{}
 	joinArgs        []interface{}
@@ -91,7 +91,7 @@ func (statement *Statement) Init() {
 	statement.columnMap = make(map[string]bool)
 	statement.columnMap = make(map[string]bool)
 	statement.AltTableName = ""
 	statement.AltTableName = ""
 	statement.tableName = ""
 	statement.tableName = ""
-	statement.IdParam = nil
+	statement.idParam = nil
 	statement.RawSQL = ""
 	statement.RawSQL = ""
 	statement.RawParams = make([]interface{}, 0)
 	statement.RawParams = make([]interface{}, 0)
 	statement.UseCache = true
 	statement.UseCache = true
@@ -195,29 +195,26 @@ func (statement *Statement) Or(query interface{}, args ...interface{}) *Statemen
 
 
 // In generate "Where column IN (?) " statement
 // In generate "Where column IN (?) " statement
 func (statement *Statement) In(column string, args ...interface{}) *Statement {
 func (statement *Statement) In(column string, args ...interface{}) *Statement {
-	if len(args) == 0 {
-		return statement
-	}
-
-	in := builder.In(column, args...)
+	in := builder.In(statement.Engine.Quote(column), args...)
 	statement.cond = statement.cond.And(in)
 	statement.cond = statement.cond.And(in)
 	return statement
 	return statement
 }
 }
 
 
 // NotIn generate "Where column NOT IN (?) " statement
 // NotIn generate "Where column NOT IN (?) " statement
 func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
 func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
-	if len(args) == 0 {
-		return statement
-	}
-
-	in := builder.NotIn(column, args...)
-	statement.cond = statement.cond.And(in)
+	notIn := builder.NotIn(statement.Engine.Quote(column), args...)
+	statement.cond = statement.cond.And(notIn)
 	return statement
 	return statement
 }
 }
 
 
-func (statement *Statement) setRefValue(v reflect.Value) {
-	statement.RefTable = statement.Engine.autoMapType(reflect.Indirect(v))
+func (statement *Statement) setRefValue(v reflect.Value) error {
+	var err error
+	statement.RefTable, err = statement.Engine.autoMapType(reflect.Indirect(v))
+	if err != nil {
+		return err
+	}
 	statement.tableName = statement.Engine.tbName(v)
 	statement.tableName = statement.Engine.tbName(v)
+	return nil
 }
 }
 
 
 // Table tempororily set table name, the parameter could be a string or a pointer of struct
 // Table tempororily set table name, the parameter could be a string or a pointer of struct
@@ -227,7 +224,12 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
 	if t.Kind() == reflect.String {
 	if t.Kind() == reflect.String {
 		statement.AltTableName = tableNameOrBean.(string)
 		statement.AltTableName = tableNameOrBean.(string)
 	} else if t.Kind() == reflect.Struct {
 	} else if t.Kind() == reflect.Struct {
-		statement.RefTable = statement.Engine.autoMapType(v)
+		var err error
+		statement.RefTable, err = statement.Engine.autoMapType(v)
+		if err != nil {
+			statement.Engine.logger.Error(err)
+			return statement
+		}
 		statement.AltTableName = statement.Engine.tbName(v)
 		statement.AltTableName = statement.Engine.tbName(v)
 	}
 	}
 	return statement
 	return statement
@@ -418,7 +420,11 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 				if fieldValue == reflect.Zero(fieldType) {
 				if fieldValue == reflect.Zero(fieldType) {
 					continue
 					continue
 				}
 				}
-				if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
+				if fieldType.Kind() == reflect.Array {
+					if isArrayValueZero(fieldValue) {
+						continue
+					}
+				} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
 					continue
 					continue
 				}
 				}
 			}
 			}
@@ -433,13 +439,16 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 			} else if col.SQLType.IsBlob() {
 			} else if col.SQLType.IsBlob() {
 				var bytes []byte
 				var bytes []byte
 				var err error
 				var err error
-				if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
+				if fieldType.Kind() == reflect.Slice &&
 					fieldType.Elem().Kind() == reflect.Uint8 {
 					fieldType.Elem().Kind() == reflect.Uint8 {
 					if fieldValue.Len() > 0 {
 					if fieldValue.Len() > 0 {
 						val = fieldValue.Bytes()
 						val = fieldValue.Bytes()
 					} else {
 					} else {
 						continue
 						continue
 					}
 					}
+				} else if fieldType.Kind() == reflect.Array &&
+					fieldType.Elem().Kind() == reflect.Uint8 {
+					val = fieldValue.Slice(0, 0).Interface()
 				} else {
 				} else {
 					bytes, err = json.Marshal(fieldValue.Interface())
 					bytes, err = json.Marshal(fieldValue.Interface())
 					if err != nil {
 					if err != nil {
@@ -651,7 +660,9 @@ func buildConds(engine *Engine, table *core.Table, bean interface{},
 					}
 					}
 				}
 				}
 			}
 			}
-		case reflect.Array, reflect.Slice, reflect.Map:
+		case reflect.Array:
+			continue
+		case reflect.Slice, reflect.Map:
 			if fieldValue == reflect.Zero(fieldType) {
 			if fieldValue == reflect.Zero(fieldType) {
 				continue
 				continue
 			}
 			}
@@ -706,13 +717,6 @@ func (statement *Statement) TableName() string {
 	return statement.tableName
 	return statement.tableName
 }
 }
 
 
-// Id generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
-//
-// Deprecated: use ID instead
-func (statement *Statement) Id(id interface{}) *Statement {
-	return statement.ID(id)
-}
-
 // ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
 // ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
 func (statement *Statement) ID(id interface{}) *Statement {
 func (statement *Statement) ID(id interface{}) *Statement {
 	idValue := reflect.ValueOf(id)
 	idValue := reflect.ValueOf(id)
@@ -721,23 +725,23 @@ func (statement *Statement) ID(id interface{}) *Statement {
 	switch idType {
 	switch idType {
 	case ptrPkType:
 	case ptrPkType:
 		if pkPtr, ok := (id).(*core.PK); ok {
 		if pkPtr, ok := (id).(*core.PK); ok {
-			statement.IdParam = pkPtr
+			statement.idParam = pkPtr
 			return statement
 			return statement
 		}
 		}
 	case pkType:
 	case pkType:
 		if pk, ok := (id).(core.PK); ok {
 		if pk, ok := (id).(core.PK); ok {
-			statement.IdParam = &pk
+			statement.idParam = &pk
 			return statement
 			return statement
 		}
 		}
 	}
 	}
 
 
 	switch idType.Kind() {
 	switch idType.Kind() {
 	case reflect.String:
 	case reflect.String:
-		statement.IdParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()}
+		statement.idParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()}
 		return statement
 		return statement
 	}
 	}
 
 
-	statement.IdParam = &core.PK{id}
+	statement.idParam = &core.PK{id}
 	return statement
 	return statement
 }
 }
 
 
@@ -1120,7 +1124,11 @@ func (statement *Statement) genConds(bean interface{}) (string, []interface{}, e
 }
 }
 
 
 func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}) {
 func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}) {
-	statement.setRefValue(rValue(bean))
+	v := rValue(bean)
+	isStruct := v.Kind() == reflect.Struct
+	if isStruct {
+		statement.setRefValue(v)
+	}
 
 
 	var columnStr = statement.ColumnStr
 	var columnStr = statement.ColumnStr
 	if len(statement.selectStr) > 0 {
 	if len(statement.selectStr) > 0 {
@@ -1139,14 +1147,22 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{})
 			if len(columnStr) == 0 {
 			if len(columnStr) == 0 {
 				if len(statement.GroupByStr) > 0 {
 				if len(statement.GroupByStr) > 0 {
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
-				} else {
-					columnStr = "*"
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	condSQL, condArgs, _ := statement.genConds(bean)
+	if len(columnStr) == 0 {
+		columnStr = "*"
+	}
+
+	var condSQL string
+	var condArgs []interface{}
+	if isStruct {
+		condSQL, condArgs, _ = statement.genConds(bean)
+	} else {
+		condSQL, condArgs, _ = builder.ToSQL(statement.cond)
+	}
 
 
 	return statement.genSelectSQL(columnStr, condSQL), append(statement.joinArgs, condArgs...)
 	return statement.genSelectSQL(columnStr, condSQL), append(statement.joinArgs, condArgs...)
 }
 }
@@ -1172,17 +1188,21 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
 
 
 	var sumStrs = make([]string, 0, len(columns))
 	var sumStrs = make([]string, 0, len(columns))
 	for _, colName := range columns {
 	for _, colName := range columns {
+		if !strings.Contains(colName, " ") && !strings.Contains(colName, "(") {
+			colName = statement.Engine.Quote(colName)
+		}
 		sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName))
 		sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName))
 	}
 	}
+	sumSelect := strings.Join(sumStrs, ", ")
 
 
 	condSQL, condArgs, _ := statement.genConds(bean)
 	condSQL, condArgs, _ := statement.genConds(bean)
 
 
-	return statement.genSelectSQL(strings.Join(sumStrs, ", "), condSQL), append(statement.joinArgs, condArgs...)
+	return statement.genSelectSQL(sumSelect, condSQL), append(statement.joinArgs, condArgs...)
 }
 }
 
 
 func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
 func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
 	var distinct string
 	var distinct string
-	if statement.IsDistinct {
+	if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
 		distinct = "DISTINCT "
 		distinct = "DISTINCT "
 	}
 	}
 
 
@@ -1198,8 +1218,14 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
 		fmt.Fprintf(&buf, " WHERE %v", condSQL)
 		fmt.Fprintf(&buf, " WHERE %v", condSQL)
 	}
 	}
 	var whereStr = buf.String()
 	var whereStr = buf.String()
+	var fromStr = " FROM "
+
+	if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") {
+		fromStr += statement.TableName()
+	} else {
+		fromStr += quote(statement.TableName())
+	}
 
 
-	var fromStr = " FROM " + quote(statement.TableName())
 	if statement.TableAlias != "" {
 	if statement.TableAlias != "" {
 		if dialect.DBType() == core.ORACLE {
 		if dialect.DBType() == core.ORACLE {
 			fromStr += " " + quote(statement.TableAlias)
 			fromStr += " " + quote(statement.TableAlias)
@@ -1289,14 +1315,14 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) {
 }
 }
 
 
 func (statement *Statement) processIDParam() {
 func (statement *Statement) processIDParam() {
-	if statement.IdParam == nil {
+	if statement.idParam == nil {
 		return
 		return
 	}
 	}
 
 
 	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]})
+		if i < len(*(statement.idParam)) {
+			statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]})
 		} else {
 		} else {
 			statement.cond = statement.cond.And(builder.Eq{colName: ""})
 			statement.cond = statement.cond.And(builder.Eq{colName: ""})
 		}
 		}

+ 281 - 0
vendor/github.com/go-xorm/xorm/tag.go

@@ -0,0 +1,281 @@
+// 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/core"
+)
+
+type tagContext struct {
+	tagName         string
+	params          []string
+	preTag, nextTag string
+	table           *core.Table
+	col             *core.Column
+	fieldValue      reflect.Value
+	isIndex         bool
+	isUnique        bool
+	indexNames      map[string]int
+	engine          *Engine
+	hasCacheTag     bool
+	hasNoCacheTag   bool
+	ignoreNext      bool
+}
+
+// tagHandler describes tag handler for XORM
+type tagHandler func(ctx *tagContext) error
+
+var (
+	// defaultTagHandlers enumerates all the default tag handler
+	defaultTagHandlers = map[string]tagHandler{
+		"<-":       OnlyFromDBTagHandler,
+		"->":       OnlyToDBTagHandler,
+		"PK":       PKTagHandler,
+		"NULL":     NULLTagHandler,
+		"NOT":      IgnoreTagHandler,
+		"AUTOINCR": AutoIncrTagHandler,
+		"DEFAULT":  DefaultTagHandler,
+		"CREATED":  CreatedTagHandler,
+		"UPDATED":  UpdatedTagHandler,
+		"DELETED":  DeletedTagHandler,
+		"VERSION":  VersionTagHandler,
+		"UTC":      UTCTagHandler,
+		"LOCAL":    LocalTagHandler,
+		"NOTNULL":  NotNullTagHandler,
+		"INDEX":    IndexTagHandler,
+		"UNIQUE":   UniqueTagHandler,
+		"CACHE":    CacheTagHandler,
+		"NOCACHE":  NoCacheTagHandler,
+	}
+)
+
+func init() {
+	for k := range core.SqlTypes {
+		defaultTagHandlers[k] = SQLTypeTagHandler
+	}
+}
+
+// IgnoreTagHandler describes ignored tag handler
+func IgnoreTagHandler(ctx *tagContext) error {
+	return nil
+}
+
+// OnlyFromDBTagHandler describes mapping direction tag handler
+func OnlyFromDBTagHandler(ctx *tagContext) error {
+	ctx.col.MapType = core.ONLYFROMDB
+	return nil
+}
+
+// OnlyToDBTagHandler describes mapping direction tag handler
+func OnlyToDBTagHandler(ctx *tagContext) error {
+	ctx.col.MapType = core.ONLYTODB
+	return nil
+}
+
+// PKTagHandler decribes primary key tag handler
+func PKTagHandler(ctx *tagContext) error {
+	ctx.col.IsPrimaryKey = true
+	ctx.col.Nullable = false
+	return nil
+}
+
+// NULLTagHandler describes null tag handler
+func NULLTagHandler(ctx *tagContext) error {
+	ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
+	return nil
+}
+
+// NotNullTagHandler describes notnull tag handler
+func NotNullTagHandler(ctx *tagContext) error {
+	ctx.col.Nullable = false
+	return nil
+}
+
+// AutoIncrTagHandler describes autoincr tag handler
+func AutoIncrTagHandler(ctx *tagContext) error {
+	ctx.col.IsAutoIncrement = true
+	/*
+		if len(ctx.params) > 0 {
+			autoStartInt, err := strconv.Atoi(ctx.params[0])
+			if err != nil {
+				return err
+			}
+			ctx.col.AutoIncrStart = autoStartInt
+		} else {
+			ctx.col.AutoIncrStart = 1
+		}
+	*/
+	return nil
+}
+
+// DefaultTagHandler describes default tag handler
+func DefaultTagHandler(ctx *tagContext) error {
+	if len(ctx.params) > 0 {
+		ctx.col.Default = ctx.params[0]
+	} else {
+		ctx.col.Default = ctx.nextTag
+		ctx.ignoreNext = true
+	}
+	return nil
+}
+
+// CreatedTagHandler describes created tag handler
+func CreatedTagHandler(ctx *tagContext) error {
+	ctx.col.IsCreated = true
+	return nil
+}
+
+// VersionTagHandler describes version tag handler
+func VersionTagHandler(ctx *tagContext) error {
+	ctx.col.IsVersion = true
+	ctx.col.Default = "1"
+	return nil
+}
+
+// UTCTagHandler describes utc tag handler
+func UTCTagHandler(ctx *tagContext) error {
+	ctx.col.TimeZone = time.UTC
+	return nil
+}
+
+// LocalTagHandler describes local tag handler
+func LocalTagHandler(ctx *tagContext) error {
+	if len(ctx.params) == 0 {
+		ctx.col.TimeZone = time.Local
+	} else {
+		var err error
+		ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// UpdatedTagHandler describes updated tag handler
+func UpdatedTagHandler(ctx *tagContext) error {
+	ctx.col.IsUpdated = true
+	return nil
+}
+
+// DeletedTagHandler describes deleted tag handler
+func DeletedTagHandler(ctx *tagContext) error {
+	ctx.col.IsDeleted = true
+	return nil
+}
+
+// IndexTagHandler describes index tag handler
+func IndexTagHandler(ctx *tagContext) error {
+	if len(ctx.params) > 0 {
+		ctx.indexNames[ctx.params[0]] = core.IndexType
+	} else {
+		ctx.isIndex = true
+	}
+	return nil
+}
+
+// UniqueTagHandler describes unique tag handler
+func UniqueTagHandler(ctx *tagContext) error {
+	if len(ctx.params) > 0 {
+		ctx.indexNames[ctx.params[0]] = core.UniqueType
+	} else {
+		ctx.isUnique = true
+	}
+	return nil
+}
+
+// SQLTypeTagHandler describes SQL Type tag handler
+func SQLTypeTagHandler(ctx *tagContext) error {
+	ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
+	if len(ctx.params) > 0 {
+		if ctx.tagName == core.Enum {
+			ctx.col.EnumOptions = make(map[string]int)
+			for k, v := range ctx.params {
+				v = strings.TrimSpace(v)
+				v = strings.Trim(v, "'")
+				ctx.col.EnumOptions[v] = k
+			}
+		} else if ctx.tagName == core.Set {
+			ctx.col.SetOptions = make(map[string]int)
+			for k, v := range ctx.params {
+				v = strings.TrimSpace(v)
+				v = strings.Trim(v, "'")
+				ctx.col.SetOptions[v] = k
+			}
+		} else {
+			var err error
+			if len(ctx.params) == 2 {
+				ctx.col.Length, err = strconv.Atoi(ctx.params[0])
+				if err != nil {
+					return err
+				}
+				ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
+				if err != nil {
+					return err
+				}
+			} else if len(ctx.params) == 1 {
+				ctx.col.Length, err = strconv.Atoi(ctx.params[0])
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// ExtendsTagHandler describes extends tag handler
+func ExtendsTagHandler(ctx *tagContext) error {
+	var fieldValue = ctx.fieldValue
+	switch fieldValue.Kind() {
+	case reflect.Ptr:
+		f := fieldValue.Type().Elem()
+		if f.Kind() == reflect.Struct {
+			fieldPtr := fieldValue
+			fieldValue = fieldValue.Elem()
+			if !fieldValue.IsValid() || fieldPtr.IsNil() {
+				fieldValue = reflect.New(f).Elem()
+			}
+		}
+		fallthrough
+	case reflect.Struct:
+		parentTable, err := ctx.engine.mapType(fieldValue)
+		if err != nil {
+			return err
+		}
+		for _, col := range parentTable.Columns() {
+			col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
+			ctx.table.AddColumn(col)
+			for indexName, indexType := range col.Indexes {
+				addIndex(indexName, ctx.table, col, indexType)
+			}
+		}
+	default:
+		//TODO: warning
+	}
+	return nil
+}
+
+// CacheTagHandler describes cache tag handler
+func CacheTagHandler(ctx *tagContext) error {
+	if !ctx.hasCacheTag {
+		ctx.hasCacheTag = true
+	}
+	return nil
+}
+
+// NoCacheTagHandler describes nocache tag handler
+func NoCacheTagHandler(ctx *tagContext) error {
+	if !ctx.hasNoCacheTag {
+		ctx.hasNoCacheTag = true
+	}
+	return nil
+}

+ 2 - 1
vendor/github.com/go-xorm/xorm/xorm.go

@@ -17,7 +17,7 @@ import (
 
 
 const (
 const (
 	// Version show the xorm's version
 	// Version show the xorm's version
-	Version string = "0.6.0.1022"
+	Version string = "0.6.2.0412"
 )
 )
 
 
 func regDrvsNDialects() bool {
 func regDrvsNDialects() bool {
@@ -86,6 +86,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 		mutex:         &sync.RWMutex{},
 		mutex:         &sync.RWMutex{},
 		TagIdentifier: "xorm",
 		TagIdentifier: "xorm",
 		TZLocation:    time.Local,
 		TZLocation:    time.Local,
+		tagHandlers:   defaultTagHandlers,
 	}
 	}
 
 
 	logger := NewSimpleLogger(os.Stdout)
 	logger := NewSimpleLogger(os.Stdout)

+ 3 - 3
vendor/vendor.json

@@ -159,10 +159,10 @@
 			"revisionTime": "2017-02-06T15:24:21Z"
 			"revisionTime": "2017-02-06T15:24:21Z"
 		},
 		},
 		{
 		{
-			"checksumSHA1": "BGWfs63vC5cJuxhVRrj+7YJKz7A=",
+			"checksumSHA1": "Ka4hFMvc75Fb57ZNLALyYSM7CCE=",
 			"path": "github.com/go-xorm/xorm",
 			"path": "github.com/go-xorm/xorm",
-			"revision": "19f6dfc2e8c069adc624ca56cf8127444159d5c1",
-			"revisionTime": "2017-02-10T01:55:37Z"
+			"revision": "d52a762fba17a2ed265463c1c7b608c14836eaaf",
+			"revisionTime": "2017-04-20T16:02:48Z"
 		},
 		},
 		{
 		{
 			"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=",
 			"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=",