Jelajahi Sumber

vendor: update github.com/go-xorm/…

Unknwon 6 tahun lalu
induk
melakukan
a75c435245
45 mengubah file dengan 1347 tambahan dan 1054 penghapusan
  1. 2 1
      vendor/github.com/go-xorm/builder/README.md
  2. 4 2
      vendor/github.com/go-xorm/builder/builder_insert.go
  3. 4 0
      vendor/github.com/go-xorm/builder/builder_select.go
  4. 3 1
      vendor/github.com/go-xorm/builder/circle.yml
  5. 4 2
      vendor/github.com/go-xorm/builder/cond_and.go
  6. 7 1
      vendor/github.com/go-xorm/builder/cond_compare.go
  7. 18 2
      vendor/github.com/go-xorm/builder/cond_eq.go
  8. 1 1
      vendor/github.com/go-xorm/builder/cond_like.go
  9. 18 2
      vendor/github.com/go-xorm/builder/cond_neq.go
  10. 24 0
      vendor/github.com/go-xorm/builder/cond_not.go
  11. 1 0
      vendor/github.com/go-xorm/builder/go.mod
  12. 2 2
      vendor/github.com/go-xorm/core/column.go
  13. 45 12
      vendor/github.com/go-xorm/core/db.go
  14. 2 1
      vendor/github.com/go-xorm/core/dialect.go
  15. 3 3
      vendor/github.com/go-xorm/core/filter.go
  16. 1 0
      vendor/github.com/go-xorm/core/go.mod
  17. 2 0
      vendor/github.com/go-xorm/core/index.go
  18. 3 61
      vendor/github.com/go-xorm/core/rows.go
  19. 0 2
      vendor/github.com/go-xorm/core/table.go
  20. 3 1
      vendor/github.com/go-xorm/core/type.go
  21. 57 43
      vendor/github.com/go-xorm/xorm/README.md
  22. 44 33
      vendor/github.com/go-xorm/xorm/README_CN.md
  23. 4 1
      vendor/github.com/go-xorm/xorm/circle.yml
  24. 23 2
      vendor/github.com/go-xorm/xorm/dialect_postgres.go
  25. 76 107
      vendor/github.com/go-xorm/xorm/engine.go
  26. 4 1
      vendor/github.com/go-xorm/xorm/engine_cond.go
  27. 113 0
      vendor/github.com/go-xorm/xorm/engine_table.go
  28. 26 5
      vendor/github.com/go-xorm/xorm/error.go
  29. 6 0
      vendor/github.com/go-xorm/xorm/go.mod
  30. 0 162
      vendor/github.com/go-xorm/xorm/helpers.go
  31. 5 0
      vendor/github.com/go-xorm/xorm/interface.go
  32. 3 3
      vendor/github.com/go-xorm/xorm/rows.go
  33. 353 356
      vendor/github.com/go-xorm/xorm/session.go
  34. 115 0
      vendor/github.com/go-xorm/xorm/session_cols.go
  35. 3 3
      vendor/github.com/go-xorm/xorm/session_delete.go
  36. 1 1
      vendor/github.com/go-xorm/xorm/session_exist.go
  37. 13 6
      vendor/github.com/go-xorm/xorm/session_find.go
  38. 4 3
      vendor/github.com/go-xorm/xorm/session_get.go
  39. 115 43
      vendor/github.com/go-xorm/xorm/session_insert.go
  40. 5 1
      vendor/github.com/go-xorm/xorm/session_query.go
  41. 30 51
      vendor/github.com/go-xorm/xorm/session_schema.go
  42. 101 14
      vendor/github.com/go-xorm/xorm/session_update.go
  43. 87 114
      vendor/github.com/go-xorm/xorm/statement.go
  44. 3 2
      vendor/github.com/go-xorm/xorm/xorm.go
  45. 9 9
      vendor/vendor.json

+ 2 - 1
vendor/github.com/go-xorm/builder/README.md

@@ -1,6 +1,7 @@
 # SQL builder
 
-[![CircleCI](https://circleci.com/gh/go-xorm/builder/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/builder/tree/master)
+[![CircleCI](https://circleci.com/gh/go-xorm/builder/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/builder/tree/master)  [![codecov](https://codecov.io/gh/go-xorm/builder/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/builder)
+[![](https://goreportcard.com/badge/github.com/go-xorm/builder)](https://goreportcard.com/report/github.com/go-xorm/builder)
 
 Package builder is a lightweight and fast SQL builder for Go and XORM.
 

+ 4 - 2
vendor/github.com/go-xorm/builder/builder_insert.go

@@ -15,7 +15,7 @@ func (b *Builder) insertWriteTo(w Writer) error {
 		return errors.New("no table indicated")
 	}
 	if len(b.inserts) <= 0 {
-		return errors.New("no column to be update")
+		return errors.New("no column to be insert")
 	}
 
 	if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.tableName); err != nil {
@@ -26,7 +26,9 @@ func (b *Builder) insertWriteTo(w Writer) error {
 	var bs []byte
 	var valBuffer = bytes.NewBuffer(bs)
 	var i = 0
-	for col, value := range b.inserts {
+
+	for _, col := range b.inserts.sortedKeys() {
+		value := b.inserts[col]
 		fmt.Fprint(w, col)
 		if e, ok := value.(expr); ok {
 			fmt.Fprint(valBuffer, e.sql)

+ 4 - 0
vendor/github.com/go-xorm/builder/builder_select.go

@@ -45,6 +45,10 @@ func (b *Builder) selectWriteTo(w Writer) error {
 		}
 	}
 
+	if !b.cond.IsValid() {
+		return nil
+	}
+
 	if _, err := fmt.Fprint(w, " WHERE "); err != nil {
 		return err
 	}

+ 3 - 1
vendor/github.com/go-xorm/builder/circle.yml

@@ -9,4 +9,6 @@ test:
   override:
     # './...' is a relative pattern which means all subdirectories
     - golint ./...
-    - go test -v -race
+    - go test -v -race -coverprofile=coverage.txt -covermode=atomic
+  post:
+    - bash <(curl -s https://codecov.io/bash)

+ 4 - 2
vendor/github.com/go-xorm/builder/cond_and.go

@@ -25,7 +25,9 @@ func And(conds ...Cond) Cond {
 func (and condAnd) WriteTo(w Writer) error {
 	for i, cond := range and {
 		_, isOr := cond.(condOr)
-		if isOr {
+		_, isExpr := cond.(expr)
+		wrap := isOr || isExpr
+		if wrap {
 			fmt.Fprint(w, "(")
 		}
 
@@ -34,7 +36,7 @@ func (and condAnd) WriteTo(w Writer) error {
 			return err
 		}
 
-		if isOr {
+		if wrap {
 			fmt.Fprint(w, ")")
 		}
 

+ 7 - 1
vendor/github.com/go-xorm/builder/cond_compare.go

@@ -10,7 +10,13 @@ import "fmt"
 func WriteMap(w Writer, data map[string]interface{}, op string) error {
 	var args = make([]interface{}, 0, len(data))
 	var i = 0
-	for k, v := range data {
+	keys := make([]string, 0, len(data))
+	for k := range data {
+		keys = append(keys, k)
+	}
+
+	for _, k := range keys {
+		v := data[k]
 		switch v.(type) {
 		case expr:
 			if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {

+ 18 - 2
vendor/github.com/go-xorm/builder/cond_eq.go

@@ -4,7 +4,10 @@
 
 package builder
 
-import "fmt"
+import (
+	"fmt"
+	"sort"
+)
 
 // Incr implements a type used by Eq
 type Incr int
@@ -19,7 +22,8 @@ var _ Cond = Eq{}
 
 func (eq Eq) opWriteTo(op string, w Writer) error {
 	var i = 0
-	for k, v := range eq {
+	for _, k := range eq.sortedKeys() {
+		v := eq[k]
 		switch v.(type) {
 		case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
 			if err := In(k, v).WriteTo(w); err != nil {
@@ -94,3 +98,15 @@ func (eq Eq) Or(conds ...Cond) Cond {
 func (eq Eq) IsValid() bool {
 	return len(eq) > 0
 }
+
+// sortedKeys returns all keys of this Eq sorted with sort.Strings.
+// It is used internally for consistent ordering when generating
+// SQL, see https://github.com/go-xorm/builder/issues/10
+func (eq Eq) sortedKeys() []string {
+	keys := make([]string, 0, len(eq))
+	for key := range eq {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	return keys
+}

+ 1 - 1
vendor/github.com/go-xorm/builder/cond_like.go

@@ -16,7 +16,7 @@ func (like Like) WriteTo(w Writer) error {
 	if _, err := fmt.Fprintf(w, "%s LIKE ?", like[0]); err != nil {
 		return err
 	}
-	// FIXME: if use other regular express, this will be failed. but for compitable, keep this
+	// FIXME: if use other regular express, this will be failed. but for compatible, keep this
 	if like[1][0] == '%' || like[1][len(like[1])-1] == '%' {
 		w.Append(like[1])
 	} else {

+ 18 - 2
vendor/github.com/go-xorm/builder/cond_neq.go

@@ -4,7 +4,10 @@
 
 package builder
 
-import "fmt"
+import (
+	"fmt"
+	"sort"
+)
 
 // Neq defines not equal conditions
 type Neq map[string]interface{}
@@ -15,7 +18,8 @@ var _ Cond = Neq{}
 func (neq Neq) WriteTo(w Writer) error {
 	var args = make([]interface{}, 0, len(neq))
 	var i = 0
-	for k, v := range neq {
+	for _, k := range neq.sortedKeys() {
+		v := neq[k]
 		switch v.(type) {
 		case []int, []int64, []string, []int32, []int16, []int8:
 			if err := NotIn(k, v).WriteTo(w); err != nil {
@@ -76,3 +80,15 @@ func (neq Neq) Or(conds ...Cond) Cond {
 func (neq Neq) IsValid() bool {
 	return len(neq) > 0
 }
+
+// sortedKeys returns all keys of this Neq sorted with sort.Strings.
+// It is used internally for consistent ordering when generating
+// SQL, see https://github.com/go-xorm/builder/issues/10
+func (neq Neq) sortedKeys() []string {
+	keys := make([]string, 0, len(neq))
+	for key := range neq {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	return keys
+}

+ 24 - 0
vendor/github.com/go-xorm/builder/cond_not.go

@@ -21,6 +21,18 @@ func (not Not) WriteTo(w Writer) error {
 		if _, err := fmt.Fprint(w, "("); err != nil {
 			return err
 		}
+	case Eq:
+		if len(not[0].(Eq)) > 1 {
+			if _, err := fmt.Fprint(w, "("); err != nil {
+				return err
+			}
+		}
+	case Neq:
+		if len(not[0].(Neq)) > 1 {
+			if _, err := fmt.Fprint(w, "("); err != nil {
+				return err
+			}
+		}
 	}
 
 	if err := not[0].WriteTo(w); err != nil {
@@ -32,6 +44,18 @@ func (not Not) WriteTo(w Writer) error {
 		if _, err := fmt.Fprint(w, ")"); err != nil {
 			return err
 		}
+	case Eq:
+		if len(not[0].(Eq)) > 1 {
+			if _, err := fmt.Fprint(w, ")"); err != nil {
+				return err
+			}
+		}
+	case Neq:
+		if len(not[0].(Neq)) > 1 {
+			if _, err := fmt.Fprint(w, ")"); err != nil {
+				return err
+			}
+		}
 	}
 
 	return nil

+ 1 - 0
vendor/github.com/go-xorm/builder/go.mod

@@ -0,0 +1 @@
+module "github.com/go-xorm/builder"

+ 2 - 2
vendor/github.com/go-xorm/core/column.go

@@ -147,12 +147,12 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 			}
 			fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
 		} else {
-			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
+			return nil, fmt.Errorf("field %v is not valid", col.FieldName)
 		}
 	}
 
 	if !fieldValue.IsValid() {
-		return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
+		return nil, fmt.Errorf("field %v is not valid", col.FieldName)
 	}
 
 	return &fieldValue, nil

+ 45 - 12
vendor/github.com/go-xorm/core/db.go

@@ -7,6 +7,11 @@ import (
 	"fmt"
 	"reflect"
 	"regexp"
+	"sync"
+)
+
+var (
+	DefaultCacheSize = 200
 )
 
 func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
@@ -58,9 +63,16 @@ func StructToSlice(query string, st interface{}) (string, []interface{}, error)
 	return query, args, nil
 }
 
+type cacheStruct struct {
+	value reflect.Value
+	idx   int
+}
+
 type DB struct {
 	*sql.DB
-	Mapper IMapper
+	Mapper            IMapper
+	reflectCache      map[reflect.Type]*cacheStruct
+	reflectCacheMutex sync.RWMutex
 }
 
 func Open(driverName, dataSourceName string) (*DB, error) {
@@ -68,11 +80,32 @@ func Open(driverName, dataSourceName string) (*DB, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &DB{db, NewCacheMapper(&SnakeMapper{})}, nil
+	return &DB{
+		DB:           db,
+		Mapper:       NewCacheMapper(&SnakeMapper{}),
+		reflectCache: make(map[reflect.Type]*cacheStruct),
+	}, nil
 }
 
 func FromDB(db *sql.DB) *DB {
-	return &DB{db, NewCacheMapper(&SnakeMapper{})}
+	return &DB{
+		DB:           db,
+		Mapper:       NewCacheMapper(&SnakeMapper{}),
+		reflectCache: make(map[reflect.Type]*cacheStruct),
+	}
+}
+
+func (db *DB) reflectNew(typ reflect.Type) reflect.Value {
+	db.reflectCacheMutex.Lock()
+	defer db.reflectCacheMutex.Unlock()
+	cs, ok := db.reflectCache[typ]
+	if !ok || cs.idx+1 > DefaultCacheSize-1 {
+		cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
+		db.reflectCache[typ] = cs
+	} else {
+		cs.idx = cs.idx + 1
+	}
+	return cs.value.Index(cs.idx).Addr()
 }
 
 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
@@ -83,7 +116,7 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 		}
 		return nil, err
 	}
-	return &Rows{rows, db.Mapper}, nil
+	return &Rows{rows, db}, nil
 }
 
 func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
@@ -128,8 +161,8 @@ func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
 
 type Stmt struct {
 	*sql.Stmt
-	Mapper IMapper
-	names  map[string]int
+	db    *DB
+	names map[string]int
 }
 
 func (db *DB) Prepare(query string) (*Stmt, error) {
@@ -145,7 +178,7 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &Stmt{stmt, db.Mapper, names}, nil
+	return &Stmt{stmt, db, names}, nil
 }
 
 func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
@@ -179,7 +212,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &Rows{rows, s.Mapper}, nil
+	return &Rows{rows, s.db}, nil
 }
 
 func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
@@ -274,7 +307,7 @@ func (EmptyScanner) Scan(src interface{}) error {
 
 type Tx struct {
 	*sql.Tx
-	Mapper IMapper
+	db *DB
 }
 
 func (db *DB) Begin() (*Tx, error) {
@@ -282,7 +315,7 @@ func (db *DB) Begin() (*Tx, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &Tx{tx, db.Mapper}, nil
+	return &Tx{tx, db}, nil
 }
 
 func (tx *Tx) Prepare(query string) (*Stmt, error) {
@@ -298,7 +331,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &Stmt{stmt, tx.Mapper, names}, nil
+	return &Stmt{stmt, tx.db, names}, nil
 }
 
 func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
@@ -327,7 +360,7 @@ func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &Rows{rows, tx.Mapper}, nil
+	return &Rows{rows, tx.db}, nil
 }
 
 func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) {

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

@@ -149,7 +149,8 @@ func (db *Base) SupportDropIfExists() bool {
 }
 
 func (db *Base) DropTableSql(tableName string) string {
-	return fmt.Sprintf("DROP TABLE IF EXISTS `%s`", tableName)
+	quote := db.dialect.Quote
+	return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))
 }
 
 func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {

+ 3 - 3
vendor/github.com/go-xorm/core/filter.go

@@ -37,9 +37,9 @@ func (q *Quoter) Quote(content string) string {
 func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string {
 	quoter := NewQuoter(dialect)
 	if table != nil && len(table.PrimaryKeys) == 1 {
-		sql = strings.Replace(sql, "`(id)`", quoter.Quote(table.PrimaryKeys[0]), -1)
-		sql = strings.Replace(sql, quoter.Quote("(id)"), quoter.Quote(table.PrimaryKeys[0]), -1)
-		return strings.Replace(sql, "(id)", quoter.Quote(table.PrimaryKeys[0]), -1)
+		sql = strings.Replace(sql, " `(id)` ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
+		sql = strings.Replace(sql, " "+quoter.Quote("(id)")+" ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
+		return strings.Replace(sql, " (id) ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
 	}
 	return sql
 }

+ 1 - 0
vendor/github.com/go-xorm/core/go.mod

@@ -0,0 +1 @@
+module "github.com/go-xorm/core"

+ 2 - 0
vendor/github.com/go-xorm/core/index.go

@@ -22,6 +22,8 @@ type Index struct {
 func (index *Index) XName(tableName string) string {
 	if !strings.HasPrefix(index.Name, "UQE_") &&
 		!strings.HasPrefix(index.Name, "IDX_") {
+		tableName = strings.Replace(tableName, `"`, "", -1)
+		tableName = strings.Replace(tableName, `.`, "_", -1)
 		if index.Type == UniqueType {
 			return fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
 		}

+ 3 - 61
vendor/github.com/go-xorm/core/rows.go

@@ -9,7 +9,7 @@ import (
 
 type Rows struct {
 	*sql.Rows
-	Mapper IMapper
+	db *DB
 }
 
 func (rs *Rows) ToMapString() ([]map[string]string, error) {
@@ -105,7 +105,7 @@ func (rs *Rows) ScanStructByName(dest interface{}) error {
 	newDest := make([]interface{}, len(cols))
 	var v EmptyScanner
 	for j, name := range cols {
-		f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
+		f := fieldByName(vv.Elem(), rs.db.Mapper.Table2Obj(name))
 		if f.IsValid() {
 			newDest[j] = f.Addr().Interface()
 		} else {
@@ -116,36 +116,6 @@ func (rs *Rows) ScanStructByName(dest interface{}) error {
 	return rs.Rows.Scan(newDest...)
 }
 
-type cacheStruct struct {
-	value reflect.Value
-	idx   int
-}
-
-var (
-	reflectCache      = make(map[reflect.Type]*cacheStruct)
-	reflectCacheMutex sync.RWMutex
-)
-
-func ReflectNew(typ reflect.Type) reflect.Value {
-	reflectCacheMutex.RLock()
-	cs, ok := reflectCache[typ]
-	reflectCacheMutex.RUnlock()
-
-	const newSize = 200
-
-	if !ok || cs.idx+1 > newSize-1 {
-		cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), newSize, newSize), 0}
-		reflectCacheMutex.Lock()
-		reflectCache[typ] = cs
-		reflectCacheMutex.Unlock()
-	} else {
-		reflectCacheMutex.Lock()
-		cs.idx = cs.idx + 1
-		reflectCacheMutex.Unlock()
-	}
-	return cs.value.Index(cs.idx).Addr()
-}
-
 // scan data to a slice's pointer, slice's length should equal to columns' number
 func (rs *Rows) ScanSlice(dest interface{}) error {
 	vv := reflect.ValueOf(dest)
@@ -197,9 +167,7 @@ func (rs *Rows) ScanMap(dest interface{}) error {
 	vvv := vv.Elem()
 
 	for i, _ := range cols {
-		newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
-		//v := reflect.New(vvv.Type().Elem())
-		//newDest[i] = v.Interface()
+		newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface()
 	}
 
 	err = rs.Rows.Scan(newDest...)
@@ -215,32 +183,6 @@ func (rs *Rows) ScanMap(dest interface{}) error {
 	return nil
 }
 
-/*func (rs *Rows) ScanMap(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
-		return errors.New("dest should be a map's pointer")
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-	err = rs.ScanSlice(newDest)
-	if err != nil {
-		return err
-	}
-
-	vvv := vv.Elem()
-
-	for i, name := range cols {
-		vname := reflect.ValueOf(name)
-		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
-	}
-
-	return nil
-}*/
 type Row struct {
 	rows *Rows
 	// One of these two will be non-nil:

+ 0 - 2
vendor/github.com/go-xorm/core/table.go

@@ -49,7 +49,6 @@ func NewTable(name string, t reflect.Type) *Table {
 }
 
 func (table *Table) columnsByName(name string) []*Column {
-
 	n := len(name)
 
 	for k := range table.columnsMap {
@@ -75,7 +74,6 @@ func (table *Table) GetColumn(name string) *Column {
 }
 
 func (table *Table) GetColumnIdx(name string, idx int) *Column {
-
 	cols := table.columnsByName(name)
 
 	if cols != nil && idx < len(cols) {

+ 3 - 1
vendor/github.com/go-xorm/core/type.go

@@ -74,6 +74,7 @@ var (
 	NVarchar         = "NVARCHAR"
 	TinyText         = "TINYTEXT"
 	Text             = "TEXT"
+	NText            = "NTEXT"
 	Clob             = "CLOB"
 	MediumText       = "MEDIUMTEXT"
 	LongText         = "LONGTEXT"
@@ -130,6 +131,7 @@ var (
 		NVarchar:   TEXT_TYPE,
 		TinyText:   TEXT_TYPE,
 		Text:       TEXT_TYPE,
+		NText:      TEXT_TYPE,
 		MediumText: TEXT_TYPE,
 		LongText:   TEXT_TYPE,
 		Uuid:       TEXT_TYPE,
@@ -293,7 +295,7 @@ func SQLType2Type(st SQLType) reflect.Type {
 		return reflect.TypeOf(float32(1))
 	case Double:
 		return reflect.TypeOf(float64(1))
-	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
+	case Char, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
 		return reflect.TypeOf("")
 	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
 		return reflect.TypeOf([]byte{})

+ 57 - 43
vendor/github.com/go-xorm/xorm/README.md

@@ -1,3 +1,5 @@
+# xorm
+
 [中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md)
 
 Xorm is a simple and powerful ORM for Go.
@@ -6,7 +8,7 @@ Xorm is a simple and powerful ORM for Go.
 [![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) 
 [![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
 
-# Features
+## Features
 
 * Struct <-> Table Mapping Support
 
@@ -30,7 +32,9 @@ Xorm is a simple and powerful ORM for Go.
 
 * Automatical Read/Write seperatelly
 
-# Drivers Support
+* Postgres schema support
+
+## Drivers Support
 
 Drivers for Go's sql package which currently support database/sql includes:
 
@@ -48,43 +52,17 @@ Drivers for Go's sql package which currently support database/sql includes:
 
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 
-# Changelog
-
-* **v0.6.4**
-    * Automatical Read/Write seperatelly
-    * Query/QueryString/QueryInterface and action with Where/And
-    * Get support non-struct variables
-    * BufferSize on Iterate
-    * fix some other bugs.
-
-* **v0.6.3**
-    * merge tests to main project
-    * add `Exist` function
-    * add `SumInt` function
-    * Mysql now support read and create column comment.
-    * fix time related bugs.
-    * fix some other bugs.
-
-* **v0.6.2**
-    * refactor tag parse methods
-    * add Scan features to Get
-    * add QueryString method
-
-[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
-
-# Installation
+## Installation
 
 	go get github.com/go-xorm/xorm
 
-# Documents
+## Documents
 
 * [Manual](http://xorm.io/docs)
 
 * [GoDoc](http://godoc.org/github.com/go-xorm/xorm)
 
-* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
-
-# Quick Start
+## Quick Start
 
 * Create Engine
 
@@ -380,7 +358,52 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
 return session.Commit()
 ```
 
-# Cases
+## Contributing
+
+If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.
+
+## Credits
+
+### Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
+
+### Backers
+
+Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/xorm#backer)]
+
+<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
+
+### Sponsors
+
+Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/xorm#sponsor)]
+
+## Changelog
+
+* **v0.7.0**
+    * Some bugs fixed
+
+* **v0.6.6**
+    * Some bugs fixed
+
+* **v0.6.5**
+    * Postgres schema support
+    * vgo support
+    * Add FindAndCount
+    * Database special params support via NewEngineWithParams
+    * Some bugs fixed
+
+* **v0.6.4**
+    * Automatical Read/Write seperatelly
+    * Query/QueryString/QueryInterface and action with Where/And
+    * Get support non-struct variables
+    * BufferSize on Iterate
+    * fix some other bugs.
+
+[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
+
+## Cases
 
 * [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
 
@@ -416,15 +439,6 @@ return session.Commit()
 
 * [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
 
-# Discuss
-
-Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm)
-
-# Contributing
-
-If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
-
-# LICENSE
+## LICENSE
 
- BSD License
- [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
+BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)

+ 44 - 33
vendor/github.com/go-xorm/xorm/README_CN.md

@@ -22,6 +22,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 * 支持级联加载Struct
 
+* Schema支持(仅Postgres)
+
 * 支持缓存
 
 * 支持根据数据库自动生成xorm的结构体
@@ -50,35 +52,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
 
-## 更新日志
-
-* **v0.6.3**
-    * 合并单元测试到主工程
-    * 新增`Exist`方法
-    * 新增`SumInt`方法
-    * Mysql新增读取和创建字段注释支持
-    * 新增`SetConnMaxLifetime`方法
-    * 修正了时间相关的Bug
-    * 修复了一些其它Bug
-
-* **v0.6.2**
-    * 重构Tag解析方式
-    * Get方法新增类似Scan的特性
-    * 新增 QueryString 方法
-
-* **v0.6.0**
-    * 去除对 ql 的支持
-    * 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数
-将可以用 `builder.Cond` 作为条件组合
-    * 新增 Sum, SumInt, SumInt64 和 NotIn 函数
-    * Bug修正
-
-* **v0.5.0**
-    * logging接口进行不兼容改变
-    * Bug修正
-
-[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
-
 ## 安装
 
 	go get github.com/go-xorm/xorm
@@ -387,6 +360,27 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
 return session.Commit()
 ```
 
+## 贡献
+
+如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 280360085 技术帮助和讨论。
+
+## Credits
+
+### Contributors
+
+感谢所有的贡献者. [[Contribute](CONTRIBUTING.md)].
+<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
+
+### Backers
+
+感谢我们所有的 backers! 🙏 [[成为 backer](https://opencollective.com/xorm#backer)]
+
+<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
+
+### Sponsors
+
+成为 sponsor 来支持 xorm。您的 logo 将会被显示并被链接到您的网站。 [[成为 sponsor](https://opencollective.com/xorm#sponsor)]
+
 # 案例
 
 * [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
@@ -421,13 +415,30 @@ return session.Commit()
 
 * [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
 
-## 讨论
 
-请加入QQ群:280360085 进行讨论。
+## 更新日志
 
-## 贡献
+* **v0.7.0**
+    * 修正部分Bug
+
+* **v0.6.6**
+    * 修正部分Bug
+
+* **v0.6.5**
+    * 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres
+    * vgo 支持
+    * 新增 `FindAndCount` 函数
+    * 通过 `NewEngineWithParams` 支持数据库特别参数
+    * 修正部分Bug
 
-如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
+* **v0.6.4**
+    * 自动读写分离支持
+    * Query/QueryString/QueryInterface 支持与 Where/And 合用
+    * `Get` 支持获取非结构体变量
+    * `Iterate` 支持 `BufferSize` 
+    * 修正部分Bug
+
+[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 
 ## LICENSE
 

+ 4 - 1
vendor/github.com/go-xorm/xorm/circle.yml

@@ -17,6 +17,7 @@ database:
     - createdb -p 5432 -e -U postgres xorm_test1
     - createdb -p 5432 -e -U postgres xorm_test2
     - createdb -p 5432 -e -U postgres xorm_test3
+    - psql xorm_test postgres -c "create schema xorm"
 
 test:
   override:
@@ -30,7 +31,9 @@ test:
     - go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
     - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
     - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
-    - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt > coverage.txt
+    - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
+    - go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
+    - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt
     - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
     - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
     - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh

+ 23 - 2
vendor/github.com/go-xorm/xorm/dialect_postgres.go

@@ -769,6 +769,8 @@ var (
 	DefaultPostgresSchema = "public"
 )
 
+const postgresPublicSchema = "public"
+
 type postgres struct {
 	core.Base
 }
@@ -893,6 +895,7 @@ func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
 		args := []interface{}{tableName}
 		return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
 	}
+
 	args := []interface{}{db.Schema, tableName}
 	return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
 }
@@ -910,6 +913,9 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
 	quote := db.Quote
 	idxName := index.Name
 
+	tableName = strings.Replace(tableName, `"`, "", -1)
+	tableName = strings.Replace(tableName, `.`, "_", -1)
+
 	if !strings.HasPrefix(idxName, "UQE_") &&
 		!strings.HasPrefix(idxName, "IDX_") {
 		if index.Type == core.UniqueType {
@@ -918,6 +924,9 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
 			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
 		}
 	}
+	if db.Uri.Schema != "" {
+		idxName = db.Uri.Schema + "." + idxName
+	}
 	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 }
 
@@ -958,7 +967,7 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
 	var f string
 	if len(db.Schema) != 0 {
 		args = append(args, db.Schema)
-		f = "AND s.table_schema = $2"
+		f = " AND s.table_schema = $2"
 	}
 	s = fmt.Sprintf(s, f)
 
@@ -1083,11 +1092,11 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
 func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
-	db.LogSQL(s, args)
 	if len(db.Schema) != 0 {
 		args = append(args, db.Schema)
 		s = s + " AND schemaname=$2"
 	}
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
@@ -1214,3 +1223,15 @@ func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 
 	return db, nil
 }
+
+type pqDriverPgx struct {
+	pqDriver
+}
+
+func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	// Remove the leading characters for driver to work
+	if len(dataSourceName) >= 9 && dataSourceName[0] == 0 {
+		dataSourceName = dataSourceName[9:]
+	}
+	return pgx.pqDriver.Parse(driverName, dataSourceName)
+}

+ 76 - 107
vendor/github.com/go-xorm/xorm/engine.go

@@ -49,6 +49,35 @@ type Engine struct {
 	tagHandlers map[string]tagHandler
 
 	engineGroup *EngineGroup
+
+	cachers    map[string]core.Cacher
+	cacherLock sync.RWMutex
+}
+
+func (engine *Engine) setCacher(tableName string, cacher core.Cacher) {
+	engine.cacherLock.Lock()
+	engine.cachers[tableName] = cacher
+	engine.cacherLock.Unlock()
+}
+
+func (engine *Engine) SetCacher(tableName string, cacher core.Cacher) {
+	engine.setCacher(tableName, cacher)
+}
+
+func (engine *Engine) getCacher(tableName string) core.Cacher {
+	var cacher core.Cacher
+	var ok bool
+	engine.cacherLock.RLock()
+	cacher, ok = engine.cachers[tableName]
+	engine.cacherLock.RUnlock()
+	if !ok && !engine.disableGlobalCache {
+		cacher = engine.Cacher
+	}
+	return cacher
+}
+
+func (engine *Engine) GetCacher(tableName string) core.Cacher {
+	return engine.getCacher(tableName)
 }
 
 // BufferSize sets buffer size for iterate
@@ -245,13 +274,7 @@ func (engine *Engine) NoCascade() *Session {
 
 // MapCacher Set a table use a special cacher
 func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error {
-	v := rValue(bean)
-	tb, err := engine.autoMapType(v)
-	if err != nil {
-		return err
-	}
-
-	tb.Cacher = cacher
+	engine.setCacher(engine.TableName(bean, true), cacher)
 	return nil
 }
 
@@ -536,33 +559,6 @@ func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.D
 	return nil
 }
 
-func (engine *Engine) tableName(beanOrTableName interface{}) (string, error) {
-	v := rValue(beanOrTableName)
-	if v.Type().Kind() == reflect.String {
-		return beanOrTableName.(string), nil
-	} else if v.Type().Kind() == reflect.Struct {
-		return engine.tbName(v), nil
-	}
-	return "", errors.New("bean should be a struct or struct's point")
-}
-
-func (engine *Engine) tbName(v reflect.Value) string {
-	if tb, ok := v.Interface().(TableName); ok {
-		return tb.TableName()
-	}
-
-	if v.Type().Kind() == reflect.Ptr {
-		if tb, ok := reflect.Indirect(v).Interface().(TableName); ok {
-			return tb.TableName()
-		}
-	} else if v.CanAddr() {
-		if tb, ok := v.Addr().Interface().(TableName); ok {
-			return tb.TableName()
-		}
-	}
-	return engine.TableMapper.Obj2Table(reflect.Indirect(v).Type().Name())
-}
-
 // Cascade use cascade or not
 func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
 	session := engine.NewSession()
@@ -846,7 +842,7 @@ func (engine *Engine) TableInfo(bean interface{}) *Table {
 	if err != nil {
 		engine.logger.Error(err)
 	}
-	return &Table{tb, engine.tbName(v)}
+	return &Table{tb, engine.TableName(bean)}
 }
 
 func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
@@ -861,15 +857,6 @@ func addIndex(indexName string, table *core.Table, col *core.Column, indexType i
 	}
 }
 
-func (engine *Engine) newTable() *core.Table {
-	table := core.NewEmptyTable()
-
-	if !engine.disableGlobalCache {
-		table.Cacher = engine.Cacher
-	}
-	return table
-}
-
 // TableName table name interface to define customerize table name
 type TableName interface {
 	TableName() string
@@ -881,21 +868,9 @@ var (
 
 func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
 	t := v.Type()
-	table := engine.newTable()
-	if tb, ok := v.Interface().(TableName); ok {
-		table.Name = tb.TableName()
-	} else {
-		if v.CanAddr() {
-			if tb, ok = v.Addr().Interface().(TableName); ok {
-				table.Name = tb.TableName()
-			}
-		}
-		if table.Name == "" {
-			table.Name = engine.TableMapper.Obj2Table(t.Name())
-		}
-	}
-
+	table := core.NewEmptyTable()
 	table.Type = t
+	table.Name = engine.tbNameForMap(v)
 
 	var idFieldColName string
 	var hasCacheTag, hasNoCacheTag bool
@@ -1049,15 +1024,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
 	if hasCacheTag {
 		if engine.Cacher != nil { // !nash! use engine's cacher if provided
 			engine.logger.Info("enable cache on table:", table.Name)
-			table.Cacher = engine.Cacher
+			engine.setCacher(table.Name, engine.Cacher)
 		} else {
 			engine.logger.Info("enable LRU cache on table:", table.Name)
-			table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now
+			engine.setCacher(table.Name, NewLRUCacher2(NewMemoryStore(), time.Hour, 10000))
 		}
 	}
 	if hasNoCacheTag {
-		engine.logger.Info("no cache on table:", table.Name)
-		table.Cacher = nil
+		engine.logger.Info("disable cache on table:", table.Name)
+		engine.setCacher(table.Name, nil)
 	}
 
 	return table, nil
@@ -1116,7 +1091,25 @@ func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
 	pk := make([]interface{}, len(table.PrimaryKeys))
 	for i, col := range table.PKColumns() {
 		var err error
-		pkField := v.FieldByName(col.FieldName)
+
+		fieldName := col.FieldName
+		for {
+			parts := strings.SplitN(fieldName, ".", 2)
+			if len(parts) == 1 {
+				break
+			}
+
+			v = v.FieldByName(parts[0])
+			if v.Kind() == reflect.Ptr {
+				v = v.Elem()
+			}
+			if v.Kind() != reflect.Struct {
+				return nil, ErrUnSupportedType
+			}
+			fieldName = parts[1]
+		}
+
+		pkField := v.FieldByName(fieldName)
 		switch pkField.Kind() {
 		case reflect.String:
 			pk[i], err = engine.idTypeAssertion(col, pkField.String())
@@ -1162,26 +1155,10 @@ func (engine *Engine) CreateUniques(bean interface{}) error {
 	return session.CreateUniques(bean)
 }
 
-func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
-	return table.Cacher
-}
-
 // ClearCacheBean if enabled cache, clear the cache bean
 func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
-	v := rValue(bean)
-	t := v.Type()
-	if t.Kind() != reflect.Struct {
-		return errors.New("error params")
-	}
-	tableName := engine.tbName(v)
-	table, err := engine.autoMapType(v)
-	if err != nil {
-		return err
-	}
-	cacher := table.Cacher
-	if cacher == nil {
-		cacher = engine.Cacher
-	}
+	tableName := engine.TableName(bean)
+	cacher := engine.getCacher(tableName)
 	if cacher != nil {
 		cacher.ClearIds(tableName)
 		cacher.DelBean(tableName, id)
@@ -1192,21 +1169,8 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 // ClearCache if enabled cache, clear some tables' cache
 func (engine *Engine) ClearCache(beans ...interface{}) error {
 	for _, bean := range beans {
-		v := rValue(bean)
-		t := v.Type()
-		if t.Kind() != reflect.Struct {
-			return errors.New("error params")
-		}
-		tableName := engine.tbName(v)
-		table, err := engine.autoMapType(v)
-		if err != nil {
-			return err
-		}
-
-		cacher := table.Cacher
-		if cacher == nil {
-			cacher = engine.Cacher
-		}
+		tableName := engine.TableName(bean)
+		cacher := engine.getCacher(tableName)
 		if cacher != nil {
 			cacher.ClearIds(tableName)
 			cacher.ClearBeans(tableName)
@@ -1224,13 +1188,13 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 
 	for _, bean := range beans {
 		v := rValue(bean)
-		tableName := engine.tbName(v)
+		tableNameNoSchema := engine.TableName(bean)
 		table, err := engine.autoMapType(v)
 		if err != nil {
 			return err
 		}
 
-		isExist, err := session.Table(bean).isTableExist(tableName)
+		isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
 		if err != nil {
 			return err
 		}
@@ -1256,12 +1220,12 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 			}
 		} else {
 			for _, col := range table.Columns() {
-				isExist, err := engine.dialect.IsColumnExist(tableName, col.Name)
+				isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name)
 				if err != nil {
 					return err
 				}
 				if !isExist {
-					if err := session.statement.setRefValue(v); err != nil {
+					if err := session.statement.setRefBean(bean); err != nil {
 						return err
 					}
 					err = session.addColumn(col.Name)
@@ -1272,35 +1236,35 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 			}
 
 			for name, index := range table.Indexes {
-				if err := session.statement.setRefValue(v); err != nil {
+				if err := session.statement.setRefBean(bean); err != nil {
 					return err
 				}
 				if index.Type == core.UniqueType {
-					isExist, err := session.isIndexExist2(tableName, index.Cols, true)
+					isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
 					if err != nil {
 						return err
 					}
 					if !isExist {
-						if err := session.statement.setRefValue(v); err != nil {
+						if err := session.statement.setRefBean(bean); err != nil {
 							return err
 						}
 
-						err = session.addUnique(tableName, name)
+						err = session.addUnique(tableNameNoSchema, name)
 						if err != nil {
 							return err
 						}
 					}
 				} else if index.Type == core.IndexType {
-					isExist, err := session.isIndexExist2(tableName, index.Cols, false)
+					isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
 					if err != nil {
 						return err
 					}
 					if !isExist {
-						if err := session.statement.setRefValue(v); err != nil {
+						if err := session.statement.setRefBean(bean); err != nil {
 							return err
 						}
 
-						err = session.addIndex(tableName, name)
+						err = session.addIndex(tableNameNoSchema, name)
 						if err != nil {
 							return err
 						}
@@ -1636,6 +1600,11 @@ func (engine *Engine) SetTZDatabase(tz *time.Location) {
 	engine.DatabaseTZ = tz
 }
 
+// SetSchema sets the schema of database
+func (engine *Engine) SetSchema(schema string) {
+	engine.dialect.URI().Schema = schema
+}
+
 // Unscoped always disable struct tag "deleted"
 func (engine *Engine) Unscoped() *Session {
 	session := engine.NewSession()

+ 4 - 1
vendor/github.com/go-xorm/xorm/engine_cond.go

@@ -9,6 +9,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"reflect"
+	"strings"
 	"time"
 
 	"github.com/go-xorm/builder"
@@ -51,7 +52,9 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{},
 
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
-			engine.logger.Error(err)
+			if !strings.Contains(err.Error(), "is not valid") {
+				engine.logger.Warn(err)
+			}
 			continue
 		}
 

+ 113 - 0
vendor/github.com/go-xorm/xorm/engine_table.go

@@ -0,0 +1,113 @@
+// Copyright 2018 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"
+	"strings"
+
+	"github.com/go-xorm/core"
+)
+
+// TableNameWithSchema will automatically add schema prefix on table name
+func (engine *Engine) tbNameWithSchema(v string) string {
+	// Add schema name as prefix of table name.
+	// Only for postgres database.
+	if engine.dialect.DBType() == core.POSTGRES &&
+		engine.dialect.URI().Schema != "" &&
+		engine.dialect.URI().Schema != postgresPublicSchema &&
+		strings.Index(v, ".") == -1 {
+		return engine.dialect.URI().Schema + "." + v
+	}
+	return v
+}
+
+// TableName returns table name with schema prefix if has
+func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
+	tbName := engine.tbNameNoSchema(bean)
+	if len(includeSchema) > 0 && includeSchema[0] {
+		tbName = engine.tbNameWithSchema(tbName)
+	}
+
+	return tbName
+}
+
+// tbName get some table's table name
+func (session *Session) tbNameNoSchema(table *core.Table) string {
+	if len(session.statement.AltTableName) > 0 {
+		return session.statement.AltTableName
+	}
+
+	return table.Name
+}
+
+func (engine *Engine) tbNameForMap(v reflect.Value) string {
+	if v.Type().Implements(tpTableName) {
+		return v.Interface().(TableName).TableName()
+	}
+	if v.Kind() == reflect.Ptr {
+		v = v.Elem()
+		if v.Type().Implements(tpTableName) {
+			return v.Interface().(TableName).TableName()
+		}
+	}
+
+	return engine.TableMapper.Obj2Table(v.Type().Name())
+}
+
+func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
+	switch tablename.(type) {
+	case []string:
+		t := tablename.([]string)
+		if len(t) > 1 {
+			return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
+		} else if len(t) == 1 {
+			return engine.Quote(t[0])
+		}
+	case []interface{}:
+		t := tablename.([]interface{})
+		l := len(t)
+		var table string
+		if l > 0 {
+			f := t[0]
+			switch f.(type) {
+			case string:
+				table = f.(string)
+			case TableName:
+				table = f.(TableName).TableName()
+			default:
+				v := rValue(f)
+				t := v.Type()
+				if t.Kind() == reflect.Struct {
+					table = engine.tbNameForMap(v)
+				} else {
+					table = engine.Quote(fmt.Sprintf("%v", f))
+				}
+			}
+		}
+		if l > 1 {
+			return fmt.Sprintf("%v AS %v", engine.Quote(table),
+				engine.Quote(fmt.Sprintf("%v", t[1])))
+		} else if l == 1 {
+			return engine.Quote(table)
+		}
+	case TableName:
+		return tablename.(TableName).TableName()
+	case string:
+		return tablename.(string)
+	case reflect.Value:
+		v := tablename.(reflect.Value)
+		return engine.tbNameForMap(v)
+	default:
+		v := rValue(tablename)
+		t := v.Type()
+		if t.Kind() == reflect.Struct {
+			return engine.tbNameForMap(v)
+		}
+		return engine.Quote(fmt.Sprintf("%v", tablename))
+	}
+	return ""
+}

+ 26 - 5
vendor/github.com/go-xorm/xorm/error.go

@@ -6,23 +6,44 @@ package xorm
 
 import (
 	"errors"
+	"fmt"
 )
 
 var (
 	// ErrParamsType params error
 	ErrParamsType = errors.New("Params type error")
 	// ErrTableNotFound table not found error
-	ErrTableNotFound = errors.New("Not found table")
+	ErrTableNotFound = errors.New("Table not found")
 	// ErrUnSupportedType unsupported error
 	ErrUnSupportedType = errors.New("Unsupported type error")
-	// ErrNotExist record is not exist error
-	ErrNotExist = errors.New("Not exist error")
+	// ErrNotExist record does not exist error
+	ErrNotExist = errors.New("Record does not exist")
 	// ErrCacheFailed cache failed error
 	ErrCacheFailed = errors.New("Cache failed")
 	// ErrNeedDeletedCond delete needs less one condition error
-	ErrNeedDeletedCond = errors.New("Delete need at least one condition")
+	ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
 	// ErrNotImplemented not implemented
 	ErrNotImplemented = errors.New("Not implemented")
 	// ErrConditionType condition type unsupported
-	ErrConditionType = errors.New("Unsupported conditon type")
+	ErrConditionType = errors.New("Unsupported condition type")
 )
+
+// ErrFieldIsNotExist columns does not exist
+type ErrFieldIsNotExist struct {
+	FieldName string
+	TableName string
+}
+
+func (e ErrFieldIsNotExist) Error() string {
+	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
+}
+
+// ErrFieldIsNotValid is not valid
+type ErrFieldIsNotValid struct {
+	FieldName string
+	TableName string
+}
+
+func (e ErrFieldIsNotValid) Error() string {
+	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
+}

+ 6 - 0
vendor/github.com/go-xorm/xorm/go.mod

@@ -0,0 +1,6 @@
+module "github.com/go-xorm/xorm"
+
+require (
+	"github.com/go-xorm/builder" v0.0.0-20180322150003-a9b7ffcca3f0
+	"github.com/go-xorm/core" v0.0.0-20180322150003-0177c08cee88
+)

+ 0 - 162
vendor/github.com/go-xorm/xorm/helpers.go

@@ -11,7 +11,6 @@ import (
 	"sort"
 	"strconv"
 	"strings"
-	"time"
 
 	"github.com/go-xorm/core"
 )
@@ -293,19 +292,6 @@ func structName(v reflect.Type) string {
 	return v.Name()
 }
 
-func col2NewCols(columns ...string) []string {
-	newColumns := make([]string, 0, len(columns))
-	for _, col := range columns {
-		col = strings.Replace(col, "`", "", -1)
-		col = strings.Replace(col, `"`, "", -1)
-		ccols := strings.Split(col, ",")
-		for _, c := range ccols {
-			newColumns = append(newColumns, strings.TrimSpace(c))
-		}
-	}
-	return newColumns
-}
-
 func sliceEq(left, right []string) bool {
 	if len(left) != len(right) {
 		return false
@@ -320,154 +306,6 @@ func sliceEq(left, right []string) bool {
 	return true
 }
 
-func setColumnInt(bean interface{}, col *core.Column, t int64) {
-	v, err := col.ValueOf(bean)
-	if err != nil {
-		return
-	}
-	if v.CanSet() {
-		switch v.Type().Kind() {
-		case reflect.Int, reflect.Int64, reflect.Int32:
-			v.SetInt(t)
-		case reflect.Uint, reflect.Uint64, reflect.Uint32:
-			v.SetUint(uint64(t))
-		}
-	}
-}
-
-func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
-	v, err := col.ValueOf(bean)
-	if err != nil {
-		return
-	}
-	if v.CanSet() {
-		switch v.Type().Kind() {
-		case reflect.Struct:
-			v.Set(reflect.ValueOf(t).Convert(v.Type()))
-		case reflect.Int, reflect.Int64, reflect.Int32:
-			v.SetInt(t.Unix())
-		case reflect.Uint, reflect.Uint64, reflect.Uint32:
-			v.SetUint(uint64(t.Unix()))
-		}
-	}
-}
-
-func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
-	colNames := make([]string, 0, len(table.ColumnsSeq()))
-	args := make([]interface{}, 0, len(table.ColumnsSeq()))
-
-	for _, col := range table.Columns() {
-		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
-			if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
-				continue
-			}
-		}
-		if col.MapType == core.ONLYFROMDB {
-			continue
-		}
-
-		fieldValuePtr, err := col.ValueOf(bean)
-		if err != nil {
-			return nil, nil, err
-		}
-		fieldValue := *fieldValuePtr
-
-		if col.IsAutoIncrement {
-			switch fieldValue.Type().Kind() {
-			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
-				if fieldValue.Int() == 0 {
-					continue
-				}
-			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
-				if fieldValue.Uint() == 0 {
-					continue
-				}
-			case reflect.String:
-				if len(fieldValue.String()) == 0 {
-					continue
-				}
-			case reflect.Ptr:
-				if fieldValue.Pointer() == 0 {
-					continue
-				}
-			}
-		}
-
-		if col.IsDeleted {
-			continue
-		}
-
-		if session.statement.ColumnStr != "" {
-			if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
-				continue
-			} else if _, ok := session.statement.incrColumns[col.Name]; ok {
-				continue
-			} else if _, ok := session.statement.decrColumns[col.Name]; ok {
-				continue
-			}
-		}
-		if session.statement.OmitStr != "" {
-			if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
-				continue
-			}
-		}
-
-		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
-		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
-			if col.Nullable && isZero(fieldValue.Interface()) {
-				var nilValue *int
-				fieldValue = reflect.ValueOf(nilValue)
-			}
-		}
-
-		if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
-			// if time is non-empty, then set to auto time
-			val, t := session.engine.nowTime(col)
-			args = append(args, val)
-
-			var colName = col.Name
-			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
-				col := table.GetColumn(colName)
-				setColumnTime(bean, col, t)
-			})
-		} else if col.IsVersion && session.statement.checkVersion {
-			args = append(args, 1)
-		} else {
-			arg, err := session.value2Interface(col, fieldValue)
-			if err != nil {
-				return colNames, args, err
-			}
-			args = append(args, arg)
-		}
-
-		if includeQuote {
-			colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
-		} else {
-			colNames = append(colNames, col.Name)
-		}
-	}
-	return colNames, args, nil
-}
-
 func indexName(tableName, idxName string) string {
 	return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
 }
-
-func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
-	if len(m) == 0 {
-		return false, false
-	}
-
-	n := len(col.Name)
-
-	for mk := range m {
-		if len(mk) != n {
-			continue
-		}
-		if strings.EqualFold(mk, col.Name) {
-			return m[mk], true
-		}
-	}
-
-	return false, false
-}

+ 5 - 0
vendor/github.com/go-xorm/xorm/interface.go

@@ -42,6 +42,7 @@ type Interface interface {
 	IsTableExist(beanOrTableName interface{}) (bool, error)
 	Iterate(interface{}, IterFunc) error
 	Limit(int, ...int) *Session
+	MustCols(columns ...string) *Session
 	NoAutoCondition(...bool) *Session
 	NotIn(string, ...interface{}) *Session
 	Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
@@ -76,6 +77,7 @@ type EngineInterface interface {
 	Dialect() core.Dialect
 	DropTables(...interface{}) error
 	DumpAllToFile(fp string, tp ...core.DbType) error
+	GetCacher(string) core.Cacher
 	GetColumnMapper() core.IMapper
 	GetDefaultCacher() core.Cacher
 	GetTableMapper() core.IMapper
@@ -84,9 +86,11 @@ type EngineInterface interface {
 	NewSession() *Session
 	NoAutoTime() *Session
 	Quote(string) string
+	SetCacher(string, core.Cacher)
 	SetDefaultCacher(core.Cacher)
 	SetLogLevel(core.LogLevel)
 	SetMapper(core.IMapper)
+	SetSchema(string)
 	SetTZDatabase(tz *time.Location)
 	SetTZLocation(tz *time.Location)
 	ShowSQL(show ...bool)
@@ -94,6 +98,7 @@ type EngineInterface interface {
 	Sync2(...interface{}) error
 	StoreEngine(storeEngine string) *Session
 	TableInfo(bean interface{}) *Table
+	TableName(interface{}, ...bool) string
 	UnMapType(reflect.Type)
 }
 

+ 3 - 3
vendor/github.com/go-xorm/xorm/rows.go

@@ -32,7 +32,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 	var args []interface{}
 	var err error
 
-	if err = rows.session.statement.setRefValue(rValue(bean)); err != nil {
+	if err = rows.session.statement.setRefBean(bean); err != nil {
 		return nil, err
 	}
 
@@ -94,8 +94,7 @@ func (rows *Rows) Scan(bean interface{}) error {
 		return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
 	}
 
-	dataStruct := rValue(bean)
-	if err := rows.session.statement.setRefValue(dataStruct); err != nil {
+	if err := rows.session.statement.setRefBean(bean); err != nil {
 		return err
 	}
 
@@ -104,6 +103,7 @@ func (rows *Rows) Scan(bean interface{}) error {
 		return err
 	}
 
+	dataStruct := rValue(bean)
 	_, err = rows.session.slice2Bean(scanResults, rows.fields, bean, &dataStruct, rows.session.statement.RefTable)
 	if err != nil {
 		return err

+ 353 - 356
vendor/github.com/go-xorm/xorm/session.go

@@ -278,24 +278,22 @@ func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt,
 	return
 }
 
-func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value {
+func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
 	var col *core.Column
 	if col = table.GetColumnIdx(key, idx); col == nil {
-		//session.engine.logger.Warnf("table %v has no column %v. %v", table.Name, key, table.ColumnsSeq())
-		return nil
+		return nil, ErrFieldIsNotExist{key, table.Name}
 	}
 
 	fieldValue, err := col.ValueOfV(dataStruct)
 	if err != nil {
-		session.engine.logger.Error(err)
-		return nil
+		return nil, err
 	}
 
 	if !fieldValue.IsValid() || !fieldValue.CanSet() {
-		session.engine.logger.Warnf("table %v's column %v is not valid or cannot set", table.Name, key)
-		return nil
+		return nil, ErrFieldIsNotValid{key, table.Name}
 	}
-	return fieldValue
+
+	return fieldValue, nil
 }
 
 // Cell cell is a result of one column field
@@ -407,409 +405,417 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
 		}
 		tempMap[lKey] = idx
 
-		if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil {
-			rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
-
-			// if row is null then ignore
-			if rawValue.Interface() == nil {
-				continue
+		fieldValue, err := session.getField(dataStruct, key, table, idx)
+		if err != nil {
+			if !strings.Contains(err.Error(), "is not valid") {
+				session.engine.logger.Warn(err)
 			}
+			continue
+		}
+		if fieldValue == nil {
+			continue
+		}
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
 
-			if fieldValue.CanAddr() {
-				if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
-					if data, err := value2Bytes(&rawValue); err == nil {
-						if err := structConvert.FromDB(data); err != nil {
-							return nil, err
-						}
-					} else {
-						return nil, err
-					}
-					continue
-				}
-			}
+		// if row is null then ignore
+		if rawValue.Interface() == nil {
+			continue
+		}
 
-			if _, ok := fieldValue.Interface().(core.Conversion); ok {
+		if fieldValue.CanAddr() {
+			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 				if data, err := value2Bytes(&rawValue); err == nil {
-					if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
-						fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+					if err := structConvert.FromDB(data); err != nil {
+						return nil, err
 					}
-					fieldValue.Interface().(core.Conversion).FromDB(data)
 				} else {
 					return nil, err
 				}
 				continue
 			}
+		}
 
-			rawValueType := reflect.TypeOf(rawValue.Interface())
-			vv := reflect.ValueOf(rawValue.Interface())
-			col := table.GetColumnIdx(key, idx)
-			if col.IsPrimaryKey {
-				pk = append(pk, rawValue.Interface())
+		if _, ok := fieldValue.Interface().(core.Conversion); ok {
+			if data, err := value2Bytes(&rawValue); err == nil {
+				if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
+					fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+				}
+				fieldValue.Interface().(core.Conversion).FromDB(data)
+			} else {
+				return nil, err
 			}
-			fieldType := fieldValue.Type()
-			hasAssigned := false
+			continue
+		}
 
-			if col.SQLType.IsJson() {
-				var bs []byte
-				if rawValueType.Kind() == reflect.String {
-					bs = []byte(vv.String())
-				} else if rawValueType.ConvertibleTo(core.BytesType) {
-					bs = vv.Bytes()
-				} else {
-					return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
-				}
+		rawValueType := reflect.TypeOf(rawValue.Interface())
+		vv := reflect.ValueOf(rawValue.Interface())
+		col := table.GetColumnIdx(key, idx)
+		if col.IsPrimaryKey {
+			pk = append(pk, rawValue.Interface())
+		}
+		fieldType := fieldValue.Type()
+		hasAssigned := false
+
+		if col.SQLType.IsJson() {
+			var bs []byte
+			if rawValueType.Kind() == reflect.String {
+				bs = []byte(vv.String())
+			} else if rawValueType.ConvertibleTo(core.BytesType) {
+				bs = vv.Bytes()
+			} else {
+				return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
+			}
 
-				hasAssigned = true
+			hasAssigned = true
 
-				if len(bs) > 0 {
-					if fieldType.Kind() == reflect.String {
-						fieldValue.SetString(string(bs))
-						continue
+			if len(bs) > 0 {
+				if fieldType.Kind() == reflect.String {
+					fieldValue.SetString(string(bs))
+					continue
+				}
+				if fieldValue.CanAddr() {
+					err := json.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						return nil, err
 					}
-					if fieldValue.CanAddr() {
-						err := json.Unmarshal(bs, fieldValue.Addr().Interface())
-						if err != nil {
-							return nil, err
-						}
-					} else {
-						x := reflect.New(fieldType)
-						err := json.Unmarshal(bs, x.Interface())
-						if err != nil {
-							return nil, err
-						}
-						fieldValue.Set(x.Elem())
+				} else {
+					x := reflect.New(fieldType)
+					err := json.Unmarshal(bs, x.Interface())
+					if err != nil {
+						return nil, err
 					}
+					fieldValue.Set(x.Elem())
 				}
-
-				continue
 			}
 
-			switch fieldType.Kind() {
-			case reflect.Complex64, reflect.Complex128:
-				// TODO: reimplement this
-				var bs []byte
-				if rawValueType.Kind() == reflect.String {
-					bs = []byte(vv.String())
-				} else if rawValueType.ConvertibleTo(core.BytesType) {
-					bs = vv.Bytes()
-				}
+			continue
+		}
 
-				hasAssigned = true
-				if len(bs) > 0 {
-					if fieldValue.CanAddr() {
-						err := json.Unmarshal(bs, fieldValue.Addr().Interface())
-						if err != nil {
-							return nil, err
-						}
-					} else {
-						x := reflect.New(fieldType)
-						err := json.Unmarshal(bs, x.Interface())
-						if err != nil {
-							return nil, err
-						}
-						fieldValue.Set(x.Elem())
+		switch fieldType.Kind() {
+		case reflect.Complex64, reflect.Complex128:
+			// TODO: reimplement this
+			var bs []byte
+			if rawValueType.Kind() == reflect.String {
+				bs = []byte(vv.String())
+			} else if rawValueType.ConvertibleTo(core.BytesType) {
+				bs = vv.Bytes()
+			}
+
+			hasAssigned = true
+			if len(bs) > 0 {
+				if fieldValue.CanAddr() {
+					err := json.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						return nil, err
+					}
+				} else {
+					x := reflect.New(fieldType)
+					err := json.Unmarshal(bs, x.Interface())
+					if err != nil {
+						return nil, err
 					}
+					fieldValue.Set(x.Elem())
 				}
+			}
+		case reflect.Slice, reflect.Array:
+			switch rawValueType.Kind() {
 			case reflect.Slice, reflect.Array:
-				switch rawValueType.Kind() {
-				case reflect.Slice, reflect.Array:
-					switch rawValueType.Elem().Kind() {
-					case reflect.Uint8:
-						if fieldType.Elem().Kind() == reflect.Uint8 {
-							hasAssigned = true
-							if col.SQLType.IsText() {
-								x := reflect.New(fieldType)
-								err := json.Unmarshal(vv.Bytes(), x.Interface())
-								if err != nil {
-									return nil, err
+				switch rawValueType.Elem().Kind() {
+				case reflect.Uint8:
+					if fieldType.Elem().Kind() == reflect.Uint8 {
+						hasAssigned = true
+						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))
+									}
 								}
-								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)))
-									}
+								for i := 0; i < vv.Len(); i++ {
+									fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
 								}
 							}
 						}
 					}
 				}
-			case reflect.String:
-				if rawValueType.Kind() == reflect.String {
-					hasAssigned = true
-					fieldValue.SetString(vv.String())
-				}
-			case reflect.Bool:
-				if rawValueType.Kind() == reflect.Bool {
-					hasAssigned = true
-					fieldValue.SetBool(vv.Bool())
-				}
+			}
+		case reflect.String:
+			if rawValueType.Kind() == reflect.String {
+				hasAssigned = true
+				fieldValue.SetString(vv.String())
+			}
+		case reflect.Bool:
+			if rawValueType.Kind() == reflect.Bool {
+				hasAssigned = true
+				fieldValue.SetBool(vv.Bool())
+			}
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			switch rawValueType.Kind() {
 			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-				switch rawValueType.Kind() {
-				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-					hasAssigned = true
-					fieldValue.SetInt(vv.Int())
-				}
+				hasAssigned = true
+				fieldValue.SetInt(vv.Int())
+			}
+		case reflect.Float32, reflect.Float64:
+			switch rawValueType.Kind() {
 			case reflect.Float32, reflect.Float64:
-				switch rawValueType.Kind() {
-				case reflect.Float32, reflect.Float64:
-					hasAssigned = true
-					fieldValue.SetFloat(vv.Float())
-				}
+				hasAssigned = true
+				fieldValue.SetFloat(vv.Float())
+			}
+		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+			switch rawValueType.Kind() {
 			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
-				switch rawValueType.Kind() {
-				case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
-					hasAssigned = true
-					fieldValue.SetUint(vv.Uint())
-				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-					hasAssigned = true
-					fieldValue.SetUint(uint64(vv.Int()))
+				hasAssigned = true
+				fieldValue.SetUint(vv.Uint())
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				hasAssigned = true
+				fieldValue.SetUint(uint64(vv.Int()))
+			}
+		case reflect.Struct:
+			if fieldType.ConvertibleTo(core.TimeType) {
+				dbTZ := session.engine.DatabaseTZ
+				if col.TimeZone != nil {
+					dbTZ = col.TimeZone
 				}
-			case reflect.Struct:
-				if fieldType.ConvertibleTo(core.TimeType) {
-					dbTZ := session.engine.DatabaseTZ
-					if col.TimeZone != nil {
-						dbTZ = col.TimeZone
-					}
 
-					if rawValueType == core.TimeType {
-						hasAssigned = true
-
-						t := vv.Convert(core.TimeType).Interface().(time.Time)
-
-						z, _ := t.Zone()
-						// 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
-							session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
-							t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
-								t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
-						}
+				if rawValueType == core.TimeType {
+					hasAssigned = true
 
-						t = t.In(session.engine.TZLocation)
-						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
-					} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
-						rawValueType == core.Int32Type {
-						hasAssigned = true
+					t := vv.Convert(core.TimeType).Interface().(time.Time)
 
-						t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
-						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
-					} else {
-						if d, ok := vv.Interface().([]uint8); ok {
-							hasAssigned = true
-							t, err := session.byte2Time(col, d)
-							if err != nil {
-								session.engine.logger.Error("byte2Time error:", err.Error())
-								hasAssigned = false
-							} else {
-								fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
-							}
-						} else if d, ok := vv.Interface().(string); ok {
-							hasAssigned = true
-							t, err := session.str2Time(col, d)
-							if err != nil {
-								session.engine.logger.Error("byte2Time error:", err.Error())
-								hasAssigned = false
-							} else {
-								fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
-							}
-						} else {
-							return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
-						}
-					}
-				} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
-					// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
-					hasAssigned = true
-					if err := nulVal.Scan(vv.Interface()); err != nil {
-						session.engine.logger.Error("sql.Sanner error:", err.Error())
-						hasAssigned = false
-					}
-				} else if col.SQLType.IsJson() {
-					if rawValueType.Kind() == reflect.String {
-						hasAssigned = true
-						x := reflect.New(fieldType)
-						if len([]byte(vv.String())) > 0 {
-							err := json.Unmarshal([]byte(vv.String()), x.Interface())
-							if err != nil {
-								return nil, err
-							}
-							fieldValue.Set(x.Elem())
-						}
-					} else if rawValueType.Kind() == reflect.Slice {
-						hasAssigned = true
-						x := reflect.New(fieldType)
-						if len(vv.Bytes()) > 0 {
-							err := json.Unmarshal(vv.Bytes(), x.Interface())
-							if err != nil {
-								return nil, err
-							}
-							fieldValue.Set(x.Elem())
-						}
-					}
-				} else if session.statement.UseCascade {
-					table, err := session.engine.autoMapType(*fieldValue)
-					if err != nil {
-						return nil, err
+					z, _ := t.Zone()
+					// 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
+						session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+						t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
+							t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
 					}
 
+					t = t.In(session.engine.TZLocation)
+					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+				} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
+					rawValueType == core.Int32Type {
 					hasAssigned = true
-					if len(table.PrimaryKeys) != 1 {
-						return nil, errors.New("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())
-						has, err := session.ID(pk).NoCascade().get(structInter.Interface())
+					t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
+					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+				} else {
+					if d, ok := vv.Interface().([]uint8); ok {
+						hasAssigned = true
+						t, err := session.byte2Time(col, d)
 						if err != nil {
-							return nil, err
+							session.engine.logger.Error("byte2Time error:", err.Error())
+							hasAssigned = false
+						} else {
+							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 						}
-						if has {
-							fieldValue.Set(structInter.Elem())
+					} else if d, ok := vv.Interface().(string); ok {
+						hasAssigned = true
+						t, err := session.str2Time(col, d)
+						if err != nil {
+							session.engine.logger.Error("byte2Time error:", err.Error())
+							hasAssigned = false
 						} else {
-							return nil, errors.New("cascade obj is not exist")
+							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 						}
+					} else {
+						return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
 					}
 				}
-			case reflect.Ptr:
-				// !nashtsai! TODO merge duplicated codes above
-				switch fieldType {
-				// following types case matching ptr's native type, therefore assign ptr directly
-				case core.PtrStringType:
-					if rawValueType.Kind() == reflect.String {
-						x := vv.String()
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrBoolType:
-					if rawValueType.Kind() == reflect.Bool {
-						x := vv.Bool()
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrTimeType:
-					if rawValueType == core.PtrTimeType {
-						hasAssigned = true
-						var x = rawValue.Interface().(time.Time)
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrFloat64Type:
-					if rawValueType.Kind() == reflect.Float64 {
-						x := vv.Float()
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrUint64Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = uint64(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrInt64Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						x := vv.Int()
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrFloat32Type:
-					if rawValueType.Kind() == reflect.Float64 {
-						var x = float32(vv.Float())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrIntType:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = int(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrInt32Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = int32(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrInt8Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = int8(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrInt16Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = int16(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrUintType:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = uint(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.PtrUint32Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = uint32(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.Uint8Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = uint8(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.Uint16Type:
-					if rawValueType.Kind() == reflect.Int64 {
-						var x = uint16(vv.Int())
-						hasAssigned = true
-						fieldValue.Set(reflect.ValueOf(&x))
-					}
-				case core.Complex64Type:
-					var x complex64
+			} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
+				// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
+				hasAssigned = true
+				if err := nulVal.Scan(vv.Interface()); err != nil {
+					session.engine.logger.Error("sql.Sanner error:", err.Error())
+					hasAssigned = false
+				}
+			} else if col.SQLType.IsJson() {
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					x := reflect.New(fieldType)
 					if len([]byte(vv.String())) > 0 {
-						err := json.Unmarshal([]byte(vv.String()), &x)
+						err := json.Unmarshal([]byte(vv.String()), x.Interface())
 						if err != nil {
 							return nil, err
 						}
-						fieldValue.Set(reflect.ValueOf(&x))
+						fieldValue.Set(x.Elem())
 					}
+				} else if rawValueType.Kind() == reflect.Slice {
 					hasAssigned = true
-				case core.Complex128Type:
-					var x complex128
-					if len([]byte(vv.String())) > 0 {
-						err := json.Unmarshal([]byte(vv.String()), &x)
+					x := reflect.New(fieldType)
+					if len(vv.Bytes()) > 0 {
+						err := json.Unmarshal(vv.Bytes(), x.Interface())
 						if err != nil {
 							return nil, err
 						}
-						fieldValue.Set(reflect.ValueOf(&x))
+						fieldValue.Set(x.Elem())
 					}
-					hasAssigned = true
-				} // switch fieldType
-			} // switch fieldType.Kind()
-
-			// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
-			if !hasAssigned {
-				data, err := value2Bytes(&rawValue)
+				}
+			} else if session.statement.UseCascade {
+				table, err := session.engine.autoMapType(*fieldValue)
 				if err != nil {
 					return nil, err
 				}
 
-				if err = session.bytes2Value(col, fieldValue, data); err != nil {
+				hasAssigned = true
+				if len(table.PrimaryKeys) != 1 {
+					return nil, errors.New("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())
+					has, err := session.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")
+					}
+				}
+			}
+		case reflect.Ptr:
+			// !nashtsai! TODO merge duplicated codes above
+			switch fieldType {
+			// following types case matching ptr's native type, therefore assign ptr directly
+			case core.PtrStringType:
+				if rawValueType.Kind() == reflect.String {
+					x := vv.String()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrBoolType:
+				if rawValueType.Kind() == reflect.Bool {
+					x := vv.Bool()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrTimeType:
+				if rawValueType == core.PtrTimeType {
+					hasAssigned = true
+					var x = rawValue.Interface().(time.Time)
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrFloat64Type:
+				if rawValueType.Kind() == reflect.Float64 {
+					x := vv.Float()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUint64Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint64(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt64Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					x := vv.Int()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrFloat32Type:
+				if rawValueType.Kind() == reflect.Float64 {
+					var x = float32(vv.Float())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrIntType:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt32Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int32(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt8Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int8(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt16Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int16(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUintType:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUint32Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint32(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Uint8Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint8(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Uint16Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint16(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Complex64Type:
+				var x complex64
+				if len([]byte(vv.String())) > 0 {
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+				hasAssigned = true
+			case core.Complex128Type:
+				var x complex128
+				if len([]byte(vv.String())) > 0 {
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+				hasAssigned = true
+			} // switch fieldType
+		} // switch fieldType.Kind()
+
+		// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
+		if !hasAssigned {
+			data, err := value2Bytes(&rawValue)
+			if err != nil {
+				return nil, err
+			}
+
+			if err = session.bytes2Value(col, fieldValue, data); err != nil {
+				return nil, err
 			}
 		}
 	}
@@ -828,15 +834,6 @@ func (session *Session) LastSQL() (string, []interface{}) {
 	return session.lastSQL, session.lastSQLArgs
 }
 
-// tbName get some table's table name
-func (session *Session) tbNameNoSchema(table *core.Table) string {
-	if len(session.statement.AltTableName) > 0 {
-		return session.statement.AltTableName
-	}
-
-	return table.Name
-}
-
 // Unscoped always disable struct tag "deleted"
 func (session *Session) Unscoped() *Session {
 	session.statement.Unscoped()

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

@@ -4,6 +4,121 @@
 
 package xorm
 
+import (
+	"reflect"
+	"strings"
+	"time"
+
+	"github.com/go-xorm/core"
+)
+
+type incrParam struct {
+	colName string
+	arg     interface{}
+}
+
+type decrParam struct {
+	colName string
+	arg     interface{}
+}
+
+type exprParam struct {
+	colName string
+	expr    string
+}
+
+type columnMap []string
+
+func (m columnMap) contain(colName string) bool {
+	if len(m) == 0 {
+		return false
+	}
+
+	n := len(colName)
+	for _, mk := range m {
+		if len(mk) != n {
+			continue
+		}
+		if strings.EqualFold(mk, colName) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (m *columnMap) add(colName string) bool {
+	if m.contain(colName) {
+		return false
+	}
+	*m = append(*m, colName)
+	return true
+}
+
+func setColumnInt(bean interface{}, col *core.Column, t int64) {
+	v, err := col.ValueOf(bean)
+	if err != nil {
+		return
+	}
+	if v.CanSet() {
+		switch v.Type().Kind() {
+		case reflect.Int, reflect.Int64, reflect.Int32:
+			v.SetInt(t)
+		case reflect.Uint, reflect.Uint64, reflect.Uint32:
+			v.SetUint(uint64(t))
+		}
+	}
+}
+
+func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
+	v, err := col.ValueOf(bean)
+	if err != nil {
+		return
+	}
+	if v.CanSet() {
+		switch v.Type().Kind() {
+		case reflect.Struct:
+			v.Set(reflect.ValueOf(t).Convert(v.Type()))
+		case reflect.Int, reflect.Int64, reflect.Int32:
+			v.SetInt(t.Unix())
+		case reflect.Uint, reflect.Uint64, reflect.Uint32:
+			v.SetUint(uint64(t.Unix()))
+		}
+	}
+}
+
+func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
+	if len(m) == 0 {
+		return false, false
+	}
+
+	n := len(col.Name)
+
+	for mk := range m {
+		if len(mk) != n {
+			continue
+		}
+		if strings.EqualFold(mk, col.Name) {
+			return m[mk], true
+		}
+	}
+
+	return false, false
+}
+
+func col2NewCols(columns ...string) []string {
+	newColumns := make([]string, 0, len(columns))
+	for _, col := range columns {
+		col = strings.Replace(col, "`", "", -1)
+		col = strings.Replace(col, `"`, "", -1)
+		ccols := strings.Split(col, ",")
+		for _, c := range ccols {
+			newColumns = append(newColumns, strings.TrimSpace(c))
+		}
+	}
+	return newColumns
+}
+
 // Incr provides a query string like "count = count + 1"
 func (session *Session) Incr(column string, arg ...interface{}) *Session {
 	session.statement.Incr(column, arg...)

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

@@ -27,7 +27,7 @@ func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string,
 		return ErrCacheFailed
 	}
 
-	cacher := session.engine.getCacher2(table)
+	cacher := session.engine.getCacher(tableName)
 	pkColumns := table.PKColumns()
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 	if err != nil {
@@ -79,7 +79,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
 		defer session.Close()
 	}
 
-	if err := session.statement.setRefValue(rValue(bean)); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return 0, err
 	}
 
@@ -199,7 +199,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
 		})
 	}
 
-	if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
+	if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
 		session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
 	}
 

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

@@ -57,7 +57,7 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) {
 			}
 
 			if beanValue.Elem().Kind() == reflect.Struct {
-				if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
+				if err := session.statement.setRefBean(bean[0]); err != nil {
 					return false, err
 				}
 			}

+ 13 - 6
vendor/github.com/go-xorm/xorm/session_find.go

@@ -55,6 +55,9 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
 	if session.statement.selectStr != "" {
 		session.statement.selectStr = ""
 	}
+	if session.statement.OrderStr != "" {
+		session.statement.OrderStr = ""
+	}
 
 	return session.Count(reflect.New(sliceElementType).Interface())
 }
@@ -72,7 +75,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
 		if sliceElementType.Kind() == reflect.Ptr {
 			if sliceElementType.Elem().Kind() == reflect.Struct {
 				pv := reflect.New(sliceElementType.Elem())
-				if err := session.statement.setRefValue(pv.Elem()); err != nil {
+				if err := session.statement.setRefValue(pv); err != nil {
 					return err
 				}
 			} else {
@@ -80,7 +83,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
 			}
 		} else if sliceElementType.Kind() == reflect.Struct {
 			pv := reflect.New(sliceElementType)
-			if err := session.statement.setRefValue(pv.Elem()); err != nil {
+			if err := session.statement.setRefValue(pv); err != nil {
 				return err
 			}
 		} else {
@@ -158,7 +161,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
 		}
 
 		args = append(session.statement.joinArgs, condArgs...)
-		sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true)
+		sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
 		if err != nil {
 			return err
 		}
@@ -173,7 +176,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
 	}
 
 	if session.canCache() {
-		if cacher := session.engine.getCacher2(table); cacher != nil &&
+		if cacher := session.engine.getCacher(table.Name); cacher != nil &&
 			!session.statement.IsDistinct &&
 			!session.statement.unscoped {
 			err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
@@ -318,6 +321,12 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 		return ErrCacheFailed
 	}
 
+	tableName := session.statement.TableName()
+	cacher := session.engine.getCacher(tableName)
+	if cacher == nil {
+		return nil
+	}
+
 	for _, filter := range session.engine.dialect.Filters() {
 		sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
 	}
@@ -327,9 +336,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 		return ErrCacheFailed
 	}
 
-	tableName := session.statement.TableName()
 	table := session.statement.RefTable
-	cacher := session.engine.getCacher2(table)
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 	if err != nil {
 		rows, err := session.queryRows(newsql, args...)

+ 4 - 3
vendor/github.com/go-xorm/xorm/session_get.go

@@ -31,7 +31,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
 	}
 
 	if beanValue.Elem().Kind() == reflect.Struct {
-		if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
+		if err := session.statement.setRefBean(bean); err != nil {
 			return false, err
 		}
 	}
@@ -57,7 +57,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
 	table := session.statement.RefTable
 
 	if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
-		if cacher := session.engine.getCacher2(table); cacher != nil &&
+		if cacher := session.engine.getCacher(table.Name); cacher != nil &&
 			!session.statement.unscoped {
 			has, err := session.cacheGet(bean, sqlStr, args...)
 			if err != ErrCacheFailed {
@@ -134,8 +134,9 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
 		return false, ErrCacheFailed
 	}
 
-	cacher := session.engine.getCacher2(session.statement.RefTable)
 	tableName := session.statement.TableName()
+	cacher := session.engine.getCacher(tableName)
+
 	session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
 	table := session.statement.RefTable
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)

+ 115 - 43
vendor/github.com/go-xorm/xorm/session_insert.go

@@ -66,11 +66,12 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
 		return 0, errors.New("could not insert a empty slice")
 	}
 
-	if err := session.statement.setRefValue(reflect.ValueOf(sliceValue.Index(0).Interface())); err != nil {
+	if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
 		return 0, err
 	}
 
-	if len(session.statement.TableName()) <= 0 {
+	tableName := session.statement.TableName()
+	if len(tableName) <= 0 {
 		return 0, ErrTableNotFound
 	}
 
@@ -115,15 +116,11 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
 				if col.IsDeleted {
 					continue
 				}
-				if session.statement.ColumnStr != "" {
-					if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
-						continue
-					}
+				if session.statement.omitColumnMap.contain(col.Name) {
+					continue
 				}
-				if session.statement.OmitStr != "" {
-					if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
-						continue
-					}
+				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+					continue
 				}
 				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
 					val, t := session.engine.nowTime(col)
@@ -170,15 +167,11 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
 				if col.IsDeleted {
 					continue
 				}
-				if session.statement.ColumnStr != "" {
-					if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
-						continue
-					}
+				if session.statement.omitColumnMap.contain(col.Name) {
+					continue
 				}
-				if session.statement.OmitStr != "" {
-					if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
-						continue
-					}
+				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+					continue
 				}
 				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
 					val, t := session.engine.nowTime(col)
@@ -213,7 +206,6 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
 
 	var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
 	var statement string
-	var tableName = session.statement.TableName()
 	if session.engine.dialect.DBType() == core.ORACLE {
 		sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
 		temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
@@ -240,9 +232,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
 		return 0, err
 	}
 
-	if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
-		session.cacheInsert(table, tableName)
-	}
+	session.cacheInsert(tableName)
 
 	lenAfterClosures := len(session.afterClosures)
 	for i := 0; i < size; i++ {
@@ -298,7 +288,7 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
 }
 
 func (session *Session) innerInsert(bean interface{}) (int64, error) {
-	if err := session.statement.setRefValue(rValue(bean)); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return 0, err
 	}
 	if len(session.statement.TableName()) <= 0 {
@@ -316,8 +306,8 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
 	if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
 		processor.BeforeInsert()
 	}
-	// --
-	colNames, args, err := genCols(session.statement.RefTable, session, bean, false, false)
+
+	colNames, args, err := session.genInsertColumns(bean)
 	if err != nil {
 		return 0, err
 	}
@@ -402,9 +392,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
 
 		defer handleAfterInsertProcessorFunc(bean)
 
-		if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
-			session.cacheInsert(table, tableName)
-		}
+		session.cacheInsert(tableName)
 
 		if table.Version != "" && session.statement.checkVersion {
 			verValue, err := table.VersionColumn().ValueOf(bean)
@@ -447,9 +435,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
 		}
 		defer handleAfterInsertProcessorFunc(bean)
 
-		if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
-			session.cacheInsert(table, tableName)
-		}
+		session.cacheInsert(tableName)
 
 		if table.Version != "" && session.statement.checkVersion {
 			verValue, err := table.VersionColumn().ValueOf(bean)
@@ -490,9 +476,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
 
 		defer handleAfterInsertProcessorFunc(bean)
 
-		if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
-			session.cacheInsert(table, tableName)
-		}
+		session.cacheInsert(tableName)
 
 		if table.Version != "" && session.statement.checkVersion {
 			verValue, err := table.VersionColumn().ValueOf(bean)
@@ -539,16 +523,104 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
 	return session.innerInsert(bean)
 }
 
-func (session *Session) cacheInsert(table *core.Table, tables ...string) error {
-	if table == nil {
-		return ErrCacheFailed
+func (session *Session) cacheInsert(table string) error {
+	if !session.statement.UseCache {
+		return nil
 	}
-
-	cacher := session.engine.getCacher2(table)
-	for _, t := range tables {
-		session.engine.logger.Debug("[cache] clear sql:", t)
-		cacher.ClearIds(t)
+	cacher := session.engine.getCacher(table)
+	if cacher == nil {
+		return nil
 	}
-
+	session.engine.logger.Debug("[cache] clear sql:", table)
+	cacher.ClearIds(table)
 	return nil
 }
+
+// genInsertColumns generates insert needed columns
+func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
+	table := session.statement.RefTable
+	colNames := make([]string, 0, len(table.ColumnsSeq()))
+	args := make([]interface{}, 0, len(table.ColumnsSeq()))
+
+	for _, col := range table.Columns() {
+		if col.MapType == core.ONLYFROMDB {
+			continue
+		}
+
+		if col.IsDeleted {
+			continue
+		}
+
+		if session.statement.omitColumnMap.contain(col.Name) {
+			continue
+		}
+
+		if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+			continue
+		}
+
+		if _, ok := session.statement.incrColumns[col.Name]; ok {
+			continue
+		} else if _, ok := session.statement.decrColumns[col.Name]; ok {
+			continue
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			return nil, nil, err
+		}
+		fieldValue := *fieldValuePtr
+
+		if col.IsAutoIncrement {
+			switch fieldValue.Type().Kind() {
+			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
+				if fieldValue.Int() == 0 {
+					continue
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
+				if fieldValue.Uint() == 0 {
+					continue
+				}
+			case reflect.String:
+				if len(fieldValue.String()) == 0 {
+					continue
+				}
+			case reflect.Ptr:
+				if fieldValue.Pointer() == 0 {
+					continue
+				}
+			}
+		}
+
+		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
+		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
+			if col.Nullable && isZero(fieldValue.Interface()) {
+				var nilValue *int
+				fieldValue = reflect.ValueOf(nilValue)
+			}
+		}
+
+		if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
+			// if time is non-empty, then set to auto time
+			val, t := session.engine.nowTime(col)
+			args = append(args, val)
+
+			var colName = col.Name
+			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+				col := table.GetColumn(colName)
+				setColumnTime(bean, col, t)
+			})
+		} else if col.IsVersion && session.statement.checkVersion {
+			args = append(args, 1)
+		} else {
+			arg, err := session.value2Interface(col, fieldValue)
+			if err != nil {
+				return colNames, args, err
+			}
+			args = append(args, arg)
+		}
+
+		colNames = append(colNames, col.Name)
+	}
+	return colNames, args, nil
+}

+ 5 - 1
vendor/github.com/go-xorm/xorm/session_query.go

@@ -64,13 +64,17 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
 		}
 	}
 
+	if err := session.statement.processIDParam(); err != nil {
+		return "", nil, err
+	}
+
 	condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
 	if err != nil {
 		return "", nil, err
 	}
 
 	args := append(session.statement.joinArgs, condArgs...)
-	sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true)
+	sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
 	if err != nil {
 		return "", nil, err
 	}

+ 30 - 51
vendor/github.com/go-xorm/xorm/session_schema.go

@@ -6,9 +6,7 @@ package xorm
 
 import (
 	"database/sql"
-	"errors"
 	"fmt"
-	"reflect"
 	"strings"
 
 	"github.com/go-xorm/core"
@@ -34,8 +32,7 @@ func (session *Session) CreateTable(bean interface{}) error {
 }
 
 func (session *Session) createTable(bean interface{}) error {
-	v := rValue(bean)
-	if err := session.statement.setRefValue(v); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return err
 	}
 
@@ -54,8 +51,7 @@ func (session *Session) CreateIndexes(bean interface{}) error {
 }
 
 func (session *Session) createIndexes(bean interface{}) error {
-	v := rValue(bean)
-	if err := session.statement.setRefValue(v); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return err
 	}
 
@@ -78,8 +74,7 @@ func (session *Session) CreateUniques(bean interface{}) error {
 }
 
 func (session *Session) createUniques(bean interface{}) error {
-	v := rValue(bean)
-	if err := session.statement.setRefValue(v); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return err
 	}
 
@@ -103,8 +98,7 @@ func (session *Session) DropIndexes(bean interface{}) error {
 }
 
 func (session *Session) dropIndexes(bean interface{}) error {
-	v := rValue(bean)
-	if err := session.statement.setRefValue(v); err != nil {
+	if err := session.statement.setRefBean(bean); err != nil {
 		return err
 	}
 
@@ -128,11 +122,7 @@ func (session *Session) DropTable(beanOrTableName interface{}) error {
 }
 
 func (session *Session) dropTable(beanOrTableName interface{}) error {
-	tableName, err := session.engine.tableName(beanOrTableName)
-	if err != nil {
-		return err
-	}
-
+	tableName := session.engine.TableName(beanOrTableName)
 	var needDrop = true
 	if !session.engine.dialect.SupportDropIfExists() {
 		sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
@@ -144,8 +134,8 @@ func (session *Session) dropTable(beanOrTableName interface{}) error {
 	}
 
 	if needDrop {
-		sqlStr := session.engine.Dialect().DropTableSql(tableName)
-		_, err = session.exec(sqlStr)
+		sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
+		_, err := session.exec(sqlStr)
 		return err
 	}
 	return nil
@@ -157,10 +147,7 @@ func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error)
 		defer session.Close()
 	}
 
-	tableName, err := session.engine.tableName(beanOrTableName)
-	if err != nil {
-		return false, err
-	}
+	tableName := session.engine.TableName(beanOrTableName)
 
 	return session.isTableExist(tableName)
 }
@@ -173,24 +160,15 @@ func (session *Session) isTableExist(tableName string) (bool, error) {
 
 // IsTableEmpty if table have any records
 func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
-	v := rValue(bean)
-	t := v.Type()
-
-	if t.Kind() == reflect.String {
-		if session.isAutoClose {
-			defer session.Close()
-		}
-		return session.isTableEmpty(bean.(string))
-	} else if t.Kind() == reflect.Struct {
-		rows, err := session.Count(bean)
-		return rows == 0, err
+	if session.isAutoClose {
+		defer session.Close()
 	}
-	return false, errors.New("bean should be a struct or struct's point")
+	return session.isTableEmpty(session.engine.TableName(bean))
 }
 
 func (session *Session) isTableEmpty(tableName string) (bool, error) {
 	var total int64
-	sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName))
+	sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
 	err := session.queryRow(sqlStr).Scan(&total)
 	if err != nil {
 		if err == sql.ErrNoRows {
@@ -270,7 +248,8 @@ func (session *Session) Sync2(beans ...interface{}) error {
 			return err
 		}
 		structTables = append(structTables, table)
-		var tbName = session.tbNameNoSchema(table)
+		tbName := engine.TableName(bean)
+		tbNameWithSchema := engine.TableName(tbName, true)
 
 		var oriTable *core.Table
 		for _, tb := range tables {
@@ -315,32 +294,32 @@ func (session *Session) Sync2(beans ...interface{}) error {
 							if engine.dialect.DBType() == core.MYSQL ||
 								engine.dialect.DBType() == core.POSTGRES {
 								engine.logger.Infof("Table %s column %s change type from %s to %s\n",
-									tbName, col.Name, curType, expectedType)
-								_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
+									tbNameWithSchema, col.Name, curType, expectedType)
+								_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 							} else {
 								engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
-									tbName, col.Name, curType, expectedType)
+									tbNameWithSchema, col.Name, curType, expectedType)
 							}
 						} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
 							if engine.dialect.DBType() == core.MYSQL {
 								if oriCol.Length < col.Length {
 									engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
-										tbName, col.Name, oriCol.Length, col.Length)
-									_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
+										tbNameWithSchema, col.Name, oriCol.Length, col.Length)
+									_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 								}
 							}
 						} else {
 							if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
 								engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
-									tbName, col.Name, curType, expectedType)
+									tbNameWithSchema, col.Name, curType, expectedType)
 							}
 						}
 					} else if expectedType == core.Varchar {
 						if engine.dialect.DBType() == core.MYSQL {
 							if oriCol.Length < col.Length {
 								engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
-									tbName, col.Name, oriCol.Length, col.Length)
-								_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
+									tbNameWithSchema, col.Name, oriCol.Length, col.Length)
+								_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 							}
 						}
 					}
@@ -354,7 +333,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
 					}
 				} else {
 					session.statement.RefTable = table
-					session.statement.tableName = tbName
+					session.statement.tableName = tbNameWithSchema
 					err = session.addColumn(col.Name)
 				}
 				if err != nil {
@@ -377,7 +356,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
 
 				if oriIndex != nil {
 					if oriIndex.Type != index.Type {
-						sql := engine.dialect.DropIndexSql(tbName, oriIndex)
+						sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex)
 						_, err = session.exec(sql)
 						if err != nil {
 							return err
@@ -393,7 +372,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
 
 			for name2, index2 := range oriTable.Indexes {
 				if _, ok := foundIndexNames[name2]; !ok {
-					sql := engine.dialect.DropIndexSql(tbName, index2)
+					sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2)
 					_, err = session.exec(sql)
 					if err != nil {
 						return err
@@ -404,12 +383,12 @@ func (session *Session) Sync2(beans ...interface{}) error {
 			for name, index := range addedNames {
 				if index.Type == core.UniqueType {
 					session.statement.RefTable = table
-					session.statement.tableName = tbName
-					err = session.addUnique(tbName, name)
+					session.statement.tableName = tbNameWithSchema
+					err = session.addUnique(tbNameWithSchema, name)
 				} else if index.Type == core.IndexType {
 					session.statement.RefTable = table
-					session.statement.tableName = tbName
-					err = session.addIndex(tbName, name)
+					session.statement.tableName = tbNameWithSchema
+					err = session.addIndex(tbNameWithSchema, name)
 				}
 				if err != nil {
 					return err
@@ -434,7 +413,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
 
 		for _, colName := range table.ColumnsSeq() {
 			if oriTable.GetColumn(colName) == nil {
-				engine.logger.Warnf("Table %s has column %s but struct has not related field", table.Name, colName)
+				engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(table.Name, true), colName)
 			}
 		}
 	}

+ 101 - 14
vendor/github.com/go-xorm/xorm/session_update.go

@@ -40,7 +40,7 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string,
 		}
 	}
 
-	cacher := session.engine.getCacher2(table)
+	cacher := session.engine.getCacher(tableName)
 	session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
 	if err != nil {
@@ -167,7 +167,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 	var isMap = t.Kind() == reflect.Map
 	var isStruct = t.Kind() == reflect.Struct
 	if isStruct {
-		if err := session.statement.setRefValue(v); err != nil {
+		if err := session.statement.setRefBean(bean); err != nil {
 			return 0, err
 		}
 
@@ -176,12 +176,10 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 		}
 
 		if session.statement.ColumnStr == "" {
-			colNames, args = buildUpdates(session.engine, session.statement.RefTable, bean, false, false,
-				false, false, session.statement.allUseBool, session.statement.useAllCols,
-				session.statement.mustColumnMap, session.statement.nullableMap,
-				session.statement.columnMap, true, session.statement.unscoped)
+			colNames, args = session.statement.buildUpdates(bean, false, false,
+				false, false, true)
 		} else {
-			colNames, args, err = genCols(session.statement.RefTable, session, bean, true, true)
+			colNames, args, err = session.genUpdateColumns(bean)
 			if err != nil {
 				return 0, err
 			}
@@ -202,7 +200,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 	table := session.statement.RefTable
 
 	if session.statement.UseAutoTime && table != nil && table.Updated != "" {
-		if _, ok := session.statement.columnMap[strings.ToLower(table.Updated)]; !ok {
+		if !session.statement.columnMap.contain(table.Updated) &&
+			!session.statement.omitColumnMap.contain(table.Updated) {
 			colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
 			col := table.UpdatedColumn()
 			val, t := session.engine.nowTime(col)
@@ -362,12 +361,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 		}
 	}
 
-	if table != nil {
-		if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
-			//session.cacheUpdate(table, tableName, sqlStr, args...)
-			cacher.ClearIds(tableName)
-			cacher.ClearBeans(tableName)
-		}
+	if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
+		//session.cacheUpdate(table, tableName, sqlStr, args...)
+		session.engine.logger.Debug("[cacheUpdate] clear table ", tableName)
+		cacher.ClearIds(tableName)
+		cacher.ClearBeans(tableName)
 	}
 
 	// handle after update processors
@@ -402,3 +400,92 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 
 	return res.RowsAffected()
 }
+
+func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) {
+	table := session.statement.RefTable
+	colNames := make([]string, 0, len(table.ColumnsSeq()))
+	args := make([]interface{}, 0, len(table.ColumnsSeq()))
+
+	for _, col := range table.Columns() {
+		if !col.IsVersion && !col.IsCreated && !col.IsUpdated {
+			if session.statement.omitColumnMap.contain(col.Name) {
+				continue
+			}
+		}
+		if col.MapType == core.ONLYFROMDB {
+			continue
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			return nil, nil, err
+		}
+		fieldValue := *fieldValuePtr
+
+		if col.IsAutoIncrement {
+			switch fieldValue.Type().Kind() {
+			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
+				if fieldValue.Int() == 0 {
+					continue
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
+				if fieldValue.Uint() == 0 {
+					continue
+				}
+			case reflect.String:
+				if len(fieldValue.String()) == 0 {
+					continue
+				}
+			case reflect.Ptr:
+				if fieldValue.Pointer() == 0 {
+					continue
+				}
+			}
+		}
+
+		if col.IsDeleted || col.IsCreated {
+			continue
+		}
+
+		if len(session.statement.columnMap) > 0 {
+			if !session.statement.columnMap.contain(col.Name) {
+				continue
+			} else if _, ok := session.statement.incrColumns[col.Name]; ok {
+				continue
+			} else if _, ok := session.statement.decrColumns[col.Name]; ok {
+				continue
+			}
+		}
+
+		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
+		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
+			if col.Nullable && isZero(fieldValue.Interface()) {
+				var nilValue *int
+				fieldValue = reflect.ValueOf(nilValue)
+			}
+		}
+
+		if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
+			// if time is non-empty, then set to auto time
+			val, t := session.engine.nowTime(col)
+			args = append(args, val)
+
+			var colName = col.Name
+			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+				col := table.GetColumn(colName)
+				setColumnTime(bean, col, t)
+			})
+		} else if col.IsVersion && session.statement.checkVersion {
+			args = append(args, 1)
+		} else {
+			arg, err := session.value2Interface(col, fieldValue)
+			if err != nil {
+				return colNames, args, err
+			}
+			args = append(args, arg)
+		}
+
+		colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
+	}
+	return colNames, args, nil
+}

+ 87 - 114
vendor/github.com/go-xorm/xorm/statement.go

@@ -18,21 +18,6 @@ import (
 	"github.com/go-xorm/core"
 )
 
-type incrParam struct {
-	colName string
-	arg     interface{}
-}
-
-type decrParam struct {
-	colName string
-	arg     interface{}
-}
-
-type exprParam struct {
-	colName string
-	expr    string
-}
-
 // Statement save all the sql info for executing SQL
 type Statement struct {
 	RefTable        *core.Table
@@ -47,7 +32,6 @@ type Statement struct {
 	HavingStr       string
 	ColumnStr       string
 	selectStr       string
-	columnMap       map[string]bool
 	useAllCols      bool
 	OmitStr         string
 	AltTableName    string
@@ -67,6 +51,8 @@ type Statement struct {
 	allUseBool      bool
 	checkVersion    bool
 	unscoped        bool
+	columnMap       columnMap
+	omitColumnMap   columnMap
 	mustColumnMap   map[string]bool
 	nullableMap     map[string]bool
 	incrColumns     map[string]incrParam
@@ -89,7 +75,8 @@ func (statement *Statement) Init() {
 	statement.HavingStr = ""
 	statement.ColumnStr = ""
 	statement.OmitStr = ""
-	statement.columnMap = make(map[string]bool)
+	statement.columnMap = columnMap{}
+	statement.omitColumnMap = columnMap{}
 	statement.AltTableName = ""
 	statement.tableName = ""
 	statement.idParam = nil
@@ -221,34 +208,33 @@ func (statement *Statement) setRefValue(v reflect.Value) error {
 	if err != nil {
 		return err
 	}
-	statement.tableName = statement.Engine.tbName(v)
+	statement.tableName = statement.Engine.TableName(v, true)
 	return nil
 }
 
-// Table tempororily set table name, the parameter could be a string or a pointer of struct
-func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
-	v := rValue(tableNameOrBean)
-	t := v.Type()
-	if t.Kind() == reflect.String {
-		statement.AltTableName = tableNameOrBean.(string)
-	} else if t.Kind() == reflect.Struct {
-		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)
+func (statement *Statement) setRefBean(bean interface{}) error {
+	var err error
+	statement.RefTable, err = statement.Engine.autoMapType(rValue(bean))
+	if err != nil {
+		return err
 	}
-	return statement
+	statement.tableName = statement.Engine.TableName(bean, true)
+	return nil
 }
 
 // Auto generating update columnes and values according a struct
-func buildUpdates(engine *Engine, table *core.Table, bean interface{},
-	includeVersion bool, includeUpdated bool, includeNil bool,
-	includeAutoIncr bool, allUseBool bool, useAllCols bool,
-	mustColumnMap map[string]bool, nullableMap map[string]bool,
-	columnMap map[string]bool, update, unscoped bool) ([]string, []interface{}) {
+func (statement *Statement) buildUpdates(bean interface{},
+	includeVersion, includeUpdated, includeNil,
+	includeAutoIncr, update bool) ([]string, []interface{}) {
+	engine := statement.Engine
+	table := statement.RefTable
+	allUseBool := statement.allUseBool
+	useAllCols := statement.useAllCols
+	mustColumnMap := statement.mustColumnMap
+	nullableMap := statement.nullableMap
+	columnMap := statement.columnMap
+	omitColumnMap := statement.omitColumnMap
+	unscoped := statement.unscoped
 
 	var colNames = make([]string, 0)
 	var args = make([]interface{}, 0)
@@ -268,7 +254,10 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 		if col.IsDeleted && !unscoped {
 			continue
 		}
-		if use, ok := columnMap[strings.ToLower(col.Name)]; ok && !use {
+		if omitColumnMap.contain(col.Name) {
+			continue
+		}
+		if len(columnMap) > 0 && !columnMap.contain(col.Name) {
 			continue
 		}
 
@@ -604,17 +593,10 @@ func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
 }
 
 func (statement *Statement) colmap2NewColsWithQuote() []string {
-	newColumns := make([]string, 0, len(statement.columnMap))
-	for col := range statement.columnMap {
-		fields := strings.Split(strings.TrimSpace(col), ".")
-		if len(fields) == 1 {
-			newColumns = append(newColumns, statement.Engine.quote(fields[0]))
-		} else if len(fields) == 2 {
-			newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+
-				statement.Engine.quote(fields[1]))
-		} else {
-			panic(errors.New("unwanted colnames"))
-		}
+	newColumns := make([]string, len(statement.columnMap), len(statement.columnMap))
+	copy(newColumns, statement.columnMap)
+	for i := 0; i < len(statement.columnMap); i++ {
+		newColumns[i] = statement.Engine.Quote(newColumns[i])
 	}
 	return newColumns
 }
@@ -642,10 +624,11 @@ func (statement *Statement) Select(str string) *Statement {
 func (statement *Statement) Cols(columns ...string) *Statement {
 	cols := col2NewCols(columns...)
 	for _, nc := range cols {
-		statement.columnMap[strings.ToLower(nc)] = true
+		statement.columnMap.add(nc)
 	}
 
 	newColumns := statement.colmap2NewColsWithQuote()
+
 	statement.ColumnStr = strings.Join(newColumns, ", ")
 	statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1)
 	return statement
@@ -680,7 +663,7 @@ func (statement *Statement) UseBool(columns ...string) *Statement {
 func (statement *Statement) Omit(columns ...string) {
 	newColumns := col2NewCols(columns...)
 	for _, nc := range newColumns {
-		statement.columnMap[strings.ToLower(nc)] = false
+		statement.omitColumnMap = append(statement.omitColumnMap, nc)
 	}
 	statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
 }
@@ -743,6 +726,23 @@ func (statement *Statement) Asc(colNames ...string) *Statement {
 	return statement
 }
 
+// Table tempororily set table name, the parameter could be a string or a pointer of struct
+func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
+	v := rValue(tableNameOrBean)
+	t := v.Type()
+	if t.Kind() == reflect.Struct {
+		var err error
+		statement.RefTable, err = statement.Engine.autoMapType(v)
+		if err != nil {
+			statement.Engine.logger.Error(err)
+			return statement
+		}
+	}
+
+	statement.AltTableName = statement.Engine.TableName(tableNameOrBean, true)
+	return statement
+}
+
 // Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
 func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
 	var buf bytes.Buffer
@@ -752,39 +752,9 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
 		fmt.Fprintf(&buf, "%v JOIN ", joinOP)
 	}
 
-	switch tablename.(type) {
-	case []string:
-		t := tablename.([]string)
-		if len(t) > 1 {
-			fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(t[0]), statement.Engine.Quote(t[1]))
-		} else if len(t) == 1 {
-			fmt.Fprintf(&buf, statement.Engine.Quote(t[0]))
-		}
-	case []interface{}:
-		t := tablename.([]interface{})
-		l := len(t)
-		var table string
-		if l > 0 {
-			f := t[0]
-			v := rValue(f)
-			t := v.Type()
-			if t.Kind() == reflect.String {
-				table = f.(string)
-			} else if t.Kind() == reflect.Struct {
-				table = statement.Engine.tbName(v)
-			}
-		}
-		if l > 1 {
-			fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(table),
-				statement.Engine.Quote(fmt.Sprintf("%v", t[1])))
-		} else if l == 1 {
-			fmt.Fprintf(&buf, statement.Engine.Quote(table))
-		}
-	default:
-		fmt.Fprintf(&buf, statement.Engine.Quote(fmt.Sprintf("%v", tablename)))
-	}
+	tbName := statement.Engine.TableName(tablename, true)
 
-	fmt.Fprintf(&buf, " ON %v", condition)
+	fmt.Fprintf(&buf, "%s ON %v", tbName, condition)
 	statement.JoinStr = buf.String()
 	statement.joinArgs = append(statement.joinArgs, args...)
 	return statement
@@ -817,10 +787,12 @@ func (statement *Statement) genColumnStr() string {
 	columns := statement.RefTable.Columns()
 
 	for _, col := range columns {
-		if statement.OmitStr != "" {
-			if _, ok := getFlagForColumn(statement.columnMap, col); ok {
-				continue
-			}
+		if statement.omitColumnMap.contain(col.Name) {
+			continue
+		}
+
+		if len(statement.columnMap) > 0 && !statement.columnMap.contain(col.Name) {
+			continue
 		}
 
 		if col.MapType == core.ONLYTODB {
@@ -831,10 +803,6 @@ func (statement *Statement) genColumnStr() string {
 			buf.WriteString(", ")
 		}
 
-		if col.IsPrimaryKey && statement.Engine.Dialect().DBType() == "ql" {
-			buf.WriteString("id() AS ")
-		}
-
 		if statement.JoinStr != "" {
 			if statement.TableAlias != "" {
 				buf.WriteString(statement.TableAlias)
@@ -859,11 +827,13 @@ func (statement *Statement) genCreateTableSQL() string {
 func (statement *Statement) genIndexSQL() []string {
 	var sqls []string
 	tbName := statement.TableName()
-	quote := statement.Engine.Quote
-	for idxName, index := range statement.RefTable.Indexes {
+	for _, index := range statement.RefTable.Indexes {
 		if index.Type == core.IndexType {
-			sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
-				quote(tbName), quote(strings.Join(index.Cols, quote(","))))
+			sql := statement.Engine.dialect.CreateIndexSql(tbName, index)
+			/*idxTBName := strings.Replace(tbName, ".", "_", -1)
+			idxTBName = strings.Replace(idxTBName, `"`, "", -1)
+			sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(idxTBName, idxName)),
+				quote(tbName), quote(strings.Join(index.Cols, quote(","))))*/
 			sqls = append(sqls, sql)
 		}
 	}
@@ -889,16 +859,18 @@ func (statement *Statement) genUniqueSQL() []string {
 func (statement *Statement) genDelIndexSQL() []string {
 	var sqls []string
 	tbName := statement.TableName()
+	idxPrefixName := strings.Replace(tbName, `"`, "", -1)
+	idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1)
 	for idxName, index := range statement.RefTable.Indexes {
 		var rIdxName string
 		if index.Type == core.UniqueType {
-			rIdxName = uniqueName(tbName, idxName)
+			rIdxName = uniqueName(idxPrefixName, idxName)
 		} else if index.Type == core.IndexType {
-			rIdxName = indexName(tbName, idxName)
+			rIdxName = indexName(idxPrefixName, idxName)
 		}
-		sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(rIdxName))
+		sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(statement.Engine.TableName(rIdxName, true)))
 		if statement.Engine.dialect.IndexOnTable() {
-			sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(statement.TableName()))
+			sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(tbName))
 		}
 		sqls = append(sqls, sql)
 	}
@@ -949,7 +921,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
 	v := rValue(bean)
 	isStruct := v.Kind() == reflect.Struct
 	if isStruct {
-		statement.setRefValue(v)
+		statement.setRefBean(bean)
 	}
 
 	var columnStr = statement.ColumnStr
@@ -982,13 +954,17 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
 		if err := statement.mergeConds(bean); err != nil {
 			return "", nil, err
 		}
+	} else {
+		if err := statement.processIDParam(); err != nil {
+			return "", nil, err
+		}
 	}
 	condSQL, condArgs, err := builder.ToSQL(statement.cond)
 	if err != nil {
 		return "", nil, err
 	}
 
-	sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true)
+	sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true, true)
 	if err != nil {
 		return "", nil, err
 	}
@@ -1001,7 +977,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
 	var condArgs []interface{}
 	var err error
 	if len(beans) > 0 {
-		statement.setRefValue(rValue(beans[0]))
+		statement.setRefBean(beans[0])
 		condSQL, condArgs, err = statement.genConds(beans[0])
 	} else {
 		condSQL, condArgs, err = builder.ToSQL(statement.cond)
@@ -1018,7 +994,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
 			selectSQL = "count(*)"
 		}
 	}
-	sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false)
+	sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false, false)
 	if err != nil {
 		return "", nil, err
 	}
@@ -1027,7 +1003,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
 }
 
 func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
-	statement.setRefValue(rValue(bean))
+	statement.setRefBean(bean)
 
 	var sumStrs = make([]string, 0, len(columns))
 	for _, colName := range columns {
@@ -1043,7 +1019,7 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
 		return "", nil, err
 	}
 
-	sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true)
+	sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true, true)
 	if err != nil {
 		return "", nil, err
 	}
@@ -1051,7 +1027,7 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
 	return sqlStr, append(statement.joinArgs, condArgs...), nil
 }
 
-func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bool) (a string, err error) {
+func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (a string, err error) {
 	var distinct string
 	if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
 		distinct = "DISTINCT "
@@ -1062,10 +1038,6 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bo
 	var top string
 	var mssqlCondi string
 
-	if err := statement.processIDParam(); err != nil {
-		return "", err
-	}
-
 	var buf bytes.Buffer
 	if len(condSQL) > 0 {
 		fmt.Fprintf(&buf, " WHERE %v", condSQL)
@@ -1118,9 +1090,10 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bo
 			}
 
 			var orderStr string
-			if len(statement.OrderStr) > 0 {
+			if needOrderBy && len(statement.OrderStr) > 0 {
 				orderStr = " ORDER BY " + statement.OrderStr
 			}
+
 			var groupStr string
 			if len(statement.GroupByStr) > 0 {
 				groupStr = " GROUP BY " + statement.GroupByStr
@@ -1146,7 +1119,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bo
 	if statement.HavingStr != "" {
 		a = fmt.Sprintf("%v %v", a, statement.HavingStr)
 	}
-	if statement.OrderStr != "" {
+	if needOrderBy && statement.OrderStr != "" {
 		a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
 	}
 	if needLimit {
@@ -1170,7 +1143,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit bo
 }
 
 func (statement *Statement) processIDParam() error {
-	if statement.idParam == nil {
+	if statement.idParam == nil || statement.RefTable == nil {
 		return nil
 	}
 

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

@@ -17,7 +17,7 @@ import (
 
 const (
 	// Version show the xorm's version
-	Version string = "0.6.4.0910"
+	Version string = "0.7.0.0504"
 )
 
 func regDrvsNDialects() bool {
@@ -31,7 +31,7 @@ func regDrvsNDialects() bool {
 		"mysql":    {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 		"mymysql":  {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 		"postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
-		"pgx":      {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
+		"pgx":      {"postgres", func() core.Driver { return &pqDriverPgx{} }, func() core.Dialect { return &postgres{} }},
 		"sqlite3":  {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
 		"oci8":     {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
 		"goracle":  {"oracle", func() core.Driver { return &goracleDriver{} }, func() core.Dialect { return &oracle{} }},
@@ -90,6 +90,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 		TagIdentifier: "xorm",
 		TZLocation:    time.Local,
 		tagHandlers:   defaultTagHandlers,
+		cachers:       make(map[string]core.Cacher),
 	}
 
 	if uri.DbType == core.SQLITE {

+ 9 - 9
vendor/vendor.json

@@ -153,22 +153,22 @@
 			"revisionTime": "2016-08-02T11:38:42Z"
 		},
 		{
-			"checksumSHA1": "9SXbj96wb1PgppBZzxMIN0axbFQ=",
+			"checksumSHA1": "MjpLNawWs5TXcO1vjaZo8PjnYM4=",
 			"path": "github.com/go-xorm/builder",
-			"revision": "c8871c857d2555fbfbd8524f895be5386d3d8836",
-			"revisionTime": "2017-05-19T03:21:30Z"
+			"revision": "bad0a612f0d6277b953910822ab5dfb30dd18237",
+			"revisionTime": "2018-04-27T00:56:09Z"
 		},
 		{
-			"checksumSHA1": "g4e+Nb6gh55ERPYcUCsdYCZ8bdo=",
+			"checksumSHA1": "9nJmaqeYoDD1aqAX3CRNxVeOFI8=",
 			"path": "github.com/go-xorm/core",
-			"revision": "7d5d723a716c3c1adf5f478990ff7a2ff77d3abe",
-			"revisionTime": "2018-03-08T01:08:13Z"
+			"revision": "c10e21e7e1cec20e09398f2dfae385e58c8df555",
+			"revisionTime": "2018-05-04T05:52:46Z"
 		},
 		{
-			"checksumSHA1": "TLZlub4tqDx0a3BM8nXzuKksRwE=",
+			"checksumSHA1": "enhif6uVt3K+XifO1XAFrRF26QI=",
 			"path": "github.com/go-xorm/xorm",
-			"revision": "11743c1a80897b0fdbf79d88ebcaa7dd5f9d3cf3",
-			"revisionTime": "2018-03-08T01:30:38Z"
+			"revision": "a8bd843a55a7fdccb311d4fc51f8261e5035cdbb",
+			"revisionTime": "2018-06-06T08:43:14Z"
 		},
 		{
 			"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=",