浏览代码

tech: updated xorm libs

Torkel Ödegaard 8 年之前
父节点
当前提交
a7babfb7cf
共有 91 个文件被更改,包括 8372 次插入4030 次删除
  1. 1 1
      pkg/tsdb/mysql/mysql.go
  2. 27 0
      vendor/github.com/go-xorm/builder/LICENSE
  3. 175 0
      vendor/github.com/go-xorm/builder/README.md
  4. 190 0
      vendor/github.com/go-xorm/builder/builder.go
  5. 22 0
      vendor/github.com/go-xorm/builder/builder_delete.go
  6. 64 0
      vendor/github.com/go-xorm/builder/builder_insert.go
  7. 53 0
      vendor/github.com/go-xorm/builder/builder_select.go
  8. 41 0
      vendor/github.com/go-xorm/builder/builder_update.go
  9. 12 0
      vendor/github.com/go-xorm/builder/circle.yml
  10. 87 0
      vendor/github.com/go-xorm/builder/cond.go
  11. 59 0
      vendor/github.com/go-xorm/builder/cond_and.go
  12. 40 0
      vendor/github.com/go-xorm/builder/cond_between.go
  13. 154 0
      vendor/github.com/go-xorm/builder/cond_compare.go
  14. 96 0
      vendor/github.com/go-xorm/builder/cond_eq.go
  15. 39 0
      vendor/github.com/go-xorm/builder/cond_expr.go
  16. 239 0
      vendor/github.com/go-xorm/builder/cond_in.go
  17. 41 0
      vendor/github.com/go-xorm/builder/cond_like.go
  18. 78 0
      vendor/github.com/go-xorm/builder/cond_neq.go
  19. 53 0
      vendor/github.com/go-xorm/builder/cond_not.go
  20. 236 0
      vendor/github.com/go-xorm/builder/cond_notin.go
  21. 59 0
      vendor/github.com/go-xorm/builder/cond_null.go
  22. 67 0
      vendor/github.com/go-xorm/builder/cond_or.go
  23. 120 0
      vendor/github.com/go-xorm/builder/doc.go
  24. 16 0
      vendor/github.com/go-xorm/builder/error.go
  25. 0 1
      vendor/github.com/go-xorm/core/.gitignore
  26. 2 0
      vendor/github.com/go-xorm/core/README.md
  27. 0 0
      vendor/github.com/go-xorm/core/benchmark.sh
  28. 14 0
      vendor/github.com/go-xorm/core/circle.yml
  29. 10 12
      vendor/github.com/go-xorm/core/column.go
  30. 15 295
      vendor/github.com/go-xorm/core/db.go
  31. 0 659
      vendor/github.com/go-xorm/core/db_test.go
  32. 22 8
      vendor/github.com/go-xorm/core/dialect.go
  33. 0 2
      vendor/github.com/go-xorm/core/error.go
  34. 17 14
      vendor/github.com/go-xorm/core/ilogger.go
  35. 0 45
      vendor/github.com/go-xorm/core/mapper_test.go
  36. 0 33
      vendor/github.com/go-xorm/core/pk_test.go
  37. 380 0
      vendor/github.com/go-xorm/core/rows.go
  38. 27 6
      vendor/github.com/go-xorm/core/table.go
  39. 10 33
      vendor/github.com/go-xorm/core/type.go
  40. 0 28
      vendor/github.com/go-xorm/xorm/.gitignore
  41. 0 6
      vendor/github.com/go-xorm/xorm/.gitmodules
  42. 0 2
      vendor/github.com/go-xorm/xorm/.gopmfile
  43. 4 0
      vendor/github.com/go-xorm/xorm/CONTRIBUTING.md
  44. 35 28
      vendor/github.com/go-xorm/xorm/README.md
  45. 29 15
      vendor/github.com/go-xorm/xorm/README_CN.md
  46. 1 1
      vendor/github.com/go-xorm/xorm/VERSION
  47. 25 0
      vendor/github.com/go-xorm/xorm/circle.yml
  48. 249 0
      vendor/github.com/go-xorm/xorm/convert.go
  49. 57 24
      vendor/github.com/go-xorm/xorm/dialect_mssql.go
  50. 103 23
      vendor/github.com/go-xorm/xorm/dialect_mysql.go
  51. 81 42
      vendor/github.com/go-xorm/xorm/dialect_oracle.go
  52. 144 36
      vendor/github.com/go-xorm/xorm/dialect_postgres.go
  53. 22 23
      vendor/github.com/go-xorm/xorm/dialect_sqlite3.go
  54. 42 21
      vendor/github.com/go-xorm/xorm/doc.go
  55. 379 348
      vendor/github.com/go-xorm/xorm/engine.go
  56. 14 7
      vendor/github.com/go-xorm/xorm/error.go
  57. 0 0
      vendor/github.com/go-xorm/xorm/gen_reserved.sh
  58. 0 42
      vendor/github.com/go-xorm/xorm/goracle_driver.go
  59. 192 20
      vendor/github.com/go-xorm/xorm/helpers.go
  60. 0 22
      vendor/github.com/go-xorm/xorm/helpers_test.go
  61. 107 30
      vendor/github.com/go-xorm/xorm/logger.go
  62. 31 26
      vendor/github.com/go-xorm/xorm/lru_cacher.go
  63. 5 1
      vendor/github.com/go-xorm/xorm/memory_store.go
  64. 0 69
      vendor/github.com/go-xorm/xorm/mymysql_driver.go
  65. 0 54
      vendor/github.com/go-xorm/xorm/mysql_driver.go
  66. 0 41
      vendor/github.com/go-xorm/xorm/oci8_driver.go
  67. 0 38
      vendor/github.com/go-xorm/xorm/odbc_driver.go
  68. 0 119
      vendor/github.com/go-xorm/xorm/pq_driver.go
  69. 8 6
      vendor/github.com/go-xorm/xorm/processors.go
  70. 44 41
      vendor/github.com/go-xorm/xorm/rows.go
  71. 213 1484
      vendor/github.com/go-xorm/xorm/session.go
  72. 84 0
      vendor/github.com/go-xorm/xorm/session_cols.go
  73. 70 0
      vendor/github.com/go-xorm/xorm/session_cond.go
  74. 670 0
      vendor/github.com/go-xorm/xorm/session_convert.go
  75. 238 0
      vendor/github.com/go-xorm/xorm/session_delete.go
  76. 461 0
      vendor/github.com/go-xorm/xorm/session_find.go
  77. 192 0
      vendor/github.com/go-xorm/xorm/session_get.go
  78. 543 0
      vendor/github.com/go-xorm/xorm/session_insert.go
  79. 42 0
      vendor/github.com/go-xorm/xorm/session_iterate.go
  80. 144 0
      vendor/github.com/go-xorm/xorm/session_raw.go
  81. 489 0
      vendor/github.com/go-xorm/xorm/session_schema.go
  82. 137 0
      vendor/github.com/go-xorm/xorm/session_sum.go
  83. 83 0
      vendor/github.com/go-xorm/xorm/session_tx.go
  84. 356 0
      vendor/github.com/go-xorm/xorm/session_update.go
  85. 0 20
      vendor/github.com/go-xorm/xorm/sqlite3_driver.go
  86. 241 276
      vendor/github.com/go-xorm/xorm/statement.go
  87. 45 19
      vendor/github.com/go-xorm/xorm/syslogger.go
  88. 281 0
      vendor/github.com/go-xorm/xorm/tag.go
  89. 12 0
      vendor/github.com/go-xorm/xorm/types.go
  90. 11 9
      vendor/github.com/go-xorm/xorm/xorm.go
  91. 22 0
      vendor/vendor.json

+ 1 - 1
pkg/tsdb/mysql/mysql.go

@@ -65,7 +65,7 @@ func (e *MysqlExecutor) initEngine() error {
 	e.log.Debug("getEngine", "connection", cnnstr)
 
 	engine, err := xorm.NewEngine("mysql", cnnstr)
-	engine.SetMaxConns(10)
+	engine.SetMaxOpenConns(10)
 	engine.SetMaxIdleConns(10)
 	if err != nil {
 		return err

+ 27 - 0
vendor/github.com/go-xorm/builder/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2016 The Xorm Authors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 175 - 0
vendor/github.com/go-xorm/builder/README.md

@@ -0,0 +1,175 @@
+# SQL builder
+
+[![CircleCI](https://circleci.com/gh/go-xorm/builder/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/builder/tree/master)
+
+Package builder is a lightweight and fast SQL builder for Go and XORM.
+
+Make sure you have installed Go 1.1+ and then:
+
+    go get github.com/go-xorm/builder
+
+# Insert
+
+```Go
+sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
+```
+
+# Select
+
+```Go
+sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
+
+sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
+		RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
+```
+
+# Update
+
+```Go
+sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
+```
+
+# Delete
+
+```Go
+sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
+```
+
+# Conditions
+
+* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Eq{"a":1})
+// a=? [1]
+sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
+// b=? AND c=? ["c", 0]
+sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
+// b=? AND c=? ["c", 0]
+sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
+// b=? OR b=? ["c", "d"]
+sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
+// b IN (?,?) ["c", "d"]
+sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
+// b=? AND c IN (?,?) [1, 2, 3]
+```
+
+* `Neq` is the same to `Eq`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Neq{"a":1})
+// a<>? [1]
+sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
+// b<>? AND c<>? ["c", 0]
+sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
+// b<>? AND c<>? ["c", 0]
+sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
+// b<>? OR b<>? ["c", "d"]
+sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
+// b NOT IN (?,?) ["c", "d"]
+sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
+// b<>? AND c NOT IN (?,?) [1, 2, 3]
+```
+
+* `Gt`, `Gte`, `Lt`, `Lte`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
+// a>? AND b>=? [1, 2]
+sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
+// a<? OR b<=? [1, 2]
+```
+
+* `Like`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Like{"a", "c"})
+// a LIKE ? [%c%]
+```
+
+* `Expr` you can customerize your sql with `Expr`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Expr("a = ? ", 1))
+// a = ? [1]
+sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
+// a=(select id from table where c = ?) [1]
+```
+
+* `In` and `NotIn`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(In("a", 1, 2, 3))
+// a IN (?,?,?) [1,2,3]
+sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
+// a IN (?,?,?) [1,2,3]
+sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
+// a IN (select id from b where c = ?) [1]
+```
+
+* `IsNull` and `NotNull`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(IsNull{"a"})
+// a IS NULL []
+sql, args, _ := ToSQL(NotNull{"b"})
+	// b IS NOT NULL []
+```
+
+* `And(conds ...Cond)`, And can connect one or more condtions via And
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
+// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
+```
+
+* `Or(conds ...Cond)`, Or can connect one or more conditions via Or
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
+// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
+sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
+// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
+```
+
+* `Between`
+
+```Go
+import . "github.com/go-xorm/builder"
+
+sql, args, _ := ToSQL(Between{"a", 1, 2})
+// a BETWEEN 1 AND 2
+```
+
+* Define yourself conditions
+
+Since `Cond` is an interface.
+
+```Go
+type Cond interface {
+	WriteTo(Writer) error
+	And(...Cond) Cond
+	Or(...Cond) Cond
+	IsValid() bool
+}
+```
+
+You can define yourself conditions and compose with other `Cond`.

+ 190 - 0
vendor/github.com/go-xorm/builder/builder.go

@@ -0,0 +1,190 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+type optype byte
+
+const (
+	condType   optype = iota // only conditions
+	selectType               // select
+	insertType               // insert
+	updateType               // update
+	deleteType               // delete
+)
+
+type join struct {
+	joinType  string
+	joinTable string
+	joinCond  Cond
+}
+
+// Builder describes a SQL statement
+type Builder struct {
+	optype
+	tableName string
+	cond      Cond
+	selects   []string
+	joins     []join
+	inserts   Eq
+	updates   []Eq
+}
+
+// Select creates a select Builder
+func Select(cols ...string) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Select(cols...)
+}
+
+// Insert creates an insert Builder
+func Insert(eq Eq) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Insert(eq)
+}
+
+// Update creates an update Builder
+func Update(updates ...Eq) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Update(updates...)
+}
+
+// Delete creates a delete Builder
+func Delete(conds ...Cond) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Delete(conds...)
+}
+
+// Where sets where SQL
+func (b *Builder) Where(cond Cond) *Builder {
+	b.cond = b.cond.And(cond)
+	return b
+}
+
+// From sets the table name
+func (b *Builder) From(tableName string) *Builder {
+	b.tableName = tableName
+	return b
+}
+
+// Into sets insert table name
+func (b *Builder) Into(tableName string) *Builder {
+	b.tableName = tableName
+	return b
+}
+
+// Join sets join table and contions
+func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
+	switch joinCond.(type) {
+	case Cond:
+		b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
+	case string:
+		b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
+	}
+
+	return b
+}
+
+// InnerJoin sets inner join
+func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
+	return b.Join("INNER", joinTable, joinCond)
+}
+
+// LeftJoin sets left join SQL
+func (b *Builder) LeftJoin(joinTable string, joinCond interface{}) *Builder {
+	return b.Join("LEFT", joinTable, joinCond)
+}
+
+// RightJoin sets right join SQL
+func (b *Builder) RightJoin(joinTable string, joinCond interface{}) *Builder {
+	return b.Join("RIGHT", joinTable, joinCond)
+}
+
+// CrossJoin sets cross join SQL
+func (b *Builder) CrossJoin(joinTable string, joinCond interface{}) *Builder {
+	return b.Join("CROSS", joinTable, joinCond)
+}
+
+// FullJoin sets full join SQL
+func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
+	return b.Join("FULL", joinTable, joinCond)
+}
+
+// Select sets select SQL
+func (b *Builder) Select(cols ...string) *Builder {
+	b.selects = cols
+	b.optype = selectType
+	return b
+}
+
+// And sets AND condition
+func (b *Builder) And(cond Cond) *Builder {
+	b.cond = And(b.cond, cond)
+	return b
+}
+
+// Or sets OR condition
+func (b *Builder) Or(cond Cond) *Builder {
+	b.cond = Or(b.cond, cond)
+	return b
+}
+
+// Insert sets insert SQL
+func (b *Builder) Insert(eq Eq) *Builder {
+	b.inserts = eq
+	b.optype = insertType
+	return b
+}
+
+// Update sets update SQL
+func (b *Builder) Update(updates ...Eq) *Builder {
+	b.updates = updates
+	b.optype = updateType
+	return b
+}
+
+// Delete sets delete SQL
+func (b *Builder) Delete(conds ...Cond) *Builder {
+	b.cond = b.cond.And(conds...)
+	b.optype = deleteType
+	return b
+}
+
+// WriteTo implements Writer interface
+func (b *Builder) WriteTo(w Writer) error {
+	switch b.optype {
+	case condType:
+		return b.cond.WriteTo(w)
+	case selectType:
+		return b.selectWriteTo(w)
+	case insertType:
+		return b.insertWriteTo(w)
+	case updateType:
+		return b.updateWriteTo(w)
+	case deleteType:
+		return b.deleteWriteTo(w)
+	}
+
+	return ErrNotSupportType
+}
+
+// ToSQL convert a builder to SQL and args
+func (b *Builder) ToSQL() (string, []interface{}, error) {
+	w := NewWriter()
+	if err := b.WriteTo(w); err != nil {
+		return "", nil, err
+	}
+
+	return w.writer.String(), w.args, nil
+}
+
+// ToSQL convert a builder or condtions to SQL and args
+func ToSQL(cond interface{}) (string, []interface{}, error) {
+	switch cond.(type) {
+	case Cond:
+		return condToSQL(cond.(Cond))
+	case *Builder:
+		return cond.(*Builder).ToSQL()
+	}
+	return "", nil, ErrNotSupportType
+}

+ 22 - 0
vendor/github.com/go-xorm/builder/builder_delete.go

@@ -0,0 +1,22 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"errors"
+	"fmt"
+)
+
+func (b *Builder) deleteWriteTo(w Writer) error {
+	if len(b.tableName) <= 0 {
+		return errors.New("no table indicated")
+	}
+
+	if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.tableName); err != nil {
+		return err
+	}
+
+	return b.cond.WriteTo(w)
+}

+ 64 - 0
vendor/github.com/go-xorm/builder/builder_insert.go

@@ -0,0 +1,64 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+)
+
+func (b *Builder) insertWriteTo(w Writer) error {
+	if len(b.tableName) <= 0 {
+		return errors.New("no table indicated")
+	}
+	if len(b.inserts) <= 0 {
+		return errors.New("no column to be update")
+	}
+
+	if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.tableName); err != nil {
+		return err
+	}
+
+	var args = make([]interface{}, 0)
+	var bs []byte
+	var valBuffer = bytes.NewBuffer(bs)
+	var i = 0
+	for col, value := range b.inserts {
+		fmt.Fprint(w, col)
+		if e, ok := value.(expr); ok {
+			fmt.Fprint(valBuffer, e.sql)
+			args = append(args, e.args...)
+		} else {
+			fmt.Fprint(valBuffer, "?")
+			args = append(args, value)
+		}
+
+		if i != len(b.inserts)-1 {
+			if _, err := fmt.Fprint(w, ","); err != nil {
+				return err
+			}
+			if _, err := fmt.Fprint(valBuffer, ","); err != nil {
+				return err
+			}
+		}
+		i = i + 1
+	}
+
+	if _, err := fmt.Fprint(w, ") Values ("); err != nil {
+		return err
+	}
+
+	if _, err := w.Write(valBuffer.Bytes()); err != nil {
+		return err
+	}
+	if _, err := fmt.Fprint(w, ")"); err != nil {
+		return err
+	}
+
+	w.Append(args...)
+
+	return nil
+}

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

@@ -0,0 +1,53 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"errors"
+	"fmt"
+)
+
+func (b *Builder) selectWriteTo(w Writer) error {
+	if len(b.tableName) <= 0 {
+		return errors.New("no table indicated")
+	}
+
+	if _, err := fmt.Fprint(w, "SELECT "); err != nil {
+		return err
+	}
+	if len(b.selects) > 0 {
+		for i, s := range b.selects {
+			if _, err := fmt.Fprint(w, s); err != nil {
+				return err
+			}
+			if i != len(b.selects)-1 {
+				if _, err := fmt.Fprint(w, ","); err != nil {
+					return err
+				}
+			}
+		}
+	} else {
+		if _, err := fmt.Fprint(w, "*"); err != nil {
+			return err
+		}
+	}
+
+	if _, err := fmt.Fprintf(w, " FROM %s", b.tableName); err != nil {
+		return err
+	}
+
+	for _, v := range b.joins {
+		fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable)
+		if err := v.joinCond.WriteTo(w); err != nil {
+			return err
+		}
+	}
+
+	if _, err := fmt.Fprint(w, " WHERE "); err != nil {
+		return err
+	}
+
+	return b.cond.WriteTo(w)
+}

+ 41 - 0
vendor/github.com/go-xorm/builder/builder_update.go

@@ -0,0 +1,41 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"errors"
+	"fmt"
+)
+
+func (b *Builder) updateWriteTo(w Writer) error {
+	if len(b.tableName) <= 0 {
+		return errors.New("no table indicated")
+	}
+	if len(b.updates) <= 0 {
+		return errors.New("no column to be update")
+	}
+
+	if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.tableName); err != nil {
+		return err
+	}
+
+	for i, s := range b.updates {
+		if err := s.opWriteTo(",", w); err != nil {
+			return err
+		}
+
+		if i != len(b.updates)-1 {
+			if _, err := fmt.Fprint(w, ","); err != nil {
+				return err
+			}
+		}
+	}
+
+	if _, err := fmt.Fprint(w, " WHERE "); err != nil {
+		return err
+	}
+
+	return b.cond.WriteTo(w)
+}

+ 12 - 0
vendor/github.com/go-xorm/builder/circle.yml

@@ -0,0 +1,12 @@
+dependencies:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - go get -t -d -v ./...
+    - go build -v
+    - go get -u github.com/golang/lint/golint
+
+test:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - golint ./...
+    - go test -v -race

+ 87 - 0
vendor/github.com/go-xorm/builder/cond.go

@@ -0,0 +1,87 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"bytes"
+	"io"
+)
+
+// Writer defines the interface
+type Writer interface {
+	io.Writer
+	Append(...interface{})
+}
+
+var _ Writer = NewWriter()
+
+// BytesWriter implments Writer and save SQL in bytes.Buffer
+type BytesWriter struct {
+	writer *bytes.Buffer
+	buffer []byte
+	args   []interface{}
+}
+
+// NewWriter creates a new string writer
+func NewWriter() *BytesWriter {
+	w := &BytesWriter{}
+	w.writer = bytes.NewBuffer(w.buffer)
+	return w
+}
+
+// Write writes data to Writer
+func (s *BytesWriter) Write(buf []byte) (int, error) {
+	return s.writer.Write(buf)
+}
+
+// Append appends args to Writer
+func (s *BytesWriter) Append(args ...interface{}) {
+	s.args = append(s.args, args...)
+}
+
+// Cond defines an interface
+type Cond interface {
+	WriteTo(Writer) error
+	And(...Cond) Cond
+	Or(...Cond) Cond
+	IsValid() bool
+}
+
+type condEmpty struct{}
+
+var _ Cond = condEmpty{}
+
+// NewCond creates an empty condition
+func NewCond() Cond {
+	return condEmpty{}
+}
+
+func (condEmpty) WriteTo(w Writer) error {
+	return nil
+}
+
+func (condEmpty) And(conds ...Cond) Cond {
+	return And(conds...)
+}
+
+func (condEmpty) Or(conds ...Cond) Cond {
+	return Or(conds...)
+}
+
+func (condEmpty) IsValid() bool {
+	return false
+}
+
+func condToSQL(cond Cond) (string, []interface{}, error) {
+	if cond == nil || !cond.IsValid() {
+		return "", nil, nil
+	}
+
+	w := NewWriter()
+	if err := cond.WriteTo(w); err != nil {
+		return "", nil, err
+	}
+	return w.writer.String(), w.args, nil
+}

+ 59 - 0
vendor/github.com/go-xorm/builder/cond_and.go

@@ -0,0 +1,59 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+type condAnd []Cond
+
+var _ Cond = condAnd{}
+
+// And generates AND conditions
+func And(conds ...Cond) Cond {
+	var result = make(condAnd, 0, len(conds))
+	for _, cond := range conds {
+		if cond == nil || !cond.IsValid() {
+			continue
+		}
+		result = append(result, cond)
+	}
+	return result
+}
+
+func (and condAnd) WriteTo(w Writer) error {
+	for i, cond := range and {
+		_, isOr := cond.(condOr)
+		if isOr {
+			fmt.Fprint(w, "(")
+		}
+
+		err := cond.WriteTo(w)
+		if err != nil {
+			return err
+		}
+
+		if isOr {
+			fmt.Fprint(w, ")")
+		}
+
+		if i != len(and)-1 {
+			fmt.Fprint(w, " AND ")
+		}
+	}
+
+	return nil
+}
+
+func (and condAnd) And(conds ...Cond) Cond {
+	return And(and, And(conds...))
+}
+
+func (and condAnd) Or(conds ...Cond) Cond {
+	return Or(and, Or(conds...))
+}
+
+func (and condAnd) IsValid() bool {
+	return len(and) > 0
+}

+ 40 - 0
vendor/github.com/go-xorm/builder/cond_between.go

@@ -0,0 +1,40 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// Between implmentes between condition
+type Between struct {
+	Col     string
+	LessVal interface{}
+	MoreVal interface{}
+}
+
+var _ Cond = Between{}
+
+// WriteTo write data to Writer
+func (between Between) WriteTo(w Writer) error {
+	if _, err := fmt.Fprintf(w, "%s BETWEEN ? AND ?", between.Col); err != nil {
+		return err
+	}
+	w.Append(between.LessVal, between.MoreVal)
+	return nil
+}
+
+// And implments And with other conditions
+func (between Between) And(conds ...Cond) Cond {
+	return And(between, And(conds...))
+}
+
+// Or implments Or with other conditions
+func (between Between) Or(conds ...Cond) Cond {
+	return Or(between, Or(conds...))
+}
+
+// IsValid tests if the condition is valid
+func (between Between) IsValid() bool {
+	return len(between.Col) > 0
+}

+ 154 - 0
vendor/github.com/go-xorm/builder/cond_compare.go

@@ -0,0 +1,154 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// WriteMap writes conditions' SQL to Writer, op could be =, <>, >, <, <=, >= and etc.
+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 {
+		switch v.(type) {
+		case expr:
+			if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
+				return err
+			}
+
+			if err := v.(expr).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		case *Builder:
+			if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
+				return err
+			}
+
+			if err := v.(*Builder).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		default:
+			if _, err := fmt.Fprintf(w, "%s%s?", k, op); err != nil {
+				return err
+			}
+			args = append(args, v)
+		}
+		if i != len(data)-1 {
+			if _, err := fmt.Fprint(w, " AND "); err != nil {
+				return err
+			}
+		}
+		i = i + 1
+	}
+	w.Append(args...)
+	return nil
+}
+
+// Lt defines < condition
+type Lt map[string]interface{}
+
+var _ Cond = Lt{}
+
+// WriteTo write SQL to Writer
+func (lt Lt) WriteTo(w Writer) error {
+	return WriteMap(w, lt, "<")
+}
+
+// And implements And with other conditions
+func (lt Lt) And(conds ...Cond) Cond {
+	return condAnd{lt, And(conds...)}
+}
+
+// Or implements Or with other conditions
+func (lt Lt) Or(conds ...Cond) Cond {
+	return condOr{lt, Or(conds...)}
+}
+
+// IsValid tests if this Eq is valid
+func (lt Lt) IsValid() bool {
+	return len(lt) > 0
+}
+
+// Lte defines <= condition
+type Lte map[string]interface{}
+
+var _ Cond = Lte{}
+
+// WriteTo write SQL to Writer
+func (lte Lte) WriteTo(w Writer) error {
+	return WriteMap(w, lte, "<=")
+}
+
+// And implements And with other conditions
+func (lte Lte) And(conds ...Cond) Cond {
+	return And(lte, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (lte Lte) Or(conds ...Cond) Cond {
+	return Or(lte, Or(conds...))
+}
+
+// IsValid tests if this Eq is valid
+func (lte Lte) IsValid() bool {
+	return len(lte) > 0
+}
+
+// Gt defines > condition
+type Gt map[string]interface{}
+
+var _ Cond = Gt{}
+
+// WriteTo write SQL to Writer
+func (gt Gt) WriteTo(w Writer) error {
+	return WriteMap(w, gt, ">")
+}
+
+// And implements And with other conditions
+func (gt Gt) And(conds ...Cond) Cond {
+	return And(gt, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (gt Gt) Or(conds ...Cond) Cond {
+	return Or(gt, Or(conds...))
+}
+
+// IsValid tests if this Eq is valid
+func (gt Gt) IsValid() bool {
+	return len(gt) > 0
+}
+
+// Gte defines >= condition
+type Gte map[string]interface{}
+
+var _ Cond = Gte{}
+
+// WriteTo write SQL to Writer
+func (gte Gte) WriteTo(w Writer) error {
+	return WriteMap(w, gte, ">=")
+}
+
+// And implements And with other conditions
+func (gte Gte) And(conds ...Cond) Cond {
+	return And(gte, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (gte Gte) Or(conds ...Cond) Cond {
+	return Or(gte, Or(conds...))
+}
+
+// IsValid tests if this Eq is valid
+func (gte Gte) IsValid() bool {
+	return len(gte) > 0
+}

+ 96 - 0
vendor/github.com/go-xorm/builder/cond_eq.go

@@ -0,0 +1,96 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// Incr implements a type used by Eq
+type Incr int
+
+// Decr implements a type used by Eq
+type Decr int
+
+// Eq defines equals conditions
+type Eq map[string]interface{}
+
+var _ Cond = Eq{}
+
+func (eq Eq) opWriteTo(op string, w Writer) error {
+	var i = 0
+	for k, v := range eq {
+		switch v.(type) {
+		case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
+			if err := In(k, v).WriteTo(w); err != nil {
+				return err
+			}
+		case expr:
+			if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
+				return err
+			}
+
+			if err := v.(expr).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		case *Builder:
+			if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
+				return err
+			}
+
+			if err := v.(*Builder).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		case Incr:
+			if _, err := fmt.Fprintf(w, "%s=%s+?", k, k); err != nil {
+				return err
+			}
+			w.Append(int(v.(Incr)))
+		case Decr:
+			if _, err := fmt.Fprintf(w, "%s=%s-?", k, k); err != nil {
+				return err
+			}
+			w.Append(int(v.(Decr)))
+		default:
+			if _, err := fmt.Fprintf(w, "%s=?", k); err != nil {
+				return err
+			}
+			w.Append(v)
+		}
+		if i != len(eq)-1 {
+			if _, err := fmt.Fprint(w, op); err != nil {
+				return err
+			}
+		}
+		i = i + 1
+	}
+	return nil
+}
+
+// WriteTo writes SQL to Writer
+func (eq Eq) WriteTo(w Writer) error {
+	return eq.opWriteTo(" AND ", w)
+}
+
+// And implements And with other conditions
+func (eq Eq) And(conds ...Cond) Cond {
+	return And(eq, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (eq Eq) Or(conds ...Cond) Cond {
+	return Or(eq, Or(conds...))
+}
+
+// IsValid tests if this Eq is valid
+func (eq Eq) IsValid() bool {
+	return len(eq) > 0
+}

+ 39 - 0
vendor/github.com/go-xorm/builder/cond_expr.go

@@ -0,0 +1,39 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+type expr struct {
+	sql  string
+	args []interface{}
+}
+
+var _ Cond = expr{}
+
+// Expr generate customerize SQL
+func Expr(sql string, args ...interface{}) Cond {
+	return expr{sql, args}
+}
+
+func (expr expr) WriteTo(w Writer) error {
+	if _, err := fmt.Fprint(w, expr.sql); err != nil {
+		return err
+	}
+	w.Append(expr.args...)
+	return nil
+}
+
+func (expr expr) And(conds ...Cond) Cond {
+	return And(expr, And(conds...))
+}
+
+func (expr expr) Or(conds ...Cond) Cond {
+	return Or(expr, Or(conds...))
+}
+
+func (expr expr) IsValid() bool {
+	return len(expr.sql) > 0
+}

+ 239 - 0
vendor/github.com/go-xorm/builder/cond_in.go

@@ -0,0 +1,239 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+type condIn struct {
+	col  string
+	vals []interface{}
+}
+
+var _ Cond = condIn{}
+
+// In generates IN condition
+func In(col string, values ...interface{}) Cond {
+	return condIn{col, values}
+}
+
+func (condIn condIn) handleBlank(w Writer) error {
+	if _, err := fmt.Fprintf(w, "%s IN ()", condIn.col); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (condIn condIn) WriteTo(w Writer) error {
+	if len(condIn.vals) <= 0 {
+		return condIn.handleBlank(w)
+	}
+
+	switch condIn.vals[0].(type) {
+	case []int8:
+		vals := condIn.vals[0].([]int8)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int16:
+		vals := condIn.vals[0].([]int16)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int:
+		vals := condIn.vals[0].([]int)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int32:
+		vals := condIn.vals[0].([]int32)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int64:
+		vals := condIn.vals[0].([]int64)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint8:
+		vals := condIn.vals[0].([]uint8)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint16:
+		vals := condIn.vals[0].([]uint16)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint:
+		vals := condIn.vals[0].([]uint)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint32:
+		vals := condIn.vals[0].([]uint32)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint64:
+		vals := condIn.vals[0].([]uint64)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []string:
+		vals := condIn.vals[0].([]string)
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []interface{}:
+		vals := condIn.vals[0].([]interface{})
+		if len(vals) <= 0 {
+			return condIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		w.Append(vals...)
+	case expr:
+		val := condIn.vals[0].(expr)
+		if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
+			return err
+		}
+		if err := val.WriteTo(w); err != nil {
+			return err
+		}
+		if _, err := fmt.Fprintf(w, ")"); err != nil {
+			return err
+		}
+	case *Builder:
+		bd := condIn.vals[0].(*Builder)
+		if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
+			return err
+		}
+		if err := bd.WriteTo(w); err != nil {
+			return err
+		}
+		if _, err := fmt.Fprintf(w, ")"); err != nil {
+			return err
+		}
+	default:
+		v := reflect.ValueOf(condIn.vals[0])
+		if v.Kind() == reflect.Slice {
+			l := v.Len()
+			if l == 0 {
+				return condIn.handleBlank(w)
+			}
+
+			questionMark := strings.Repeat("?,", l)
+			if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+				return err
+			}
+
+			for i := 0; i < l; i++ {
+				w.Append(v.Index(i).Interface())
+			}
+		} else {
+			questionMark := strings.Repeat("?,", len(condIn.vals))
+			if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
+				return err
+			}
+			w.Append(condIn.vals...)
+		}
+	}
+	return nil
+}
+
+func (condIn condIn) And(conds ...Cond) Cond {
+	return And(condIn, And(conds...))
+}
+
+func (condIn condIn) Or(conds ...Cond) Cond {
+	return Or(condIn, Or(conds...))
+}
+
+func (condIn condIn) IsValid() bool {
+	return len(condIn.col) > 0 && len(condIn.vals) > 0
+}

+ 41 - 0
vendor/github.com/go-xorm/builder/cond_like.go

@@ -0,0 +1,41 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// Like defines like condition
+type Like [2]string
+
+var _ Cond = Like{"", ""}
+
+// WriteTo write SQL to Writer
+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
+	if like[1][0] == '%' || like[1][len(like[1])-1] == '%' {
+		w.Append(like[1])
+	} else {
+		w.Append("%" + like[1] + "%")
+	}
+	return nil
+}
+
+// And implements And with other conditions
+func (like Like) And(conds ...Cond) Cond {
+	return And(like, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (like Like) Or(conds ...Cond) Cond {
+	return Or(like, Or(conds...))
+}
+
+// IsValid tests if this condition is valid
+func (like Like) IsValid() bool {
+	return len(like[0]) > 0 && len(like[1]) > 0
+}

+ 78 - 0
vendor/github.com/go-xorm/builder/cond_neq.go

@@ -0,0 +1,78 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// Neq defines not equal conditions
+type Neq map[string]interface{}
+
+var _ Cond = Neq{}
+
+// WriteTo writes SQL to Writer
+func (neq Neq) WriteTo(w Writer) error {
+	var args = make([]interface{}, 0, len(neq))
+	var i = 0
+	for k, v := range neq {
+		switch v.(type) {
+		case []int, []int64, []string, []int32, []int16, []int8:
+			if err := NotIn(k, v).WriteTo(w); err != nil {
+				return err
+			}
+		case expr:
+			if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
+				return err
+			}
+
+			if err := v.(expr).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		case *Builder:
+			if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
+				return err
+			}
+
+			if err := v.(*Builder).WriteTo(w); err != nil {
+				return err
+			}
+
+			if _, err := fmt.Fprintf(w, ")"); err != nil {
+				return err
+			}
+		default:
+			if _, err := fmt.Fprintf(w, "%s<>?", k); err != nil {
+				return err
+			}
+			args = append(args, v)
+		}
+		if i != len(neq)-1 {
+			if _, err := fmt.Fprint(w, " AND "); err != nil {
+				return err
+			}
+		}
+		i = i + 1
+	}
+	w.Append(args...)
+	return nil
+}
+
+// And implements And with other conditions
+func (neq Neq) And(conds ...Cond) Cond {
+	return And(neq, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (neq Neq) Or(conds ...Cond) Cond {
+	return Or(neq, Or(conds...))
+}
+
+// IsValid tests if this condition is valid
+func (neq Neq) IsValid() bool {
+	return len(neq) > 0
+}

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

@@ -0,0 +1,53 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// Not defines NOT condition
+type Not [1]Cond
+
+var _ Cond = Not{}
+
+// WriteTo writes SQL to Writer
+func (not Not) WriteTo(w Writer) error {
+	if _, err := fmt.Fprint(w, "NOT "); err != nil {
+		return err
+	}
+	switch not[0].(type) {
+	case condAnd, condOr:
+		if _, err := fmt.Fprint(w, "("); err != nil {
+			return err
+		}
+	}
+
+	if err := not[0].WriteTo(w); err != nil {
+		return err
+	}
+
+	switch not[0].(type) {
+	case condAnd, condOr:
+		if _, err := fmt.Fprint(w, ")"); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// And implements And with other conditions
+func (not Not) And(conds ...Cond) Cond {
+	return And(not, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (not Not) Or(conds ...Cond) Cond {
+	return Or(not, Or(conds...))
+}
+
+// IsValid tests if this condition is valid
+func (not Not) IsValid() bool {
+	return not[0] != nil && not[0].IsValid()
+}

+ 236 - 0
vendor/github.com/go-xorm/builder/cond_notin.go

@@ -0,0 +1,236 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+type condNotIn condIn
+
+var _ Cond = condNotIn{}
+
+// NotIn generate NOT IN condition
+func NotIn(col string, values ...interface{}) Cond {
+	return condNotIn{col, values}
+}
+
+func (condNotIn condNotIn) handleBlank(w Writer) error {
+	if _, err := fmt.Fprintf(w, "%s NOT IN ()", condNotIn.col); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (condNotIn condNotIn) WriteTo(w Writer) error {
+	if len(condNotIn.vals) <= 0 {
+		return condNotIn.handleBlank(w)
+	}
+
+	switch condNotIn.vals[0].(type) {
+	case []int8:
+		vals := condNotIn.vals[0].([]int8)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int16:
+		vals := condNotIn.vals[0].([]int16)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int:
+		vals := condNotIn.vals[0].([]int)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int32:
+		vals := condNotIn.vals[0].([]int32)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []int64:
+		vals := condNotIn.vals[0].([]int64)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint8:
+		vals := condNotIn.vals[0].([]uint8)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint16:
+		vals := condNotIn.vals[0].([]uint16)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint:
+		vals := condNotIn.vals[0].([]uint)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint32:
+		vals := condNotIn.vals[0].([]uint32)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []uint64:
+		vals := condNotIn.vals[0].([]uint64)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []string:
+		vals := condNotIn.vals[0].([]string)
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		for _, val := range vals {
+			w.Append(val)
+		}
+	case []interface{}:
+		vals := condNotIn.vals[0].([]interface{})
+		if len(vals) <= 0 {
+			return condNotIn.handleBlank(w)
+		}
+		questionMark := strings.Repeat("?,", len(vals))
+		if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+			return err
+		}
+		w.Append(vals...)
+	case expr:
+		val := condNotIn.vals[0].(expr)
+		if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
+			return err
+		}
+		if err := val.WriteTo(w); err != nil {
+			return err
+		}
+		if _, err := fmt.Fprintf(w, ")"); err != nil {
+			return err
+		}
+	case *Builder:
+		val := condNotIn.vals[0].(*Builder)
+		if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
+			return err
+		}
+		if err := val.WriteTo(w); err != nil {
+			return err
+		}
+		if _, err := fmt.Fprintf(w, ")"); err != nil {
+			return err
+		}
+	default:
+		v := reflect.ValueOf(condNotIn.vals[0])
+		if v.Kind() == reflect.Slice {
+			l := v.Len()
+			if l == 0 {
+				return condNotIn.handleBlank(w)
+			}
+
+			questionMark := strings.Repeat("?,", l)
+			if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+				return err
+			}
+
+			for i := 0; i < l; i++ {
+				w.Append(v.Index(i).Interface())
+			}
+		} else {
+			questionMark := strings.Repeat("?,", len(condNotIn.vals))
+			if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
+				return err
+			}
+			w.Append(condNotIn.vals...)
+		}
+	}
+	return nil
+}
+
+func (condNotIn condNotIn) And(conds ...Cond) Cond {
+	return And(condNotIn, And(conds...))
+}
+
+func (condNotIn condNotIn) Or(conds ...Cond) Cond {
+	return Or(condNotIn, Or(conds...))
+}
+
+func (condNotIn condNotIn) IsValid() bool {
+	return len(condNotIn.col) > 0 && len(condNotIn.vals) > 0
+}

+ 59 - 0
vendor/github.com/go-xorm/builder/cond_null.go

@@ -0,0 +1,59 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+// IsNull defines IS NULL condition
+type IsNull [1]string
+
+var _ Cond = IsNull{""}
+
+// WriteTo write SQL to Writer
+func (isNull IsNull) WriteTo(w Writer) error {
+	_, err := fmt.Fprintf(w, "%s IS NULL", isNull[0])
+	return err
+}
+
+// And implements And with other conditions
+func (isNull IsNull) And(conds ...Cond) Cond {
+	return And(isNull, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (isNull IsNull) Or(conds ...Cond) Cond {
+	return Or(isNull, Or(conds...))
+}
+
+// IsValid tests if this condition is valid
+func (isNull IsNull) IsValid() bool {
+	return len(isNull[0]) > 0
+}
+
+// NotNull defines NOT NULL condition
+type NotNull [1]string
+
+var _ Cond = NotNull{""}
+
+// WriteTo write SQL to Writer
+func (notNull NotNull) WriteTo(w Writer) error {
+	_, err := fmt.Fprintf(w, "%s IS NOT NULL", notNull[0])
+	return err
+}
+
+// And implements And with other conditions
+func (notNull NotNull) And(conds ...Cond) Cond {
+	return And(notNull, And(conds...))
+}
+
+// Or implements Or with other conditions
+func (notNull NotNull) Or(conds ...Cond) Cond {
+	return Or(notNull, Or(conds...))
+}
+
+// IsValid tests if this condition is valid
+func (notNull NotNull) IsValid() bool {
+	return len(notNull[0]) > 0
+}

+ 67 - 0
vendor/github.com/go-xorm/builder/cond_or.go

@@ -0,0 +1,67 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "fmt"
+
+type condOr []Cond
+
+var _ Cond = condOr{}
+
+// Or sets OR conditions
+func Or(conds ...Cond) Cond {
+	var result = make(condOr, 0, len(conds))
+	for _, cond := range conds {
+		if cond == nil || !cond.IsValid() {
+			continue
+		}
+		result = append(result, cond)
+	}
+	return result
+}
+
+// WriteTo implments Cond
+func (o condOr) WriteTo(w Writer) error {
+	for i, cond := range o {
+		var needQuote bool
+		switch cond.(type) {
+		case condAnd:
+			needQuote = true
+		case Eq:
+			needQuote = (len(cond.(Eq)) > 1)
+		}
+
+		if needQuote {
+			fmt.Fprint(w, "(")
+		}
+
+		err := cond.WriteTo(w)
+		if err != nil {
+			return err
+		}
+
+		if needQuote {
+			fmt.Fprint(w, ")")
+		}
+
+		if i != len(o)-1 {
+			fmt.Fprint(w, " OR ")
+		}
+	}
+
+	return nil
+}
+
+func (o condOr) And(conds ...Cond) Cond {
+	return And(o, And(conds...))
+}
+
+func (o condOr) Or(conds ...Cond) Cond {
+	return Or(o, Or(conds...))
+}
+
+func (o condOr) IsValid() bool {
+	return len(o) > 0
+}

+ 120 - 0
vendor/github.com/go-xorm/builder/doc.go

@@ -0,0 +1,120 @@
+// Copyright 2016 The XORM Authors. All rights reserved.
+// Use of this source code is governed by a BSD
+// license that can be found in the LICENSE file.
+
+/*
+
+Package builder is a simple and powerful sql builder for Go.
+
+Make sure you have installed Go 1.1+ and then:
+
+    go get github.com/go-xorm/builder
+
+WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
+
+1. Eq is a redefine of a map, you can give one or more conditions to Eq
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Eq{"a":1})
+    // a=? [1]
+    sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
+    // b=? AND c=? ["c", 0]
+    sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
+    // b=? AND c=? ["c", 0]
+    sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
+    // b=? OR b=? ["c", "d"]
+    sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
+    // b IN (?,?) ["c", "d"]
+    sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
+    // b=? AND c IN (?,?) [1, 2, 3]
+
+2. Neq is the same to Eq
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Neq{"a":1})
+    // a<>? [1]
+    sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
+    // b<>? AND c<>? ["c", 0]
+    sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
+    // b<>? AND c<>? ["c", 0]
+    sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
+    // b<>? OR b<>? ["c", "d"]
+    sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
+    // b NOT IN (?,?) ["c", "d"]
+    sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
+    // b<>? AND c NOT IN (?,?) [1, 2, 3]
+
+3. Gt, Gte, Lt, Lte
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
+    // a>? AND b>=? [1, 2]
+    sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
+    // a<? OR b<=? [1, 2]
+
+4. Like
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Like{"a", "c"})
+    // a LIKE ? [%c%]
+
+5. Expr you can customerize your sql with Expr
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Expr("a = ? ", 1))
+    // a = ? [1]
+    sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
+    // a=(select id from table where c = ?) [1]
+
+6. In and NotIn
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(In("a", 1, 2, 3))
+    // a IN (?,?,?) [1,2,3]
+    sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
+    // a IN (?,?,?) [1,2,3]
+    sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
+    // a IN (select id from b where c = ?) [1]
+
+7. IsNull and NotNull
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(IsNull{"a"})
+    // a IS NULL []
+    sql, args, _ := ToSQL(NotNull{"b"})
+     // b IS NOT NULL []
+
+8. And(conds ...Cond), And can connect one or more condtions via AND
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
+    // a=? AND b LIKE ? AND d<>? [1, %c%, 2]
+
+9. Or(conds ...Cond), Or can connect one or more conditions via Or
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
+    // a=? OR b LIKE ? OR d<>? [1, %c%, 2]
+    sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
+    // a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
+
+10. Between
+
+    import . "github.com/go-xorm/builder"
+
+    sql, args, _ := ToSQL(Between("a", 1, 2))
+    // a BETWEEN 1 AND 2
+
+11. define yourself conditions
+Since Cond is a interface, you can define yourself conditions and compare with them
+*/
+package builder

+ 16 - 0
vendor/github.com/go-xorm/builder/error.go

@@ -0,0 +1,16 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import "errors"
+
+var (
+	// ErrNotSupportType not supported SQL type error
+	ErrNotSupportType = errors.New("not supported SQL type")
+	// ErrNoNotInConditions no NOT IN params error
+	ErrNoNotInConditions = errors.New("No NOT IN conditions")
+	// ErrNoInConditions no IN params error
+	ErrNoInConditions = errors.New("No IN conditions")
+)

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

@@ -1 +0,0 @@
-*.db

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

@@ -1,5 +1,7 @@
 Core is a lightweight wrapper of sql.DB.
 
+[![CircleCI](https://circleci.com/gh/go-xorm/core/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/core/tree/master)
+
 # Open
 ```Go
 db, _ := core.Open(db, connstr)

+ 0 - 0
vendor/github.com/go-xorm/core/benchmark.sh


+ 14 - 0
vendor/github.com/go-xorm/core/circle.yml

@@ -0,0 +1,14 @@
+dependencies:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - go get -t -d -v ./...
+    - go build -v
+
+database:
+  override:
+    - mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
+    
+test:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - go test -v -race

+ 10 - 12
vendor/github.com/go-xorm/core/column.go

@@ -16,13 +16,14 @@ const (
 // database column
 type Column struct {
 	Name            string
+	TableName       string
 	FieldName       string
 	SQLType         SQLType
 	Length          int
 	Length2         int
 	Nullable        bool
 	Default         string
-	Indexes         map[string]bool
+	Indexes         map[string]int
 	IsPrimaryKey    bool
 	IsAutoIncrement bool
 	MapType         int
@@ -31,7 +32,6 @@ type Column struct {
 	IsDeleted       bool
 	IsCascade       bool
 	IsVersion       bool
-	fieldPath       []string
 	DefaultIsEmpty  bool
 	EnumOptions     map[string]int
 	SetOptions      map[string]int
@@ -42,13 +42,14 @@ type Column struct {
 func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
 	return &Column{
 		Name:            name,
+		TableName:       "",
 		FieldName:       fieldName,
 		SQLType:         sqlType,
 		Length:          len1,
 		Length2:         len2,
 		Nullable:        nullable,
 		Default:         "",
-		Indexes:         make(map[string]bool),
+		Indexes:         make(map[string]int),
 		IsPrimaryKey:    false,
 		IsAutoIncrement: false,
 		MapType:         TWOSIDES,
@@ -57,7 +58,6 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable
 		IsDeleted:       false,
 		IsCascade:       false,
 		IsVersion:       false,
-		fieldPath:       nil,
 		DefaultIsEmpty:  false,
 		EnumOptions:     make(map[string]int),
 	}
@@ -119,12 +119,10 @@ func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
 
 func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 	var fieldValue reflect.Value
-	if col.fieldPath == nil {
-		col.fieldPath = strings.Split(col.FieldName, ".")
-	}
+	fieldPath := strings.Split(col.FieldName, ".")
 
 	if dataStruct.Type().Kind() == reflect.Map {
-		keyValue := reflect.ValueOf(col.fieldPath[len(col.fieldPath)-1])
+		keyValue := reflect.ValueOf(fieldPath[len(fieldPath)-1])
 		fieldValue = dataStruct.MapIndex(keyValue)
 		return &fieldValue, nil
 	} else if dataStruct.Type().Kind() == reflect.Interface {
@@ -132,19 +130,19 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 		dataStruct = &structValue
 	}
 
-	level := len(col.fieldPath)
-	fieldValue = dataStruct.FieldByName(col.fieldPath[0])
+	level := len(fieldPath)
+	fieldValue = dataStruct.FieldByName(fieldPath[0])
 	for i := 0; i < level-1; i++ {
 		if !fieldValue.IsValid() {
 			break
 		}
 		if fieldValue.Kind() == reflect.Struct {
-			fieldValue = fieldValue.FieldByName(col.fieldPath[i+1])
+			fieldValue = fieldValue.FieldByName(fieldPath[i+1])
 		} else if fieldValue.Kind() == reflect.Ptr {
 			if fieldValue.IsNil() {
 				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
 			}
-			fieldValue = fieldValue.Elem().FieldByName(col.fieldPath[i+1])
+			fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
 		} else {
 			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
 		}

+ 15 - 295
vendor/github.com/go-xorm/core/db.go

@@ -4,9 +4,9 @@ import (
 	"database/sql"
 	"database/sql/driver"
 	"errors"
+	"fmt"
 	"reflect"
 	"regexp"
-	"sync"
 )
 
 func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
@@ -15,12 +15,19 @@ func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
 		return "", []interface{}{}, ErrNoMapPointer
 	}
 
-	args := make([]interface{}, 0)
+	args := make([]interface{}, 0, len(vv.Elem().MapKeys()))
+	var err error
 	query = re.ReplaceAllStringFunc(query, func(src string) string {
-		args = append(args, vv.Elem().MapIndex(reflect.ValueOf(src[1:])).Interface())
+		v := vv.Elem().MapIndex(reflect.ValueOf(src[1:]))
+		if !v.IsValid() {
+			err = fmt.Errorf("map key %s is missing", src[1:])
+		} else {
+			args = append(args, v.Interface())
+		}
 		return "?"
 	})
-	return query, args, nil
+
+	return query, args, err
 }
 
 func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
@@ -95,82 +102,12 @@ func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
 	return db.Query(query, args...)
 }
 
-type Row struct {
-	rows *Rows
-	// One of these two will be non-nil:
-	err error // deferred error for easy chaining
-}
-
-func (row *Row) Columns() ([]string, error) {
-	if row.err != nil {
-		return nil, row.err
-	}
-	return row.rows.Columns()
-}
-
-func (row *Row) Scan(dest ...interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	defer row.rows.Close()
-
-	for _, dp := range dest {
-		if _, ok := dp.(*sql.RawBytes); ok {
-			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
-		}
-	}
-
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	err := row.rows.Scan(dest...)
-	if err != nil {
-		return err
-	}
-	// Make sure the query can be processed to completion with no errors.
-	if err := row.rows.Close(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (row *Row) ScanStructByName(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	return row.rows.ScanStructByName(dest)
-}
-
-func (row *Row) ScanStructByIndex(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	return row.rows.ScanStructByIndex(dest)
-}
-
-// scan data to a slice's pointer, slice's length should equal to columns' number
-func (row *Row) ScanSlice(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	return row.rows.ScanSlice(dest)
-}
-
-// scan data to a map's pointer
-func (row *Row) ScanMap(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	return row.rows.ScanMap(dest)
-}
-
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 	rows, err := db.Query(query, args...)
-	return &Row{rows, err}
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return &Row{rows, nil}
 }
 
 func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
@@ -328,44 +265,6 @@ func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
 	return db.DB.Exec(query, args...)
 }
 
-type Rows struct {
-	*sql.Rows
-	Mapper IMapper
-}
-
-// scan data to a struct's pointer according field index
-func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
-	if len(dest) == 0 {
-		return errors.New("at least one struct")
-	}
-
-	vvvs := make([]reflect.Value, len(dest))
-	for i, s := range dest {
-		vv := reflect.ValueOf(s)
-		if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
-			return errors.New("dest should be a struct's pointer")
-		}
-
-		vvvs[i] = vv.Elem()
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-	newDest := make([]interface{}, len(cols))
-
-	var i = 0
-	for _, vvv := range vvvs {
-		for j := 0; j < vvv.NumField(); j++ {
-			newDest[i] = vvv.Field(j).Addr().Interface()
-			i = i + 1
-		}
-	}
-
-	return rs.Rows.Scan(newDest...)
-}
-
 type EmptyScanner struct {
 }
 
@@ -373,185 +272,6 @@ func (EmptyScanner) Scan(src interface{}) error {
 	return nil
 }
 
-var (
-	fieldCache      = make(map[reflect.Type]map[string]int)
-	fieldCacheMutex sync.RWMutex
-)
-
-func fieldByName(v reflect.Value, name string) reflect.Value {
-	t := v.Type()
-	fieldCacheMutex.RLock()
-	cache, ok := fieldCache[t]
-	fieldCacheMutex.RUnlock()
-	if !ok {
-		cache = make(map[string]int)
-		for i := 0; i < v.NumField(); i++ {
-			cache[t.Field(i).Name] = i
-		}
-		fieldCacheMutex.Lock()
-		fieldCache[t] = cache
-		fieldCacheMutex.Unlock()
-	}
-
-	if i, ok := cache[name]; ok {
-		return v.Field(i)
-	}
-
-	return reflect.Zero(t)
-}
-
-// scan data to a struct's pointer according field name
-func (rs *Rows) ScanStructByName(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
-		return errors.New("dest should be a struct's pointer")
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-	var v EmptyScanner
-	for j, name := range cols {
-		f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
-		if f.IsValid() {
-			newDest[j] = f.Addr().Interface()
-		} else {
-			newDest[j] = &v
-		}
-	}
-
-	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)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
-		return errors.New("dest should be a slice's pointer")
-	}
-
-	vvv := vv.Elem()
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-
-	for j := 0; j < len(cols); j++ {
-		if j >= vvv.Len() {
-			newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
-		} else {
-			newDest[j] = vvv.Index(j).Addr().Interface()
-		}
-	}
-
-	err = rs.Rows.Scan(newDest...)
-	if err != nil {
-		return err
-	}
-
-	srcLen := vvv.Len()
-	for i := srcLen; i < len(cols); i++ {
-		vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
-	}
-	return nil
-}
-
-// scan data to a map's pointer
-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))
-	vvv := vv.Elem()
-
-	for i, _ := range cols {
-		newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
-		//v := reflect.New(vvv.Type().Elem())
-		//newDest[i] = v.Interface()
-	}
-
-	err = rs.Rows.Scan(newDest...)
-	if err != nil {
-		return err
-	}
-
-	for i, name := range cols {
-		vname := reflect.ValueOf(name)
-		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
-	}
-
-	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 Tx struct {
 	*sql.Tx
 	Mapper IMapper

+ 0 - 659
vendor/github.com/go-xorm/core/db_test.go

@@ -1,659 +0,0 @@
-package core
-
-import (
-	"errors"
-	"fmt"
-	"os"
-	"testing"
-	"time"
-
-	_ "github.com/go-sql-driver/mysql"
-	_ "github.com/mattn/go-sqlite3"
-)
-
-var (
-	//dbtype         string = "sqlite3"
-	dbtype         string = "mysql"
-	createTableSql string
-)
-
-type User struct {
-	Id       int64
-	Name     string
-	Title    string
-	Age      float32
-	Alias    string
-	NickName string
-	Created  NullTime
-}
-
-func init() {
-	switch dbtype {
-	case "sqlite3":
-		createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, " +
-			"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
-	case "mysql":
-		createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` TEXT NULL, " +
-			"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
-	default:
-		panic("no db type")
-	}
-}
-
-func testOpen() (*DB, error) {
-	switch dbtype {
-	case "sqlite3":
-		os.Remove("./test.db")
-		return Open("sqlite3", "./test.db")
-	case "mysql":
-		return Open("mysql", "root:@/core_test?charset=utf8")
-	default:
-		panic("no db type")
-	}
-}
-
-func BenchmarkOriQuery(b *testing.B) {
-	b.StopTimer()
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			var Id int64
-			var Name, Title, Alias, NickName string
-			var Age float32
-			var Created NullTime
-			err = rows.Scan(&Id, &Name, &Title, &Age, &Alias, &NickName, &Created)
-			if err != nil {
-				b.Error(err)
-			}
-			//fmt.Println(Id, Name, Title, Age, Alias, NickName)
-		}
-		rows.Close()
-	}
-}
-
-func BenchmarkStructQuery(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			var user User
-			err = rows.ScanStructByIndex(&user)
-			if err != nil {
-				b.Error(err)
-			}
-			if user.Name != "xlw" {
-				fmt.Println(user)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-		rows.Close()
-	}
-}
-
-func BenchmarkStruct2Query(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	db.Mapper = NewCacheMapper(&SnakeMapper{})
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			var user User
-			err = rows.ScanStructByName(&user)
-			if err != nil {
-				b.Error(err)
-			}
-			if user.Name != "xlw" {
-				fmt.Println(user)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-		rows.Close()
-	}
-}
-
-func BenchmarkSliceInterfaceQuery(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		cols, err := rows.Columns()
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			slice := make([]interface{}, len(cols))
-			err = rows.ScanSlice(&slice)
-			if err != nil {
-				b.Error(err)
-			}
-			fmt.Println(slice)
-			if *slice[1].(*string) != "xlw" {
-				fmt.Println(slice)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}
-
-/*func BenchmarkSliceBytesQuery(b *testing.B) {
-	b.StopTimer()
-	os.Remove("./test.db")
-	db, err := Open("sqlite3", "./test.db")
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		cols, err := rows.Columns()
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			slice := make([][]byte, len(cols))
-			err = rows.ScanSlice(&slice)
-			if err != nil {
-				b.Error(err)
-			}
-			if string(slice[1]) != "xlw" {
-				fmt.Println(slice)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}
-*/
-
-func BenchmarkSliceStringQuery(b *testing.B) {
-	b.StopTimer()
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		cols, err := rows.Columns()
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			slice := make([]*string, len(cols))
-			err = rows.ScanSlice(&slice)
-			if err != nil {
-				b.Error(err)
-			}
-			if (*slice[1]) != "xlw" {
-				fmt.Println(slice)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}
-
-func BenchmarkMapInterfaceQuery(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			m := make(map[string]interface{})
-			err = rows.ScanMap(&m)
-			if err != nil {
-				b.Error(err)
-			}
-			if m["name"].(string) != "xlw" {
-				fmt.Println(m)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}
-
-/*func BenchmarkMapBytesQuery(b *testing.B) {
-	b.StopTimer()
-	os.Remove("./test.db")
-	db, err := Open("sqlite3", "./test.db")
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			m := make(map[string][]byte)
-			err = rows.ScanMap(&m)
-			if err != nil {
-				b.Error(err)
-			}
-			if string(m["name"]) != "xlw" {
-				fmt.Println(m)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}
-*/
-/*
-func BenchmarkMapStringQuery(b *testing.B) {
-	b.StopTimer()
-	os.Remove("./test.db")
-	db, err := Open("sqlite3", "./test.db")
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	for i := 0; i < 50; i++ {
-		_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		rows, err := db.Query("select * from user")
-		if err != nil {
-			b.Error(err)
-		}
-
-		for rows.Next() {
-			m := make(map[string]string)
-			err = rows.ScanMap(&m)
-			if err != nil {
-				b.Error(err)
-			}
-			if m["name"] != "xlw" {
-				fmt.Println(m)
-				b.Error(errors.New("name should be xlw"))
-			}
-		}
-
-		rows.Close()
-	}
-}*/
-
-func BenchmarkExec(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
-			"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
-		if err != nil {
-			b.Error(err)
-		}
-	}
-}
-
-func BenchmarkExecMap(b *testing.B) {
-	b.StopTimer()
-
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	b.StartTimer()
-
-	mp := map[string]interface{}{
-		"name":      "xlw",
-		"title":     "tester",
-		"age":       1.2,
-		"alias":     "lunny",
-		"nick_name": "lunny xiao",
-		"created":   time.Now(),
-	}
-
-	for i := 0; i < b.N; i++ {
-		_, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name, created) "+
-			"values (?name,?title,?age,?alias,?nick_name,?created)",
-			&mp)
-		if err != nil {
-			b.Error(err)
-		}
-	}
-}
-
-func TestExecMap(t *testing.T) {
-	db, err := testOpen()
-	if err != nil {
-		t.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		t.Error(err)
-	}
-
-	mp := map[string]interface{}{
-		"name":      "xlw",
-		"title":     "tester",
-		"age":       1.2,
-		"alias":     "lunny",
-		"nick_name": "lunny xiao",
-		"created":   time.Now(),
-	}
-
-	_, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name,created) "+
-		"values (?name,?title,?age,?alias,?nick_name,?created)",
-		&mp)
-	if err != nil {
-		t.Error(err)
-	}
-
-	rows, err := db.Query("select * from user")
-	if err != nil {
-		t.Error(err)
-	}
-
-	for rows.Next() {
-		var user User
-		err = rows.ScanStructByName(&user)
-		if err != nil {
-			t.Error(err)
-		}
-		fmt.Println("--", user)
-	}
-}
-
-func TestExecStruct(t *testing.T) {
-	db, err := testOpen()
-	if err != nil {
-		t.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		t.Error(err)
-	}
-
-	user := User{Name: "xlw",
-		Title:    "tester",
-		Age:      1.2,
-		Alias:    "lunny",
-		NickName: "lunny xiao",
-		Created:  NullTime(time.Now()),
-	}
-
-	_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
-		"values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
-		&user)
-	if err != nil {
-		t.Error(err)
-	}
-
-	rows, err := db.QueryStruct("select * from user where `name` = ?Name", &user)
-	if err != nil {
-		t.Error(err)
-	}
-
-	for rows.Next() {
-		var user User
-		err = rows.ScanStructByName(&user)
-		if err != nil {
-			t.Error(err)
-		}
-		fmt.Println("1--", user)
-	}
-}
-
-func BenchmarkExecStruct(b *testing.B) {
-	b.StopTimer()
-	db, err := testOpen()
-	if err != nil {
-		b.Error(err)
-	}
-	defer db.Close()
-
-	_, err = db.Exec(createTableSql)
-	if err != nil {
-		b.Error(err)
-	}
-
-	b.StartTimer()
-
-	user := User{Name: "xlw",
-		Title:    "tester",
-		Age:      1.2,
-		Alias:    "lunny",
-		NickName: "lunny xiao",
-		Created:  NullTime(time.Now()),
-	}
-
-	for i := 0; i < b.N; i++ {
-		_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
-			"values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
-			&user)
-		if err != nil {
-			b.Error(err)
-		}
-	}
-}

+ 22 - 8
vendor/github.com/go-xorm/core/dialect.go

@@ -20,6 +20,7 @@ type Uri struct {
 	Laddr   string
 	Raddr   string
 	Timeout time.Duration
+	Schema  string
 }
 
 // a dialect is a driver's wrapper
@@ -84,7 +85,7 @@ type Base struct {
 	dialect        Dialect
 	driverName     string
 	dataSourceName string
-	Logger         ILogger
+	logger         ILogger
 	*Uri
 }
 
@@ -93,7 +94,7 @@ func (b *Base) DB() *DB {
 }
 
 func (b *Base) SetLogger(logger ILogger) {
-	b.Logger = logger
+	b.logger = logger
 }
 
 func (b *Base) Init(db *DB, dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
@@ -151,10 +152,8 @@ func (db *Base) DropTableSql(tableName string) string {
 }
 
 func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
+	db.LogSQL(query, args)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 		return false, err
 	}
@@ -277,17 +276,32 @@ func (b *Base) ForUpdateSql(query string) string {
 	return query + " FOR UPDATE"
 }
 
+func (b *Base) LogSQL(sql string, args []interface{}) {
+	if b.logger != nil && b.logger.IsShowSQL() {
+		if len(args) > 0 {
+			b.logger.Infof("[SQL] %v %v", sql, args)
+		} else {
+			b.logger.Infof("[SQL] %v", sql)
+		}
+	}
+}
+
 var (
-	dialects = map[DbType]func() Dialect{}
+	dialects = map[string]func() Dialect{}
 )
 
+// RegisterDialect register database dialect
 func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
 	if dialectFunc == nil {
 		panic("core: Register dialect is nil")
 	}
-	dialects[dbName] = dialectFunc // !nashtsai! allow override dialect
+	dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect
 }
 
+// QueryDialect query if registed database dialect
 func QueryDialect(dbName DbType) Dialect {
-	return dialects[dbName]()
+	if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
+		return d()
+	}
+	return nil
 }

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

@@ -5,6 +5,4 @@ import "errors"
 var (
 	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
 	ErrNoStructPointer = errors.New("mp should be a struct's pointer")
-	//ErrNotExist        = errors.New("Not exist")
-	//ErrIgnore = errors.New("Ignore")
 )

+ 17 - 14
vendor/github.com/go-xorm/core/ilogger.go

@@ -4,25 +4,28 @@ type LogLevel int
 
 const (
 	// !nashtsai! following level also match syslog.Priority value
-	LOG_UNKNOWN LogLevel = iota - 2
-	LOG_OFF     LogLevel = iota - 1
-	LOG_ERR     LogLevel = iota + 3
+	LOG_DEBUG LogLevel = iota
+	LOG_INFO
 	LOG_WARNING
-	LOG_INFO LogLevel = iota + 6
-	LOG_DEBUG
+	LOG_ERR
+	LOG_OFF
+	LOG_UNKNOWN
 )
 
 // logger interface
 type ILogger interface {
-	Debug(v ...interface{}) (err error)
-	Debugf(format string, v ...interface{}) (err error)
-	Err(v ...interface{}) (err error)
-	Errf(format string, v ...interface{}) (err error)
-	Info(v ...interface{}) (err error)
-	Infof(format string, v ...interface{}) (err error)
-	Warning(v ...interface{}) (err error)
-	Warningf(format string, v ...interface{}) (err error)
+	Debug(v ...interface{})
+	Debugf(format string, v ...interface{})
+	Error(v ...interface{})
+	Errorf(format string, v ...interface{})
+	Info(v ...interface{})
+	Infof(format string, v ...interface{})
+	Warn(v ...interface{})
+	Warnf(format string, v ...interface{})
 
 	Level() LogLevel
-	SetLevel(l LogLevel) (err error)
+	SetLevel(l LogLevel)
+
+	ShowSQL(show ...bool)
+	IsShowSQL() bool
 }

+ 0 - 45
vendor/github.com/go-xorm/core/mapper_test.go

@@ -1,45 +0,0 @@
-package core
-
-import (
-	"testing"
-)
-
-func TestGonicMapperFromObj(t *testing.T) {
-	testCases := map[string]string{
-		"HTTPLib":             "http_lib",
-		"id":                  "id",
-		"ID":                  "id",
-		"IDa":                 "i_da",
-		"iDa":                 "i_da",
-		"IDAa":                "id_aa",
-		"aID":                 "a_id",
-		"aaID":                "aa_id",
-		"aaaID":               "aaa_id",
-		"MyREalFunkYLONgNAME": "my_r_eal_funk_ylo_ng_name",
-	}
-
-	for in, expected := range testCases {
-		out := gonicCasedName(in)
-		if out != expected {
-			t.Errorf("Given %s, expected %s but got %s", in, expected, out)
-		}
-	}
-}
-
-func TestGonicMapperToObj(t *testing.T) {
-	testCases := map[string]string{
-		"http_lib":                  "HTTPLib",
-		"id":                        "ID",
-		"ida":                       "Ida",
-		"id_aa":                     "IDAa",
-		"aa_id":                     "AaID",
-		"my_r_eal_funk_ylo_ng_name": "MyREalFunkYloNgName",
-	}
-
-	for in, expected := range testCases {
-		out := LintGonicMapper.Table2Obj(in)
-		if out != expected {
-			t.Errorf("Given %s, expected %s but got %s", in, expected, out)
-		}
-	}
-}

+ 0 - 33
vendor/github.com/go-xorm/core/pk_test.go

@@ -1,33 +0,0 @@
-package core
-
-import (
-	"fmt"
-	"reflect"
-	"testing"
-)
-
-func TestPK(t *testing.T) {
-	p := NewPK(1, 3, "string")
-	str, err := p.ToString()
-	if err != nil {
-		t.Error(err)
-	}
-	fmt.Println(str)
-
-	s := &PK{}
-	err = s.FromString(str)
-	if err != nil {
-		t.Error(err)
-	}
-	fmt.Println(s)
-
-	if len(*p) != len(*s) {
-		t.Fatal("p", *p, "should be equal", *s)
-	}
-
-	for i, ori := range *p {
-		if ori != (*s)[i] {
-			t.Fatal("ori", ori, reflect.ValueOf(ori), "should be equal", (*s)[i], reflect.ValueOf((*s)[i]))
-		}
-	}
-}

+ 380 - 0
vendor/github.com/go-xorm/core/rows.go

@@ -0,0 +1,380 @@
+package core
+
+import (
+	"database/sql"
+	"errors"
+	"reflect"
+	"sync"
+)
+
+type Rows struct {
+	*sql.Rows
+	Mapper IMapper
+}
+
+func (rs *Rows) ToMapString() ([]map[string]string, error) {
+	cols, err := rs.Columns()
+	if err != nil {
+		return nil, err
+	}
+
+	var results = make([]map[string]string, 0, 10)
+	for rs.Next() {
+		var record = make(map[string]string, len(cols))
+		err = rs.ScanMap(&record)
+		if err != nil {
+			return nil, err
+		}
+		results = append(results, record)
+	}
+	return results, nil
+}
+
+// scan data to a struct's pointer according field index
+func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
+	if len(dest) == 0 {
+		return errors.New("at least one struct")
+	}
+
+	vvvs := make([]reflect.Value, len(dest))
+	for i, s := range dest {
+		vv := reflect.ValueOf(s)
+		if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+			return errors.New("dest should be a struct's pointer")
+		}
+
+		vvvs[i] = vv.Elem()
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+	newDest := make([]interface{}, len(cols))
+
+	var i = 0
+	for _, vvv := range vvvs {
+		for j := 0; j < vvv.NumField(); j++ {
+			newDest[i] = vvv.Field(j).Addr().Interface()
+			i = i + 1
+		}
+	}
+
+	return rs.Rows.Scan(newDest...)
+}
+
+var (
+	fieldCache      = make(map[reflect.Type]map[string]int)
+	fieldCacheMutex sync.RWMutex
+)
+
+func fieldByName(v reflect.Value, name string) reflect.Value {
+	t := v.Type()
+	fieldCacheMutex.RLock()
+	cache, ok := fieldCache[t]
+	fieldCacheMutex.RUnlock()
+	if !ok {
+		cache = make(map[string]int)
+		for i := 0; i < v.NumField(); i++ {
+			cache[t.Field(i).Name] = i
+		}
+		fieldCacheMutex.Lock()
+		fieldCache[t] = cache
+		fieldCacheMutex.Unlock()
+	}
+
+	if i, ok := cache[name]; ok {
+		return v.Field(i)
+	}
+
+	return reflect.Zero(t)
+}
+
+// scan data to a struct's pointer according field name
+func (rs *Rows) ScanStructByName(dest interface{}) error {
+	vv := reflect.ValueOf(dest)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return errors.New("dest should be a struct's pointer")
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+	var v EmptyScanner
+	for j, name := range cols {
+		f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
+		if f.IsValid() {
+			newDest[j] = f.Addr().Interface()
+		} else {
+			newDest[j] = &v
+		}
+	}
+
+	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)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
+		return errors.New("dest should be a slice's pointer")
+	}
+
+	vvv := vv.Elem()
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+
+	for j := 0; j < len(cols); j++ {
+		if j >= vvv.Len() {
+			newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
+		} else {
+			newDest[j] = vvv.Index(j).Addr().Interface()
+		}
+	}
+
+	err = rs.Rows.Scan(newDest...)
+	if err != nil {
+		return err
+	}
+
+	srcLen := vvv.Len()
+	for i := srcLen; i < len(cols); i++ {
+		vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
+	}
+	return nil
+}
+
+// scan data to a map's pointer
+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))
+	vvv := vv.Elem()
+
+	for i, _ := range cols {
+		newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
+		//v := reflect.New(vvv.Type().Elem())
+		//newDest[i] = v.Interface()
+	}
+
+	err = rs.Rows.Scan(newDest...)
+	if err != nil {
+		return err
+	}
+
+	for i, name := range cols {
+		vname := reflect.ValueOf(name)
+		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
+	}
+
+	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:
+	err error // deferred error for easy chaining
+}
+
+func (row *Row) Columns() ([]string, error) {
+	if row.err != nil {
+		return nil, row.err
+	}
+	return row.rows.Columns()
+}
+
+func (row *Row) Scan(dest ...interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	for _, dp := range dest {
+		if _, ok := dp.(*sql.RawBytes); ok {
+			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
+		}
+	}
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.Scan(dest...)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ScanStructByName(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanStructByName(dest)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ScanStructByIndex(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanStructByIndex(dest)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+// scan data to a slice's pointer, slice's length should equal to columns' number
+func (row *Row) ScanSlice(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanSlice(dest)
+	if err != nil {
+		return err
+	}
+
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+// scan data to a map's pointer
+func (row *Row) ScanMap(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanMap(dest)
+	if err != nil {
+		return err
+	}
+
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ToMapString() (map[string]string, error) {
+	cols, err := row.Columns()
+	if err != nil {
+		return nil, err
+	}
+
+	var record = make(map[string]string, len(cols))
+	err = row.ScanMap(&record)
+	if err != nil {
+		return nil, err
+	}
+
+	return record, nil
+}

+ 27 - 6
vendor/github.com/go-xorm/core/table.go

@@ -47,19 +47,40 @@ func NewTable(name string, t reflect.Type) *Table {
 	}
 }
 
+func (table *Table) columnsByName(name string) []*Column {
+
+	n := len(name)
+
+	for k := range table.columnsMap {
+		if len(k) != n {
+			continue
+		}
+		if strings.EqualFold(k, name) {
+			return table.columnsMap[k]
+		}
+	}
+	return nil
+}
+
 func (table *Table) GetColumn(name string) *Column {
-	if c, ok := table.columnsMap[strings.ToLower(name)]; ok {
-		return c[0]
+
+	cols := table.columnsByName(name)
+
+	if cols != nil {
+		return cols[0]
 	}
+
 	return nil
 }
 
 func (table *Table) GetColumnIdx(name string, idx int) *Column {
-	if c, ok := table.columnsMap[strings.ToLower(name)]; ok {
-		if idx < len(c) {
-			return c[idx]
-		}
+
+	cols := table.columnsByName(name)
+
+	if cols != nil && idx < len(cols) {
+		return cols[idx]
 	}
+
 	return nil
 }
 

+ 10 - 33
vendor/github.com/go-xorm/core/type.go

@@ -54,7 +54,7 @@ func (s *SQLType) IsNumeric() bool {
 }
 
 func (s *SQLType) IsJson() bool {
-	return s.Name == Json
+	return s.Name == Json || s.Name == Jsonb
 }
 
 var (
@@ -105,7 +105,8 @@ var (
 	Serial    = "SERIAL"
 	BigSerial = "BIGSERIAL"
 
-	Json = "JSON"
+	Json  = "JSON"
+	Jsonb = "JSONB"
 
 	SqlTypes = map[string]int{
 		Bit:       NUMERIC_TYPE,
@@ -116,9 +117,10 @@ var (
 		Integer:   NUMERIC_TYPE,
 		BigInt:    NUMERIC_TYPE,
 
-		Enum: TEXT_TYPE,
-		Set:  TEXT_TYPE,
-		Json: TEXT_TYPE,
+		Enum:  TEXT_TYPE,
+		Set:   TEXT_TYPE,
+		Json:  TEXT_TYPE,
+		Jsonb: TEXT_TYPE,
 
 		Char:       TEXT_TYPE,
 		Varchar:    TEXT_TYPE,
@@ -205,6 +207,7 @@ var (
 	StringType = reflect.TypeOf(c_EMPTY_STRING)
 	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
 	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
+	BytesType  = reflect.SliceOf(ByteType)
 
 	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
 )
@@ -235,6 +238,7 @@ var (
 	PtrTimeType = reflect.PtrTo(TimeType)
 )
 
+// Type2SQLType generate SQLType acorrding Go's type
 func Type2SQLType(t reflect.Type) (st SQLType) {
 	switch k := t.Kind(); k {
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
@@ -265,40 +269,13 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
 			st = SQLType{Text, 0, 0}
 		}
 	case reflect.Ptr:
-		st, _ = ptrType2SQLType(t)
+		st = Type2SQLType(t.Elem())
 	default:
 		st = SQLType{Text, 0, 0}
 	}
 	return
 }
 
-func ptrType2SQLType(t reflect.Type) (st SQLType, has bool) {
-	has = true
-
-	switch t {
-	case reflect.TypeOf(&c_EMPTY_STRING):
-		st = SQLType{Varchar, 255, 0}
-		return
-	case reflect.TypeOf(&c_BOOL_DEFAULT):
-		st = SQLType{Bool, 0, 0}
-	case reflect.TypeOf(&c_COMPLEX64_DEFAULT), reflect.TypeOf(&c_COMPLEX128_DEFAULT):
-		st = SQLType{Varchar, 64, 0}
-	case reflect.TypeOf(&c_FLOAT32_DEFAULT):
-		st = SQLType{Float, 0, 0}
-	case reflect.TypeOf(&c_FLOAT64_DEFAULT):
-		st = SQLType{Double, 0, 0}
-	case reflect.TypeOf(&c_INT64_DEFAULT), reflect.TypeOf(&c_UINT64_DEFAULT):
-		st = SQLType{BigInt, 0, 0}
-	case reflect.TypeOf(&c_TIME_DEFAULT):
-		st = SQLType{DateTime, 0, 0}
-	case reflect.TypeOf(&c_INT_DEFAULT), reflect.TypeOf(&c_INT32_DEFAULT), reflect.TypeOf(&c_INT8_DEFAULT), reflect.TypeOf(&c_INT16_DEFAULT), reflect.TypeOf(&c_UINT_DEFAULT), reflect.TypeOf(&c_UINT32_DEFAULT), reflect.TypeOf(&c_UINT8_DEFAULT), reflect.TypeOf(&c_UINT16_DEFAULT):
-		st = SQLType{Int, 0, 0}
-	default:
-		has = false
-	}
-	return
-}
-
 // default sql type change to go types
 func SQLType2Type(st SQLType) reflect.Type {
 	name := strings.ToUpper(st.Name)

+ 0 - 28
vendor/github.com/go-xorm/xorm/.gitignore

@@ -1,28 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-*.db
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-vendor
-
-*.log
-.vendor
-temp_test.go

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

@@ -1,6 +0,0 @@
-[submodule "docs/manual-en-US"]
-	path = docs/manual-en-US
-	url = https://github.com/go-xorm/manual-en-US.git
-[submodule "docs/manual-zh-CN"]
-	path = docs/manual-zh-CN
-	url = https://github.com/go-xorm/manual-zh-CN.git

+ 0 - 2
vendor/github.com/go-xorm/xorm/.gopmfile

@@ -1,2 +0,0 @@
-[target]
-path = github.com/go-xorm/xorm

+ 4 - 0
vendor/github.com/go-xorm/xorm/CONTRIBUTING.md

@@ -9,6 +9,10 @@ conventions when submitting patches.
 * [fork a repo](https://help.github.com/articles/fork-a-repo)
 * [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
 
+### Language
+
+Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible.
+
 ### Sign your codes with comments
 ```
 // !<you github id>! your comments

+ 35 - 28
vendor/github.com/go-xorm/xorm/README.md

@@ -2,9 +2,11 @@
 
 Xorm is a simple and powerful ORM for Go.
 
-[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master)  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
 
-[![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+# Notice
+
+The last master version is not backwards compatible. You should use `engine.ShowSQL()` and `engine.Logger().SetLevel()` instead of `engine.ShowSQL = `, `engine.ShowInfo = ` and so on.
 
 # Features
 
@@ -26,6 +28,7 @@ Xorm is a simple and powerful ORM for Go.
 
 * Optimistic Locking support
 
+* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder)
 
 # Drivers Support
 
@@ -43,14 +46,26 @@ Drivers for Go's sql package which currently support database/sql includes:
 
 * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 
-* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
-
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 
-* ql: [github.com/cznic/ql](https://github.com/cznic/ql) (experiment)
-
 # Changelog
 
+* **v0.6.0**
+    * remove support for ql
+    * add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or` 
+methods can use `builder.Cond` as parameter
+    * add Sum, SumInt, SumInt64 and NotIn methods
+    * some bugs fixed
+
+* **v0.5.0**
+    * logging interface changed
+    * some bugs fixed
+
+* **v0.4.5**
+    * many bugs fixed
+    * extends support unlimited deepth
+    * Delete Limit support
+
 * **v0.4.4**
     * ql database expriment support
     * tidb database expriment support
@@ -58,26 +73,10 @@ Drivers for Go's sql package which currently support database/sql includes:
     * select ForUpdate support
     * many bugs fixed
 
-* **v0.4.3**
-    * Json column type support
-    * oracle expirement support
-    * bug fixed
-
-* **v0.4.2**
-	* Transaction will auto rollback if not Rollback or Commit be called.
-    * Gonic Mapper support
-    * bug fixed
-
-[More changelogs ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
+[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
 
 # Installation
 
-If you have [gopm](https://github.com/gpmgo/gopm) installed,
-
-	gopm get github.com/go-xorm/xorm
-
-Or
-
 	go get github.com/go-xorm/xorm
 
 # Documents
@@ -124,7 +123,7 @@ results, err := engine.Query("select * from user")
 affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
 ```
 
-* Insert one or multipe records to database
+* Insert one or multiple records to database
 
 ```Go
 affected, err := engine.Insert(&user)
@@ -173,7 +172,7 @@ err := engine.Table("user").Select("user.*, detail.*")
 // SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
 ```
 
-* Query multiple records and record by record handle, there two methods Iterate and Rows
+* Query multiple records and record by record handle, there are two methods Iterate and Rows
 
 ```Go
 err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
@@ -191,7 +190,7 @@ for rows.Next() {
 }
 ```
 
-* Update one or more records, default will update non-empty and non-zero fields except to use Cols, AllCols and etc.
+* Update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
 
 ```Go
 affected, err := engine.Id(1).Update(&user)
@@ -201,7 +200,7 @@ affected, err := engine.Update(&user, &User{Name:name})
 // UPDATE user SET ... Where name = ?
 
 var ids = []int64{1, 2, 3}
-affected, err := engine.In(ids).Update(&user)
+affected, err := engine.In("id", ids).Update(&user)
 // UPDATE user SET ... Where id IN (?, ?, ?)
 
 // force update indicated columns by Cols
@@ -216,11 +215,12 @@ affected, err := engine.Id(1).AllCols().Update(&user)
 // UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
 ```
 
-* Delete one or more records, Delete MUST has conditon
+* Delete one or more records, Delete MUST have condition
 
 ```Go
 affected, err := engine.Where(...).Delete(&user)
 // DELETE FROM user Where ...
+affected, err := engine.Id(2).Delete(&user)
 ```
 
 * Count records
@@ -230,6 +230,13 @@ counts, err := engine.Count(&user)
 // SELECT count(*) AS total FROM user
 ```
 
+* Query conditions builder
+
+```Go
+err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
+// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
+```
+
 # Cases
 
 * [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)

+ 29 - 15
vendor/github.com/go-xorm/xorm/README_CN.md

@@ -4,9 +4,11 @@
 
 xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
 
-[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master)  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
 
-[![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm)
+# 注意
+
+最新的版本有不兼容的更新,您必须使用 `engine.ShowSQL()` 和 `engine.Logger().SetLevel()` 来替代 `engine.ShowSQL = `, `engine.ShowInfo = ` 等等。
 
 ## 特性
 
@@ -28,6 +30,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 * 支持记录版本(即乐观锁)
 
+* 内置SQL Builder支持
+
 ## 驱动支持
 
 目前支持的Go数据库驱动和对应的数据库如下:
@@ -48,10 +52,24 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
 
-* ql: [github.com/cznic/ql](https://github.com/cznic/ql) (试验性支持)
-
 ## 更新日志
 
+* **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修正
+
+* **v0.4.5**
+    * bug修正
+    * extends 支持无限级
+    * Delete Limit 支持
+
 * **v0.4.4**
     * Tidb 数据库支持
     * QL 试验性支持
@@ -59,21 +77,10 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
     * ForUpdate 支持
     * bug修正
 
-* **v0.4.3**
-    * Json 字段类型支持
-    * oracle实验性支持
-    * bug修正
-
 [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 
 ## 安装
 
-推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
-
-	gopm get github.com/go-xorm/xorm
-
-或者您也可以使用go工具进行安装:
-
 	go get github.com/go-xorm/xorm
 
 ## 文档
@@ -226,6 +233,13 @@ counts, err := engine.Count(&user)
 // SELECT count(*) AS total FROM user
 ```
 
+* 条件编辑器
+
+```Go
+err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
+// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
+```
+
 # 案例
 
 * [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)

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

@@ -1 +1 @@
-xorm v0.4.5.0204
+xorm v0.6.0.1022

+ 25 - 0
vendor/github.com/go-xorm/xorm/circle.yml

@@ -0,0 +1,25 @@
+dependencies:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - go get -t -d -v ./...
+    - go get -t -d -v github.com/go-xorm/tests
+    - go build -v
+
+database:
+  override:
+    - mysql -u root -e "CREATE DATABASE xorm_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
+    - mysql -u root -e "CREATE DATABASE xorm_test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
+    - mysql -u root -e "CREATE DATABASE xorm_test2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
+    - mysql -u root -e "CREATE DATABASE xorm_test3 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
+    - createdb -p 5432 -e -U postgres xorm_test
+    - createdb -p 5432 -e -U postgres xorm_test1
+    - createdb -p 5432 -e -U postgres xorm_test2
+    - createdb -p 5432 -e -U postgres xorm_test3
+
+test:
+  override:
+    # './...' is a relative pattern which means all subdirectories
+    - go test -v -race
+    - 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

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

@@ -0,0 +1,249 @@
+// Copyright 2017 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql/driver"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+
+func strconvErr(err error) error {
+	if ne, ok := err.(*strconv.NumError); ok {
+		return ne.Err
+	}
+	return err
+}
+
+func cloneBytes(b []byte) []byte {
+	if b == nil {
+		return nil
+	} else {
+		c := make([]byte, len(b))
+		copy(c, b)
+		return c
+	}
+}
+
+func asString(src interface{}) string {
+	switch v := src.(type) {
+	case string:
+		return v
+	case []byte:
+		return string(v)
+	}
+	rv := reflect.ValueOf(src)
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.FormatInt(rv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.FormatUint(rv.Uint(), 10)
+	case reflect.Float64:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+	case reflect.Float32:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+	case reflect.Bool:
+		return strconv.FormatBool(rv.Bool())
+	}
+	return fmt.Sprintf("%v", src)
+}
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.AppendInt(buf, rv.Int(), 10), true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.AppendUint(buf, rv.Uint(), 10), true
+	case reflect.Float32:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+	case reflect.Float64:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+	case reflect.Bool:
+		return strconv.AppendBool(buf, rv.Bool()), true
+	case reflect.String:
+		s := rv.String()
+		return append(buf, s...), true
+	}
+	return
+}
+
+// convertAssign copies to dest the value in src, converting it if possible.
+// An error is returned if the copy would result in loss of information.
+// dest should be a pointer type.
+func convertAssign(dest, src interface{}) error {
+	// Common cases, without reflect.
+	switch s := src.(type) {
+	case string:
+		switch d := dest.(type) {
+		case *string:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = s
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = []byte(s)
+			return nil
+		}
+	case []byte:
+		switch d := dest.(type) {
+		case *string:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = string(s)
+			return nil
+		case *interface{}:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = cloneBytes(s)
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = cloneBytes(s)
+			return nil
+		}
+
+	case time.Time:
+		switch d := dest.(type) {
+		case *string:
+			*d = s.Format(time.RFC3339Nano)
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = []byte(s.Format(time.RFC3339Nano))
+			return nil
+		}
+	case nil:
+		switch d := dest.(type) {
+		case *interface{}:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = nil
+			return nil
+		case *[]byte:
+			if d == nil {
+				return errNilPtr
+			}
+			*d = nil
+			return nil
+		}
+	}
+
+	var sv reflect.Value
+
+	switch d := dest.(type) {
+	case *string:
+		sv = reflect.ValueOf(src)
+		switch sv.Kind() {
+		case reflect.Bool,
+			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+			reflect.Float32, reflect.Float64:
+			*d = asString(src)
+			return nil
+		}
+	case *[]byte:
+		sv = reflect.ValueOf(src)
+		if b, ok := asBytes(nil, sv); ok {
+			*d = b
+			return nil
+		}
+	case *bool:
+		bv, err := driver.Bool.ConvertValue(src)
+		if err == nil {
+			*d = bv.(bool)
+		}
+		return err
+	case *interface{}:
+		*d = src
+		return nil
+	}
+
+	dpv := reflect.ValueOf(dest)
+	if dpv.Kind() != reflect.Ptr {
+		return errors.New("destination not a pointer")
+	}
+	if dpv.IsNil() {
+		return errNilPtr
+	}
+
+	if !sv.IsValid() {
+		sv = reflect.ValueOf(src)
+	}
+
+	dv := reflect.Indirect(dpv)
+	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
+		switch b := src.(type) {
+		case []byte:
+			dv.Set(reflect.ValueOf(cloneBytes(b)))
+		default:
+			dv.Set(sv)
+		}
+		return nil
+	}
+
+	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
+		dv.Set(sv.Convert(dv.Type()))
+		return nil
+	}
+
+	switch dv.Kind() {
+	case reflect.Ptr:
+		if src == nil {
+			dv.Set(reflect.Zero(dv.Type()))
+			return nil
+		} else {
+			dv.Set(reflect.New(dv.Type().Elem()))
+			return convertAssign(dv.Interface(), src)
+		}
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		s := asString(src)
+		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetInt(i64)
+		return nil
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		s := asString(src)
+		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetUint(u64)
+		return nil
+	case reflect.Float32, reflect.Float64:
+		s := asString(src)
+		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetFloat(f64)
+		return nil
+	case reflect.String:
+		dv.SetString(asString(src))
+		return nil
+	}
+
+	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
+}

+ 57 - 24
vendor/github.com/go-xorm/xorm/mssql_dialect.go → vendor/github.com/go-xorm/xorm/dialect_mssql.go

@@ -13,10 +13,6 @@ import (
 	"github.com/go-xorm/core"
 )
 
-// func init() {
-// 	RegisterDialect("mssql", &mssql{})
-// }
-
 var (
 	mssqlReservedWords = map[string]bool{
 		"ADD":                    true,
@@ -247,10 +243,13 @@ func (db *mssql) SqlType(c *core.Column) string {
 		c.Length = 7
 	case core.MediumInt:
 		res = core.Int
-	case core.MediumText, core.TinyText, core.LongText, core.Json:
-		res = core.Text
+	case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json:
+		res = core.Varchar + "(MAX)"
 	case core.Double:
 		res = core.Real
+	case core.Uuid:
+		res = core.Varchar
+		c.Length = 40
 	default:
 		res = t
 	}
@@ -259,8 +258,9 @@ func (db *mssql) SqlType(c *core.Column) string {
 		return core.Int
 	}
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
@@ -334,9 +334,12 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
 
 func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 	args := []interface{}{}
-	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
-from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
-where a.object_id=object_id('` + tableName + `')`
+	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
+	      replace(replace(isnull(c.text,''),'(',''),')','') as vdefault   
+          from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id 
+          left join  sys.syscomments c  on a.default_object_id=c.id 
+          where a.object_id=object_id('` + tableName + `')`
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
@@ -347,32 +350,38 @@ where a.object_id=object_id('` + tableName + `')`
 	cols := make(map[string]*core.Column)
 	colSeq := make([]string, 0)
 	for rows.Next() {
-		var name, ctype, precision, scale string
-		var maxLen int
-		err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale)
+		var name, ctype, vdefault string
+		var maxLen, precision, scale int
+		var nullable bool
+		err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault)
 		if err != nil {
 			return nil, nil, err
 		}
 
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
-		col.Length = maxLen
+		col.Indexes = make(map[string]int)
 		col.Name = strings.Trim(name, "` ")
-
+		col.Nullable = nullable
+		col.Default = vdefault
 		ct := strings.ToUpper(ctype)
+		if ct == "DECIMAL" {
+			col.Length = precision
+			col.Length2 = scale
+		} else {
+			col.Length = maxLen
+		}
 		switch ct {
 		case "DATETIMEOFFSET":
-			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 		case "NVARCHAR":
-			col.SQLType = core.SQLType{core.NVarchar, 0, 0}
+			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
 		case "IMAGE":
-			col.SQLType = core.SQLType{core.VarBinary, 0, 0}
+			col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
 		default:
 			if _, ok := core.SqlTypes[ct]; ok {
-				col.SQLType = core.SQLType{ct, 0, 0}
+				col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
 			} else {
-				return nil, nil, errors.New(fmt.Sprintf("unknow colType %v for %v - %v",
-					ct, tableName, col.Name))
+				return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name)
 			}
 		}
 
@@ -394,6 +403,7 @@ where a.object_id=object_id('` + tableName + `')`
 func (db *mssql) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	s := `select name from sysobjects where xtype ='U'`
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
@@ -428,6 +438,7 @@ INNER   JOIN SYS.COLUMNS C  ON IXS.OBJECT_ID=C.OBJECT_ID
 AND IXCS.COLUMN_ID=C.COLUMN_ID
 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 `
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
@@ -459,7 +470,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 		colName = strings.Trim(colName, "` ")
 
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			indexName = indexName[5+len(tableName) : len(indexName)]
+			indexName = indexName[5+len(tableName):]
 		}
 
 		var index *core.Index
@@ -516,3 +527,25 @@ func (db *mssql) ForUpdateSql(query string) string {
 func (db *mssql) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 }
+
+type odbcDriver struct {
+}
+
+func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	kv := strings.Split(dataSourceName, ";")
+	var dbName string
+
+	for _, c := range kv {
+		vv := strings.Split(strings.TrimSpace(c), "=")
+		if len(vv) == 2 {
+			switch strings.ToLower(vv[0]) {
+			case "database":
+				dbName = vv[1]
+			}
+		}
+	}
+	if dbName == "" {
+		return nil, errors.New("no db name provided")
+	}
+	return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
+}

+ 103 - 23
vendor/github.com/go-xorm/xorm/mysql_dialect.go → vendor/github.com/go-xorm/xorm/dialect_mysql.go

@@ -8,6 +8,7 @@ import (
 	"crypto/tls"
 	"errors"
 	"fmt"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
@@ -15,10 +16,6 @@ import (
 	"github.com/go-xorm/core"
 )
 
-// func init() {
-// 	RegisterDialect("mysql", &mysql{})
-// }
-
 var (
 	mysqlReservedWords = map[string]bool{
 		"ADD":               true,
@@ -206,7 +203,7 @@ func (db *mysql) SqlType(c *core.Column) string {
 		res = core.Enum
 		res += "("
 		opts := ""
-		for v, _ := range c.EnumOptions {
+		for v := range c.EnumOptions {
 			opts += fmt.Sprintf(",'%v'", v)
 		}
 		res += strings.TrimLeft(opts, ",")
@@ -215,7 +212,7 @@ func (db *mysql) SqlType(c *core.Column) string {
 		res = core.Set
 		res += "("
 		opts := ""
-		for v, _ := range c.SetOptions {
+		for v := range c.SetOptions {
 			opts += fmt.Sprintf(",'%v'", v)
 		}
 		res += strings.TrimLeft(opts, ",")
@@ -231,8 +228,8 @@ func (db *mysql) SqlType(c *core.Column) string {
 		res = t
 	}
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
 
 	if res == core.BigInt && !hasLen1 && !hasLen2 {
 		c.Length = 20
@@ -303,12 +300,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 	args := []interface{}{db.DbName, tableName}
 	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
 		" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
-
 	if err != nil {
 		return nil, nil, err
 	}
@@ -318,7 +312,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 	colSeq := make([]string, 0)
 	for rows.Next() {
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 
 		var columnName, isNullable, colType, colKey, extra string
 		var colDefault *string
@@ -380,9 +374,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 		col.Length = len1
 		col.Length2 = len2
 		if _, ok := core.SqlTypes[colType]; ok {
-			col.SQLType = core.SQLType{colType, len1, len2}
+			col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
 		} else {
-			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
+			return nil, nil, fmt.Errorf("Unknown colType %v", colType)
 		}
 
 		if colKey == "PRI" {
@@ -414,12 +408,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 func (db *mysql) GetTables() ([]*core.Table, error) {
 	args := []interface{}{db.DbName}
 	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
-		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
+		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -445,11 +437,9 @@ func (db *mysql) GetTables() ([]*core.Table, error) {
 func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{db.DbName, tableName}
 	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -477,7 +467,7 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 		colName = strings.Trim(colName, "` ")
 		var isRegular bool
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			indexName = indexName[5+len(tableName) : len(indexName)]
+			indexName = indexName[5+len(tableName):]
 			isRegular = true
 		}
 
@@ -498,3 +488,93 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 func (db *mysql) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}}
 }
+
+type mymysqlDriver struct {
+}
+
+func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.MYSQL}
+
+	pd := strings.SplitN(dataSourceName, "*", 2)
+	if len(pd) == 2 {
+		// Parse protocol part of URI
+		p := strings.SplitN(pd[0], ":", 2)
+		if len(p) != 2 {
+			return nil, errors.New("Wrong protocol part of URI")
+		}
+		db.Proto = p[0]
+		options := strings.Split(p[1], ",")
+		db.Raddr = options[0]
+		for _, o := range options[1:] {
+			kv := strings.SplitN(o, "=", 2)
+			var k, v string
+			if len(kv) == 2 {
+				k, v = kv[0], kv[1]
+			} else {
+				k, v = o, "true"
+			}
+			switch k {
+			case "laddr":
+				db.Laddr = v
+			case "timeout":
+				to, err := time.ParseDuration(v)
+				if err != nil {
+					return nil, err
+				}
+				db.Timeout = to
+			default:
+				return nil, errors.New("Unknown option: " + k)
+			}
+		}
+		// Remove protocol part
+		pd = pd[1:]
+	}
+	// Parse database part of URI
+	dup := strings.SplitN(pd[0], "/", 3)
+	if len(dup) != 3 {
+		return nil, errors.New("Wrong database part of URI")
+	}
+	db.DbName = dup[0]
+	db.User = dup[1]
+	db.Passwd = dup[2]
+
+	return db, nil
+}
+
+type mysqlDriver struct {
+}
+
+func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	dsnPattern := regexp.MustCompile(
+		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
+			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
+			`\/(?P<dbname>.*?)` + // /dbname
+			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	//tlsConfigRegister := make(map[string]*tls.Config)
+	names := dsnPattern.SubexpNames()
+
+	uri := &core.Uri{DbType: core.MYSQL}
+
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			uri.DbName = match
+		case "params":
+			if len(match) > 0 {
+				kvs := strings.Split(match, "&")
+				for _, kv := range kvs {
+					splits := strings.Split(kv, "=")
+					if len(splits) == 2 {
+						switch splits[0] {
+						case "charset":
+							uri.Charset = splits[1]
+						}
+					}
+				}
+			}
+
+		}
+	}
+	return uri, nil
+}

+ 81 - 42
vendor/github.com/go-xorm/xorm/oracle_dialect.go → vendor/github.com/go-xorm/xorm/dialect_oracle.go

@@ -7,16 +7,13 @@ package xorm
 import (
 	"errors"
 	"fmt"
+	"regexp"
 	"strconv"
 	"strings"
 
 	"github.com/go-xorm/core"
 )
 
-// func init() {
-// 	RegisterDialect("oracle", &oracle{})
-// }
-
 var (
 	oracleReservedWords = map[string]bool{
 		"ACCESS":                    true,
@@ -530,8 +527,9 @@ func (db *oracle) SqlType(c *core.Column) string {
 		res = t
 	}
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
@@ -581,14 +579,14 @@ func (db *oracle) DropTableSql(tableName string) string {
 	return fmt.Sprintf("DROP TABLE `%s`", tableName)
 }
 
-func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
 	var sql string
 	sql = "CREATE TABLE "
 	if tableName == "" {
 		tableName = table.Name
 	}
 
-	sql += b.Quote(tableName) + " ("
+	sql += db.Quote(tableName) + " ("
 
 	pkList := table.PrimaryKeys
 
@@ -597,7 +595,7 @@ func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, chars
 		/*if col.IsPrimaryKey && len(pkList) == 1 {
 			sql += col.String(b.dialect)
 		} else {*/
-		sql += col.StringNoPk(b)
+		sql += col.StringNoPk(db)
 		//}
 		sql = strings.TrimSpace(sql)
 		sql += ", "
@@ -605,17 +603,17 @@ func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, chars
 
 	if len(pkList) > 0 {
 		sql += "PRIMARY KEY ( "
-		sql += b.Quote(strings.Join(pkList, b.Quote(",")))
+		sql += db.Quote(strings.Join(pkList, db.Quote(",")))
 		sql += " ), "
 	}
 
 	sql = sql[:len(sql)-2] + ")"
-	if b.SupportEngine() && storeEngine != "" {
+	if db.SupportEngine() && storeEngine != "" {
 		sql += " ENGINE=" + storeEngine
 	}
-	if b.SupportCharset() {
+	if db.SupportCharset() {
 		if len(charset) == 0 {
-			charset = b.URI().Charset
+			charset = db.URI().Charset
 		}
 		if len(charset) > 0 {
 			sql += " DEFAULT CHARSET " + charset
@@ -637,9 +635,7 @@ func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
 
 func (db *oracle) MustDropTable(tableName string) error {
 	sql, args := db.TableCheckSql(tableName)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", sql, args)
-	}
+	db.LogSQL(sql, args)
 
 	rows, err := db.DB().Query(sql, args...)
 	if err != nil {
@@ -652,9 +648,8 @@ func (db *oracle) MustDropTable(tableName string) error {
 	}
 
 	sql = "Drop Table \"" + tableName + "\""
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", sql)
-	}
+	db.LogSQL(sql, args)
+
 	_, err = db.DB().Exec(sql)
 	return err
 }
@@ -669,10 +664,9 @@ func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 		" AND column_name = :2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 		return false, err
 	}
@@ -688,11 +682,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 	args := []interface{}{tableName}
 	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, nil, err
 	}
@@ -702,7 +694,7 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 	colSeq := make([]string, 0)
 	for rows.Next() {
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 
 		var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
 		var dataLen int
@@ -743,23 +735,23 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 
 		switch dt {
 		case "VARCHAR2":
-			col.SQLType = core.SQLType{core.Varchar, len1, len2}
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
 		case "NVARCHAR2":
-			col.SQLType = core.SQLType{core.NVarchar, len1, len2}
+			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2}
 		case "TIMESTAMP WITH TIME ZONE":
-			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 		case "NUMBER":
-			col.SQLType = core.SQLType{core.Double, len1, len2}
+			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2}
 		case "LONG", "LONG RAW":
-			col.SQLType = core.SQLType{core.Text, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0}
 		case "RAW":
-			col.SQLType = core.SQLType{core.Binary, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
 		case "ROWID":
-			col.SQLType = core.SQLType{core.Varchar, 18, 0}
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
 		case "AQ$_SUBSCRIBERS":
 			ignore = true
 		default:
-			col.SQLType = core.SQLType{strings.ToUpper(dt), len1, len2}
+			col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
 		}
 
 		if ignore {
@@ -767,7 +759,7 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 		}
 
 		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
-			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v %v", *dataType, col.SQLType))
+			return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
 		}
 
 		col.Length = dataLen
@@ -787,11 +779,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 func (db *oracle) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	s := "SELECT table_name FROM user_tables"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -814,11 +804,9 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
 		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -856,5 +844,56 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 }
 
 func (db *oracle) Filters() []core.Filter {
-	return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{":", 1}, &core.IdFilter{}}
+	return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}}
+}
+
+type goracleDriver struct {
+}
+
+func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.ORACLE}
+	dsnPattern := regexp.MustCompile(
+		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
+			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
+			`\/(?P<dbname>.*?)` + // /dbname
+			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	//tlsConfigRegister := make(map[string]*tls.Config)
+	names := dsnPattern.SubexpNames()
+
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			db.DbName = match
+		}
+	}
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	return db, nil
+}
+
+type oci8Driver struct {
+}
+
+//dataSourceName=user/password@ipv4:port/dbname
+//dataSourceName=user/password@[ipv6]:port/dbname
+func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.ORACLE}
+	dsnPattern := regexp.MustCompile(
+		`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
+			`(?P<net>.*)` + // ip:port
+			`\/(?P<dbname>.*)`) // dbname
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	names := dsnPattern.SubexpNames()
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			db.DbName = match
+		}
+	}
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	return db, nil
 }

+ 144 - 36
vendor/github.com/go-xorm/xorm/postgres_dialect.go → vendor/github.com/go-xorm/xorm/dialect_postgres.go

@@ -7,15 +7,14 @@ package xorm
 import (
 	"errors"
 	"fmt"
+	"net/url"
+	"sort"
 	"strconv"
 	"strings"
 
 	"github.com/go-xorm/core"
 )
 
-// func init() {
-// 	RegisterDialect("postgres", &postgres{})
-// }
 // from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
 var (
 	postgresReservedWords = map[string]bool{
@@ -787,6 +786,11 @@ func (db *postgres) SqlType(c *core.Column) string {
 			return core.Serial
 		}
 		return core.Integer
+	case core.BigInt:
+		if c.IsAutoIncrement {
+			return core.BigSerial
+		}
+		return core.BigInt
 	case core.Serial, core.BigSerial:
 		c.IsAutoIncrement = true
 		c.Nullable = false
@@ -816,8 +820,9 @@ func (db *postgres) SqlType(c *core.Column) string {
 		res = t
 	}
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
@@ -836,6 +841,7 @@ func (db *postgres) IsReserved(name string) bool {
 }
 
 func (db *postgres) Quote(name string) string {
+	name = strings.Replace(name, ".", `"."`, -1)
 	return "\"" + name + "\""
 }
 
@@ -882,9 +888,10 @@ func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
 }
 
 func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
-	quote := db.Quote
 	//var unique string
-	var idxName string = index.Name
+	quote := db.Quote
+	idxName := index.Name
+
 	if !strings.HasPrefix(idxName, "UQE_") &&
 		!strings.HasPrefix(idxName, "IDX_") {
 		if index.Type == core.UniqueType {
@@ -900,10 +907,9 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
 		" AND column_name = $2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 		return false, err
 	}
@@ -913,8 +919,8 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
 }
 
 func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
-	pgSchema := "public"
-	args := []interface{}{tableName,pgSchema}
+	// FIXME: the schema should be replaced by user custom's
+	args := []interface{}{tableName, "public"}
 	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
@@ -926,11 +932,9 @@ FROM pg_attribute f
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
     LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
 WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, nil, err
 	}
@@ -941,7 +945,7 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
 
 	for rows.Next() {
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 
 		var colName, isNullable, dataType string
 		var maxLenStr, colDefault, numPrecision, numRadix *string
@@ -978,22 +982,24 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
 
 		switch dataType {
 		case "character varying", "character":
-			col.SQLType = core.SQLType{core.Varchar, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 0, DefaultLength2: 0}
 		case "timestamp without time zone":
-			col.SQLType = core.SQLType{core.DateTime, 0, 0}
+			col.SQLType = core.SQLType{Name: core.DateTime, DefaultLength: 0, DefaultLength2: 0}
 		case "timestamp with time zone":
-			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 		case "double precision":
-			col.SQLType = core.SQLType{core.Double, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0}
 		case "boolean":
-			col.SQLType = core.SQLType{core.Bool, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Bool, DefaultLength: 0, DefaultLength2: 0}
 		case "time without time zone":
-			col.SQLType = core.SQLType{core.Time, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Time, DefaultLength: 0, DefaultLength2: 0}
+		case "oid":
+			col.SQLType = core.SQLType{Name: core.BigInt, DefaultLength: 0, DefaultLength2: 0}
 		default:
-			col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0}
+			col.SQLType = core.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
 		}
 		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
-			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
+			return nil, nil, fmt.Errorf("Unknown colType: %v", dataType)
 		}
 
 		col.Length = maxLen
@@ -1015,13 +1021,12 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
 }
 
 func (db *postgres) GetTables() ([]*core.Table, error) {
-	args := []interface{}{}
-	s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
+	// FIXME: replace public to user customrize schema
+	args := []interface{}{"public"}
+	s := fmt.Sprintf("SELECT tablename FROM pg_tables WHERE schemaname = $1")
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -1042,13 +1047,12 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
 }
 
 func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
-	args := []interface{}{tableName}
-	s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname='public' AND tablename=$1"
+	// FIXME: replace the public schema to user specify schema
+	args := []interface{}{"public", tableName}
+	s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname=$1 AND tablename=$2")
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -1076,7 +1080,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
 		colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
 
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			newIdxName := indexName[5+len(tableName) : len(indexName)]
+			newIdxName := indexName[5+len(tableName):]
 			if newIdxName != "" {
 				indexName = newIdxName
 			}
@@ -1092,5 +1096,109 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
 }
 
 func (db *postgres) Filters() []core.Filter {
-	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{"$", 1}}
+	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}}
+}
+
+type pqDriver struct {
+}
+
+type values map[string]string
+
+func (vs values) Set(k, v string) {
+	vs[k] = v
+}
+
+func (vs values) Get(k string) (v string) {
+	return vs[k]
+}
+
+func errorf(s string, args ...interface{}) {
+	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
+}
+
+func parseURL(connstr string) (string, error) {
+	u, err := url.Parse(connstr)
+	if err != nil {
+		return "", err
+	}
+
+	if u.Scheme != "postgresql" && u.Scheme != "postgres" {
+		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
+	}
+
+	var kvs []string
+	escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
+	accrue := func(k, v string) {
+		if v != "" {
+			kvs = append(kvs, k+"="+escaper.Replace(v))
+		}
+	}
+
+	if u.User != nil {
+		v := u.User.Username()
+		accrue("user", v)
+
+		v, _ = u.User.Password()
+		accrue("password", v)
+	}
+
+	i := strings.Index(u.Host, ":")
+	if i < 0 {
+		accrue("host", u.Host)
+	} else {
+		accrue("host", u.Host[:i])
+		accrue("port", u.Host[i+1:])
+	}
+
+	if u.Path != "" {
+		accrue("dbname", u.Path[1:])
+	}
+
+	q := u.Query()
+	for k := range q {
+		accrue(k, q.Get(k))
+	}
+
+	sort.Strings(kvs) // Makes testing easier (not a performance concern)
+	return strings.Join(kvs, " "), nil
+}
+
+func parseOpts(name string, o values) {
+	if len(name) == 0 {
+		return
+	}
+
+	name = strings.TrimSpace(name)
+
+	ps := strings.Split(name, " ")
+	for _, p := range ps {
+		kv := strings.Split(p, "=")
+		if len(kv) < 2 {
+			errorf("invalid option: %q", p)
+		}
+		o.Set(kv[0], kv[1])
+	}
+}
+
+func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.POSTGRES}
+	o := make(values)
+	var err error
+	if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
+		dataSourceName, err = parseURL(dataSourceName)
+		if err != nil {
+			return nil, err
+		}
+	}
+	parseOpts(dataSourceName, o)
+
+	db.DbName = o.Get("dbname")
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	/*db.Schema = o.Get("schema")
+	if len(db.Schema) == 0 {
+		db.Schema = "public"
+	}*/
+	return db, nil
 }

+ 22 - 23
vendor/github.com/go-xorm/xorm/sqlite3_dialect.go → vendor/github.com/go-xorm/xorm/dialect_sqlite3.go

@@ -237,9 +237,10 @@ func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
 }
 
 func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
-	quote := db.Quote
 	//var unique string
-	var idxName string = index.Name
+	quote := db.Quote
+	idxName := index.Name
+
 	if !strings.HasPrefix(idxName, "UQE_") &&
 		!strings.HasPrefix(idxName, "IDX_") {
 		if index.Type == core.UniqueType {
@@ -264,10 +265,8 @@ func (db *sqlite3) ForUpdateSql(query string) string {
 func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName}
 	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	db.LogSQL(query, args)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 		return false, err
 	}
@@ -282,11 +281,8 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
-
+	db.LogSQL(s, args)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, nil, err
 	}
@@ -316,15 +312,15 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 		colStr = reg.ReplaceAllString(colStr, ",")
 		fields := strings.Fields(strings.TrimSpace(colStr))
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 		col.Nullable = true
 		col.DefaultIsEmpty = true
 		for idx, field := range fields {
 			if idx == 0 {
-				col.Name = strings.Trim(field, "`[] ")
+				col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
 				continue
 			} else if idx == 1 {
-				col.SQLType = core.SQLType{field, 0, 0}
+				col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
 			}
 			switch field {
 			case "PRIMARY":
@@ -354,11 +350,9 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 func (db *sqlite3) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	s := "SELECT name FROM sqlite_master WHERE type='table'"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -382,11 +376,9 @@ func (db *sqlite3) GetTables() ([]*core.Table, error) {
 func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
+	db.LogSQL(s, args)
 
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 		return nil, err
 	}
@@ -394,16 +386,16 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
 
 	indexes := make(map[string]*core.Index, 0)
 	for rows.Next() {
-		var tmpSql sql.NullString
-		err = rows.Scan(&tmpSql)
+		var tmpSQL sql.NullString
+		err = rows.Scan(&tmpSQL)
 		if err != nil {
 			return nil, err
 		}
 
-		if !tmpSql.Valid {
+		if !tmpSQL.Valid {
 			continue
 		}
-		sql := tmpSql.String
+		sql := tmpSQL.String
 
 		index := new(core.Index)
 		nNStart := strings.Index(sql, "INDEX")
@@ -414,7 +406,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
 
 		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			index.Name = indexName[5+len(tableName) : len(indexName)]
+			index.Name = indexName[5+len(tableName):]
 		} else {
 			index.Name = indexName
 		}
@@ -442,3 +434,10 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
 func (db *sqlite3) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}}
 }
+
+type sqlite3Driver struct {
+}
+
+func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
+}

+ 42 - 21
vendor/github.com/go-xorm/xorm/doc.go

@@ -1,4 +1,4 @@
-// Copyright 2013 - 2015 The Xorm Authors. All rights reserved.
+// Copyright 2013 - 2016 The XORM Authors. All rights reserved.
 // Use of this source code is governed by a BSD
 // license that can be found in the LICENSE file.
 
@@ -24,7 +24,7 @@ Generally, one engine for an application is enough. You can set it as package va
 
 Raw Methods
 
-Xorm also support raw sql execution:
+XORM also support raw SQL execution:
 
 1. query a SQL string, the returned results is []map[string][]byte
 
@@ -36,9 +36,9 @@ Xorm also support raw sql execution:
 
 ORM Methods
 
-There are 7 major ORM methods and many helpful methods to use to operate database.
+There are 8 major ORM methods and many helpful methods to use to operate database.
 
-1. Insert one or multipe records to database
+1. Insert one or multiple records to database
 
     affected, err := engine.Insert(&struct)
     // INSERT INTO struct () values ()
@@ -58,10 +58,18 @@ There are 7 major ORM methods and many helpful methods to use to operate databas
 
 3. Query multiple records from database
 
-    sliceOfStructs := new(Struct)
-    err := engine.Find(sliceOfStructs)
+    var sliceOfStructs []Struct
+    err := engine.Find(&sliceOfStructs)
     // SELECT * FROM user
 
+    var mapOfStructs = make(map[int64]Struct)
+    err := engine.Find(&mapOfStructs)
+    // SELECT * FROM user
+
+    var int64s []int64
+    err := engine.Table("user").Cols("id").Find(&int64s)
+    // SELECT id FROM user
+
 4. Query multiple records and record by record handle, there two methods, one is Iterate,
 another is Rows
 
@@ -81,7 +89,7 @@ another is Rows
     affected, err := engine.Id(...).Update(&user)
     // UPDATE user SET ...
 
-6. Delete one or more records, Delete MUST has conditon
+6. Delete one or more records, Delete MUST has condition
 
     affected, err := engine.Where(...).Delete(&user)
     // DELETE FROM user Where ...
@@ -91,20 +99,31 @@ another is Rows
     counts, err := engine.Count(&user)
     // SELECT count(*) AS total FROM user
 
+8. Sum records
+
+    sumFloat64, err := engine.Sum(&user, "id")
+    // SELECT sum(id) from user
+
+    sumFloat64s, err := engine.Sums(&user, "id1", "id2")
+    // SELECT sum(id1), sum(id2) from user
+
+    sumInt64s, err := engine.SumsInt(&user, "id1", "id2")
+    // SELECT sum(id1), sum(id2) from user
+
 Conditions
 
-The above 7 methods could use with condition methods chainable.
-Attention: the above 7 methods should be the last chainable method.
+The above 8 methods could use with condition methods chainable.
+Attention: the above 8 methods should be the last chainable method.
 
-1. Id, In
+1. ID, In
 
-    engine.Id(1).Get(&user) // for single primary key
+    engine.ID(1).Get(&user) // for single primary key
     // SELECT * FROM user WHERE id = 1
-    engine.Id(core.PK{1, 2}).Get(&user) // for composite primary keys
+    engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
     // SELECT * FROM user WHERE id1 = 1 AND id2 = 2
     engine.In("id", 1, 2, 3).Find(&users)
     // SELECT * FROM user WHERE id IN (1, 2, 3)
-    engine.In("id", []int{1, 2, 3})
+    engine.In("id", []int{1, 2, 3}).Find(&users)
     // SELECT * FROM user WHERE id IN (1, 2, 3)
 
 2. Where, And, Or
@@ -127,28 +146,30 @@ Attention: the above 7 methods should be the last chainable method.
     // SELECT TOP 5 * FROM user // for mssql
     // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases
 
-5. Sql, let you custom SQL
+5. SQL, let you custom SQL
 
-    engine.Sql("select * from user").Find()
+    var users []User
+    engine.SQL("select * from user").Find(&users)
 
 6. Cols, Omit, Distinct
 
-    engine.Cols("col1, col2").Find()
+    var users []*User
+    engine.Cols("col1, col2").Find(&users)
     // SELECT col1, col2 FROM user
     engine.Cols("col1", "col2").Where().Update(user)
     // UPDATE user set col1 = ?, col2 = ? Where ...
-    engine.Omit("col1").Find()
+    engine.Omit("col1").Find(&users)
     // SELECT col2, col3 FROM user
-    engine.Omit("col1").Insert()
+    engine.Omit("col1").Insert(&user)
     // INSERT INTO table (non-col1) VALUES ()
-    engine.Distinct("col1").Find()
+    engine.Distinct("col1").Find(&users)
     // SELECT DISTINCT col1 FROM user
 
 7. Join, GroupBy, Having
 
-    engine.GroupBy("name").Having("name='xlw'").Find()
+    engine.GroupBy("name").Having("name='xlw'").Find(&users)
     //SELECT * FROM user GROUP BY name HAVING name='xlw'
-    engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find()
+    engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find(&users)
     //SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
 
 More usage, please visit http://xorm.io/docs

文件差异内容过多而无法显示
+ 379 - 348
vendor/github.com/go-xorm/xorm/engine.go


+ 14 - 7
vendor/github.com/go-xorm/xorm/error.go

@@ -9,11 +9,18 @@ import (
 )
 
 var (
-	ErrParamsType      error = errors.New("Params type error")
-	ErrTableNotFound   error = errors.New("Not found table")
-	ErrUnSupportedType error = errors.New("Unsupported type error")
-	ErrNotExist        error = errors.New("Not exist error")
-	ErrCacheFailed     error = errors.New("Cache failed")
-	ErrNeedDeletedCond error = errors.New("Delete need at least one condition")
-	ErrNotImplemented  error = errors.New("Not implemented.")
+	// ErrParamsType params error
+	ErrParamsType = errors.New("Params type error")
+	// ErrTableNotFound table not found error
+	ErrTableNotFound = errors.New("Not found table")
+	// ErrUnSupportedType unsupported error
+	ErrUnSupportedType = errors.New("Unsupported type error")
+	// ErrNotExist record is not exist error
+	ErrNotExist = errors.New("Not exist error")
+	// 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")
+	// ErrNotImplemented not implemented
+	ErrNotImplemented = errors.New("Not implemented")
 )

+ 0 - 0
vendor/github.com/go-xorm/xorm/gen_reserved.sh


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

@@ -1,42 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"errors"
-	"regexp"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("goracle", &goracleDriver{})
-// }
-
-type goracleDriver struct {
-}
-
-func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	db := &core.Uri{DbType: core.ORACLE}
-	dsnPattern := regexp.MustCompile(
-		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
-			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
-			`\/(?P<dbname>.*?)` + // /dbname
-			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
-	matches := dsnPattern.FindStringSubmatch(dataSourceName)
-	//tlsConfigRegister := make(map[string]*tls.Config)
-	names := dsnPattern.SubexpNames()
-
-	for i, match := range matches {
-		switch names[i] {
-		case "dbname":
-			db.DbName = match
-		}
-	}
-	if db.DbName == "" {
-		return nil, errors.New("dbname is empty")
-	}
-	return db, nil
-}

+ 192 - 20
vendor/github.com/go-xorm/xorm/helpers.go

@@ -5,6 +5,7 @@
 package xorm
 
 import (
+	"errors"
 	"fmt"
 	"reflect"
 	"sort"
@@ -15,6 +16,86 @@ import (
 	"github.com/go-xorm/core"
 )
 
+// str2PK convert string value to primary key value according to tp
+func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
+	var err error
+	var result interface{}
+	var defReturn = reflect.Zero(tp)
+
+	switch tp.Kind() {
+	case reflect.Int:
+		result, err = strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
+		}
+	case reflect.Int8:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
+		}
+		result = int8(x)
+	case reflect.Int16:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
+		}
+		result = int16(x)
+	case reflect.Int32:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
+		}
+		result = int32(x)
+	case reflect.Int64:
+		result, err = strconv.ParseInt(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
+		}
+	case reflect.Uint:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
+		}
+		result = uint(x)
+	case reflect.Uint8:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
+		}
+		result = uint8(x)
+	case reflect.Uint16:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
+		}
+		result = uint16(x)
+	case reflect.Uint32:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
+		}
+		result = uint32(x)
+	case reflect.Uint64:
+		result, err = strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
+		}
+	case reflect.String:
+		result = s
+	default:
+		return defReturn, errors.New("unsupported convert type")
+	}
+	return reflect.ValueOf(result).Convert(tp), nil
+}
+
+func str2PK(s string, tp reflect.Type) (interface{}, error) {
+	v, err := str2PKValue(s, tp)
+	if err != nil {
+		return nil, err
+	}
+	return v.Interface(), nil
+}
+
 func splitTag(tag string) (tags []string) {
 	tag = strings.TrimSpace(tag)
 	var hasQuote = false
@@ -30,7 +111,7 @@ func splitTag(tag string) (tags []string) {
 		}
 	}
 	if lastIdx < len(tag) {
-		tags = append(tags, strings.TrimSpace(tag[lastIdx:len(tag)]))
+		tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
 	}
 	return
 }
@@ -75,15 +156,55 @@ func isZero(k interface{}) bool {
 	return false
 }
 
-func int64ToInt(id int64, k reflect.Kind) interface{} {
-	var v interface{} = id
-	switch k {
+func isStructZero(v reflect.Value) bool {
+	if !v.IsValid() {
+		return true
+	}
+
+	for i := 0; i < v.NumField(); i++ {
+		field := v.Field(i)
+		switch field.Kind() {
+		case reflect.Ptr:
+			field = field.Elem()
+			fallthrough
+		case reflect.Struct:
+			if !isStructZero(field) {
+				return false
+			}
+		default:
+			if field.CanInterface() && !isZero(field.Interface()) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+func isArrayValueZero(v reflect.Value) bool {
+	if !v.IsValid() || v.Len() == 0 {
+		return true
+	}
+
+	for i := 0; i < v.Len(); i++ {
+		if !isZero(v.Index(i).Interface()) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
+	var v interface{}
+	switch tp.Kind() {
 	case reflect.Int16:
 		v = int16(id)
 	case reflect.Int32:
 		v = int32(id)
 	case reflect.Int:
 		v = int(id)
+	case reflect.Int64:
+		v = id
 	case reflect.Uint16:
 		v = uint16(id)
 	case reflect.Uint32:
@@ -93,7 +214,11 @@ func int64ToInt(id int64, k reflect.Kind) interface{} {
 	case reflect.Uint:
 		v = uint(id)
 	}
-	return v
+	return reflect.ValueOf(v).Convert(tp)
+}
+
+func int64ToInt(id int64, tp reflect.Type) interface{} {
+	return int64ToIntValue(id, tp).Interface()
 }
 
 func isPKZero(pk core.PK) bool {
@@ -105,10 +230,6 @@ func isPKZero(pk core.PK) bool {
 	return false
 }
 
-func equalNoCase(s1, s2 string) bool {
-	return strings.ToLower(s1) == strings.ToLower(s2)
-}
-
 func indexNoCase(s, sep string) int {
 	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 }
@@ -154,6 +275,19 @@ 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
@@ -188,7 +322,7 @@ func reflect2value(rawValue *reflect.Value) (str string, err error) {
 		default:
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 		}
-	//时间类型
+	// time type
 	case reflect.Struct:
 		if aa.ConvertibleTo(core.TimeType) {
 			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
@@ -342,6 +476,21 @@ func query2(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []m
 	return rows2Strings(rows)
 }
 
+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 {
@@ -360,13 +509,12 @@ func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
 }
 
 func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
-	colNames := make([]string, 0)
-	args := make([]interface{}, 0)
+	colNames := make([]string, 0, len(table.ColumnsSeq()))
+	args := make([]interface{}, 0, len(table.ColumnsSeq()))
 
 	for _, col := range table.Columns() {
-		lColName := strings.ToLower(col.Name)
 		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
-			if _, ok := session.Statement.columnMap[lColName]; !ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
 				continue
 			}
 		}
@@ -376,8 +524,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
-			session.Engine.LogError(err)
-			continue
+			return nil, nil, err
 		}
 		fieldValue := *fieldValuePtr
 
@@ -403,25 +550,26 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 		}
 
 		if session.Statement.ColumnStr != "" {
-			if _, ok := session.Statement.columnMap[lColName]; !ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
 				continue
 			}
 		}
 		if session.Statement.OmitStr != "" {
-			if _, ok := session.Statement.columnMap[lColName]; ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok {
 				continue
 			}
 		}
 
 		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
-		if _, ok := session.Statement.nullableMap[lColName]; ok {
+		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 {
+		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.NowTime2(col.SQLType.Name)
 			args = append(args, val)
 
@@ -448,3 +596,27 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 	}
 	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
+}

+ 0 - 22
vendor/github.com/go-xorm/xorm/helpers_test.go

@@ -1,22 +0,0 @@
-package xorm
-
-import "testing"
-
-func TestSplitTag(t *testing.T) {
-	var cases = []struct {
-		tag  string
-		tags []string
-	}{
-		{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
-		{"TEXT", []string{"TEXT"}},
-		{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
-		{"json  binary", []string{"json", "binary"}},
-	}
-
-	for _, kase := range cases {
-		tags := splitTag(kase.tag)
-		if !sliceEq(tags, kase.tags) {
-			t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
-		}
-	}
-}

+ 107 - 30
vendor/github.com/go-xorm/xorm/logger.go

@@ -12,28 +12,81 @@ import (
 	"github.com/go-xorm/core"
 )
 
+// default log options
 const (
 	DEFAULT_LOG_PREFIX = "[xorm]"
 	DEFAULT_LOG_FLAG   = log.Ldate | log.Lmicroseconds
 	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
 )
 
+var _ core.ILogger = DiscardLogger{}
+
+// DiscardLogger don't log implementation for core.ILogger
+type DiscardLogger struct{}
+
+// Debug empty implementation
+func (DiscardLogger) Debug(v ...interface{}) {}
+
+// Debugf empty implementation
+func (DiscardLogger) Debugf(format string, v ...interface{}) {}
+
+// Error empty implementation
+func (DiscardLogger) Error(v ...interface{}) {}
+
+// Errorf empty implementation
+func (DiscardLogger) Errorf(format string, v ...interface{}) {}
+
+// Info empty implementation
+func (DiscardLogger) Info(v ...interface{}) {}
+
+// Infof empty implementation
+func (DiscardLogger) Infof(format string, v ...interface{}) {}
+
+// Warn empty implementation
+func (DiscardLogger) Warn(v ...interface{}) {}
+
+// Warnf empty implementation
+func (DiscardLogger) Warnf(format string, v ...interface{}) {}
+
+// Level empty implementation
+func (DiscardLogger) Level() core.LogLevel {
+	return core.LOG_UNKNOWN
+}
+
+// SetLevel empty implementation
+func (DiscardLogger) SetLevel(l core.LogLevel) {}
+
+// ShowSQL empty implementation
+func (DiscardLogger) ShowSQL(show ...bool) {}
+
+// IsShowSQL empty implementation
+func (DiscardLogger) IsShowSQL() bool {
+	return false
+}
+
+// SimpleLogger is the default implment of core.ILogger
 type SimpleLogger struct {
-	DEBUG *log.Logger
-	ERR   *log.Logger
-	INFO  *log.Logger
-	WARN  *log.Logger
-	level core.LogLevel
+	DEBUG   *log.Logger
+	ERR     *log.Logger
+	INFO    *log.Logger
+	WARN    *log.Logger
+	level   core.LogLevel
+	showSQL bool
 }
 
+var _ core.ILogger = &SimpleLogger{}
+
+// NewSimpleLogger use a special io.Writer as logger output
 func NewSimpleLogger(out io.Writer) *SimpleLogger {
 	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
 }
 
+// NewSimpleLogger2 let you customrize your logger prefix and flag
 func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
 	return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
 }
 
+// NewSimpleLogger3 let you customrize your logger prefix and flag and logLevel
 func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
 	return &SimpleLogger{
 		DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
@@ -44,67 +97,91 @@ func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *
 	}
 }
 
-func (s *SimpleLogger) Err(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
-		s.ERR.Println(v...)
+// Error implement core.ILogger
+func (s *SimpleLogger) Error(v ...interface{}) {
+	if s.level <= core.LOG_ERR {
+		s.ERR.Output(2, fmt.Sprint(v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Errf(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
-		s.ERR.Printf(format, v...)
+// Errorf implement core.ILogger
+func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
+	if s.level <= core.LOG_ERR {
+		s.ERR.Output(2, fmt.Sprintf(format, v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Debug(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_DEBUG {
-		s.DEBUG.Println(v...)
+// Debug implement core.ILogger
+func (s *SimpleLogger) Debug(v ...interface{}) {
+	if s.level <= core.LOG_DEBUG {
+		s.DEBUG.Output(2, fmt.Sprint(v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Debugf(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_DEBUG {
-		s.DEBUG.Printf(format, v...)
+// Debugf implement core.ILogger
+func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
+	if s.level <= core.LOG_DEBUG {
+		s.DEBUG.Output(2, fmt.Sprintf(format, v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Info(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
-		s.INFO.Println(v...)
+// Info implement core.ILogger
+func (s *SimpleLogger) Info(v ...interface{}) {
+	if s.level <= core.LOG_INFO {
+		s.INFO.Output(2, fmt.Sprint(v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Infof(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
-		s.INFO.Printf(format, v...)
+// Infof implement core.ILogger
+func (s *SimpleLogger) Infof(format string, v ...interface{}) {
+	if s.level <= core.LOG_INFO {
+		s.INFO.Output(2, fmt.Sprintf(format, v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Warning(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
-		s.WARN.Println(v...)
+// Warn implement core.ILogger
+func (s *SimpleLogger) Warn(v ...interface{}) {
+	if s.level <= core.LOG_WARNING {
+		s.WARN.Output(2, fmt.Sprint(v...))
 	}
 	return
 }
 
-func (s *SimpleLogger) Warningf(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
-		s.WARN.Printf(format, v...)
+// Warnf implement core.ILogger
+func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
+	if s.level <= core.LOG_WARNING {
+		s.WARN.Output(2, fmt.Sprintf(format, v...))
 	}
 	return
 }
 
+// Level implement core.ILogger
 func (s *SimpleLogger) Level() core.LogLevel {
 	return s.level
 }
 
-func (s *SimpleLogger) SetLevel(l core.LogLevel) (err error) {
+// SetLevel implement core.ILogger
+func (s *SimpleLogger) SetLevel(l core.LogLevel) {
 	s.level = l
 	return
 }
+
+// ShowSQL implement core.ILogger
+func (s *SimpleLogger) ShowSQL(show ...bool) {
+	if len(show) == 0 {
+		s.showSQL = true
+		return
+	}
+	s.showSQL = show[0]
+}
+
+// IsShowSQL implement core.ILogger
+func (s *SimpleLogger) IsShowSQL() bool {
+	return s.showSQL
+}

+ 31 - 26
vendor/github.com/go-xorm/xorm/lru_cacher.go

@@ -13,6 +13,7 @@ import (
 	"github.com/go-xorm/core"
 )
 
+// LRUCacher implments cache object facilities
 type LRUCacher struct {
 	idList   *list.List
 	sqlList  *list.List
@@ -26,10 +27,12 @@ type LRUCacher struct {
 	GcInterval     time.Duration
 }
 
+// NewLRUCacher creates a cacher
 func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
 	return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
 }
 
+// NewLRUCacher2 creates a cache include different params
 func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
 	cacher := &LRUCacher{store: store, idList: list.New(),
 		sqlList: list.New(), Expired: expired,
@@ -41,10 +44,6 @@ func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize
 	return cacher
 }
 
-//func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
-//    return newLRUCacher(store, expired, maxSize, 0)
-//}
-
 // RunGC run once every m.GcInterval
 func (m *LRUCacher) RunGC() {
 	time.AfterFunc(m.GcInterval, func() {
@@ -92,7 +91,7 @@ func (m *LRUCacher) GC() {
 	}
 }
 
-// Get all bean's ids according to sql and parameter from cache
+// GetIds returns all bean's ids according to sql and parameter from cache
 func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -101,7 +100,7 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 	}
 	if v, err := m.store.Get(sql); err == nil {
 		if el, ok := m.sqlIndex[tableName][sql]; !ok {
-			el = m.sqlList.PushBack(newSqlNode(tableName, sql))
+			el = m.sqlList.PushBack(newSQLNode(tableName, sql))
 			m.sqlIndex[tableName][sql] = el
 		} else {
 			lastTime := el.Value.(*sqlNode).lastVisit
@@ -114,21 +113,21 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 			el.Value.(*sqlNode).lastVisit = time.Now()
 		}
 		return v
-	} else {
-		m.delIds(tableName, sql)
 	}
 
+	m.delIds(tableName, sql)
+
 	return nil
 }
 
-// Get bean according tableName and id from cache
+// GetBean returns bean according tableName and id from cache
 func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	if _, ok := m.idIndex[tableName]; !ok {
 		m.idIndex[tableName] = make(map[string]*list.Element)
 	}
-	tid := genId(tableName, id)
+	tid := genID(tableName, id)
 	if v, err := m.store.Get(tid); err == nil {
 		if el, ok := m.idIndex[tableName][id]; ok {
 			lastTime := el.Value.(*idNode).lastVisit
@@ -141,19 +140,19 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
 			m.idList.MoveToBack(el)
 			el.Value.(*idNode).lastVisit = time.Now()
 		} else {
-			el = m.idList.PushBack(newIdNode(tableName, id))
+			el = m.idList.PushBack(newIDNode(tableName, id))
 			m.idIndex[tableName][id] = el
 		}
 		return v
-	} else {
-		// store bean is not exist, then remove memory's index
-		m.delBean(tableName, id)
-		//m.clearIds(tableName)
-		return nil
 	}
+
+	// store bean is not exist, then remove memory's index
+	m.delBean(tableName, id)
+	//m.clearIds(tableName)
+	return nil
 }
 
-// Clear all sql-ids mapping on table tableName from cache
+// clearIds clears all sql-ids mapping on table tableName from cache
 func (m *LRUCacher) clearIds(tableName string) {
 	if tis, ok := m.sqlIndex[tableName]; ok {
 		for sql, v := range tis {
@@ -164,6 +163,7 @@ func (m *LRUCacher) clearIds(tableName string) {
 	m.sqlIndex[tableName] = make(map[string]*list.Element)
 }
 
+// ClearIds clears all sql-ids mapping on table tableName from cache
 func (m *LRUCacher) ClearIds(tableName string) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -174,19 +174,21 @@ func (m *LRUCacher) clearBeans(tableName string) {
 	if tis, ok := m.idIndex[tableName]; ok {
 		for id, v := range tis {
 			m.idList.Remove(v)
-			tid := genId(tableName, id)
+			tid := genID(tableName, id)
 			m.store.Del(tid)
 		}
 	}
 	m.idIndex[tableName] = make(map[string]*list.Element)
 }
 
+// ClearBeans clears all beans in some table
 func (m *LRUCacher) ClearBeans(tableName string) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	m.clearBeans(tableName)
 }
 
+// PutIds pus ids into table
 func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -194,7 +196,7 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 		m.sqlIndex[tableName] = make(map[string]*list.Element)
 	}
 	if el, ok := m.sqlIndex[tableName][sql]; !ok {
-		el = m.sqlList.PushBack(newSqlNode(tableName, sql))
+		el = m.sqlList.PushBack(newSQLNode(tableName, sql))
 		m.sqlIndex[tableName][sql] = el
 	} else {
 		el.Value.(*sqlNode).lastVisit = time.Now()
@@ -207,6 +209,7 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 	}
 }
 
+// PutBean puts beans into table
 func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -214,13 +217,13 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
 	var ok bool
 
 	if el, ok = m.idIndex[tableName][id]; !ok {
-		el = m.idList.PushBack(newIdNode(tableName, id))
+		el = m.idList.PushBack(newIDNode(tableName, id))
 		m.idIndex[tableName][id] = el
 	} else {
 		el.Value.(*idNode).lastVisit = time.Now()
 	}
 
-	m.store.Put(genId(tableName, id), obj)
+	m.store.Put(genID(tableName, id), obj)
 	if m.idList.Len() > m.MaxElementSize {
 		e := m.idList.Front()
 		node := e.Value.(*idNode)
@@ -238,6 +241,7 @@ func (m *LRUCacher) delIds(tableName, sql string) {
 	m.store.Del(sql)
 }
 
+// DelIds deletes ids
 func (m *LRUCacher) DelIds(tableName, sql string) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -245,7 +249,7 @@ func (m *LRUCacher) DelIds(tableName, sql string) {
 }
 
 func (m *LRUCacher) delBean(tableName string, id string) {
-	tid := genId(tableName, id)
+	tid := genID(tableName, id)
 	if el, ok := m.idIndex[tableName][id]; ok {
 		delete(m.idIndex[tableName], id)
 		m.idList.Remove(el)
@@ -254,6 +258,7 @@ func (m *LRUCacher) delBean(tableName string, id string) {
 	m.store.Del(tid)
 }
 
+// DelBean deletes beans in some table
 func (m *LRUCacher) DelBean(tableName string, id string) {
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
@@ -272,18 +277,18 @@ type sqlNode struct {
 	lastVisit time.Time
 }
 
-func genSqlKey(sql string, args interface{}) string {
+func genSQLKey(sql string, args interface{}) string {
 	return fmt.Sprintf("%v-%v", sql, args)
 }
 
-func genId(prefix string, id string) string {
+func genID(prefix string, id string) string {
 	return fmt.Sprintf("%v-%v", prefix, id)
 }
 
-func newIdNode(tbName string, id string) *idNode {
+func newIDNode(tbName string, id string) *idNode {
 	return &idNode{tbName, id, time.Now()}
 }
 
-func newSqlNode(tbName, sql string) *sqlNode {
+func newSQLNode(tbName, sql string) *sqlNode {
 	return &sqlNode{tbName, sql, time.Now()}
 }

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

@@ -12,16 +12,18 @@ import (
 
 var _ core.CacheStore = NewMemoryStore()
 
-// memory store
+// MemoryStore represents in-memory store
 type MemoryStore struct {
 	store map[interface{}]interface{}
 	mutex sync.RWMutex
 }
 
+// NewMemoryStore creates a new store in memory
 func NewMemoryStore() *MemoryStore {
 	return &MemoryStore{store: make(map[interface{}]interface{})}
 }
 
+// Put puts object into store
 func (s *MemoryStore) Put(key string, value interface{}) error {
 	s.mutex.Lock()
 	defer s.mutex.Unlock()
@@ -29,6 +31,7 @@ func (s *MemoryStore) Put(key string, value interface{}) error {
 	return nil
 }
 
+// Get gets object from store
 func (s *MemoryStore) Get(key string) (interface{}, error) {
 	s.mutex.RLock()
 	defer s.mutex.RUnlock()
@@ -39,6 +42,7 @@ func (s *MemoryStore) Get(key string) (interface{}, error) {
 	return nil, ErrNotExist
 }
 
+// Del deletes object
 func (s *MemoryStore) Del(key string) error {
 	s.mutex.Lock()
 	defer s.mutex.Unlock()

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

@@ -1,69 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"errors"
-	"strings"
-	"time"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("mymysql", &mymysqlDriver{})
-// }
-
-type mymysqlDriver struct {
-}
-
-func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	db := &core.Uri{DbType: core.MYSQL}
-
-	pd := strings.SplitN(dataSourceName, "*", 2)
-	if len(pd) == 2 {
-		// Parse protocol part of URI
-		p := strings.SplitN(pd[0], ":", 2)
-		if len(p) != 2 {
-			return nil, errors.New("Wrong protocol part of URI")
-		}
-		db.Proto = p[0]
-		options := strings.Split(p[1], ",")
-		db.Raddr = options[0]
-		for _, o := range options[1:] {
-			kv := strings.SplitN(o, "=", 2)
-			var k, v string
-			if len(kv) == 2 {
-				k, v = kv[0], kv[1]
-			} else {
-				k, v = o, "true"
-			}
-			switch k {
-			case "laddr":
-				db.Laddr = v
-			case "timeout":
-				to, err := time.ParseDuration(v)
-				if err != nil {
-					return nil, err
-				}
-				db.Timeout = to
-			default:
-				return nil, errors.New("Unknown option: " + k)
-			}
-		}
-		// Remove protocol part
-		pd = pd[1:]
-	}
-	// Parse database part of URI
-	dup := strings.SplitN(pd[0], "/", 3)
-	if len(dup) != 3 {
-		return nil, errors.New("Wrong database part of URI")
-	}
-	db.DbName = dup[0]
-	db.User = dup[1]
-	db.Passwd = dup[2]
-
-	return db, nil
-}

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

@@ -1,54 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"regexp"
-	"strings"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("mysql", &mysqlDriver{})
-// }
-
-type mysqlDriver struct {
-}
-
-func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	dsnPattern := regexp.MustCompile(
-		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
-			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
-			`\/(?P<dbname>.*?)` + // /dbname
-			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
-	matches := dsnPattern.FindStringSubmatch(dataSourceName)
-	//tlsConfigRegister := make(map[string]*tls.Config)
-	names := dsnPattern.SubexpNames()
-
-	uri := &core.Uri{DbType: core.MYSQL}
-
-	for i, match := range matches {
-		switch names[i] {
-		case "dbname":
-			uri.DbName = match
-		case "params":
-			if len(match) > 0 {
-				kvs := strings.Split(match, "&")
-				for _, kv := range kvs {
-					splits := strings.Split(kv, "=")
-					if len(splits) == 2 {
-						switch splits[0] {
-						case "charset":
-							uri.Charset = splits[1]
-						}
-					}
-				}
-			}
-
-		}
-	}
-	return uri, nil
-}

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

@@ -1,41 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"errors"
-	"regexp"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("oci8", &oci8Driver{})
-// }
-
-type oci8Driver struct {
-}
-
-//dataSourceName=user/password@ipv4:port/dbname
-//dataSourceName=user/password@[ipv6]:port/dbname
-func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	db := &core.Uri{DbType: core.ORACLE}
-	dsnPattern := regexp.MustCompile(
-		`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
-			`(?P<net>.*)` + // ip:port
-			`\/(?P<dbname>.*)`) // dbname
-	matches := dsnPattern.FindStringSubmatch(dataSourceName)
-	names := dsnPattern.SubexpNames()
-	for i, match := range matches {
-		switch names[i] {
-		case "dbname":
-			db.DbName = match
-		}
-	}
-	if db.DbName == "" {
-		return nil, errors.New("dbname is empty")
-	}
-	return db, nil
-}

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

@@ -1,38 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"errors"
-	"strings"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("odbc", &odbcDriver{})
-// }
-
-type odbcDriver struct {
-}
-
-func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	kv := strings.Split(dataSourceName, ";")
-	var dbName string
-
-	for _, c := range kv {
-		vv := strings.Split(strings.TrimSpace(c), "=")
-		if len(vv) == 2 {
-			switch strings.ToLower(vv[0]) {
-			case "database":
-				dbName = vv[1]
-			}
-		}
-	}
-	if dbName == "" {
-		return nil, errors.New("no db name provided")
-	}
-	return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
-}

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

@@ -1,119 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"errors"
-	"fmt"
-	"net/url"
-	"sort"
-	"strings"
-
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("postgres", &pqDriver{})
-// }
-
-type pqDriver struct {
-}
-
-type values map[string]string
-
-func (vs values) Set(k, v string) {
-	vs[k] = v
-}
-
-func (vs values) Get(k string) (v string) {
-	return vs[k]
-}
-
-func errorf(s string, args ...interface{}) {
-	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
-}
-
-func parseURL(connstr string) (string, error) {
-	u, err := url.Parse(connstr)
-	if err != nil {
-		return "", err
-	}
-
-	if u.Scheme != "postgresql" && u.Scheme != "postgres" {
-		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
-	}
-
-	var kvs []string
-	escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
-	accrue := func(k, v string) {
-		if v != "" {
-			kvs = append(kvs, k+"="+escaper.Replace(v))
-		}
-	}
-
-	if u.User != nil {
-		v := u.User.Username()
-		accrue("user", v)
-
-		v, _ = u.User.Password()
-		accrue("password", v)
-	}
-
-	i := strings.Index(u.Host, ":")
-	if i < 0 {
-		accrue("host", u.Host)
-	} else {
-		accrue("host", u.Host[:i])
-		accrue("port", u.Host[i+1:])
-	}
-
-	if u.Path != "" {
-		accrue("dbname", u.Path[1:])
-	}
-
-	q := u.Query()
-	for k := range q {
-		accrue(k, q.Get(k))
-	}
-
-	sort.Strings(kvs) // Makes testing easier (not a performance concern)
-	return strings.Join(kvs, " "), nil
-}
-
-func parseOpts(name string, o values) {
-	if len(name) == 0 {
-		return
-	}
-
-	name = strings.TrimSpace(name)
-
-	ps := strings.Split(name, " ")
-	for _, p := range ps {
-		kv := strings.Split(p, "=")
-		if len(kv) < 2 {
-			errorf("invalid option: %q", p)
-		}
-		o.Set(kv[0], kv[1])
-	}
-}
-
-func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	db := &core.Uri{DbType: core.POSTGRES}
-	o := make(values)
-	var err error
-	if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
-		dataSourceName, err = parseURL(dataSourceName)
-		if err != nil {
-			return nil, err
-		}
-	}
-	parseOpts(dataSourceName, o)
-
-	db.DbName = o.Get("dbname")
-	if db.DbName == "" {
-		return nil, errors.New("dbname is empty")
-	}
-	return db, nil
-}

+ 8 - 6
vendor/github.com/go-xorm/xorm/processors.go

@@ -4,25 +4,27 @@
 
 package xorm
 
-// Executed before an object is initially persisted to the database
+// BeforeInsertProcessor executed before an object is initially persisted to the database
 type BeforeInsertProcessor interface {
 	BeforeInsert()
 }
 
-// Executed before an object is updated
+// BeforeUpdateProcessor executed before an object is updated
 type BeforeUpdateProcessor interface {
 	BeforeUpdate()
 }
 
-// Executed before an object is deleted
+// BeforeDeleteProcessor executed before an object is deleted
 type BeforeDeleteProcessor interface {
 	BeforeDelete()
 }
 
+// BeforeSetProcessor executed before data set to the struct fields
 type BeforeSetProcessor interface {
 	BeforeSet(string, Cell)
 }
 
+// AfterSetProcessor executed after data set to the struct fields
 type AfterSetProcessor interface {
 	AfterSet(string, Cell)
 }
@@ -34,17 +36,17 @@ type AfterSetProcessor interface {
 //}
 // --
 
-// Executed after an object is persisted to the database
+// AfterInsertProcessor executed after an object is persisted to the database
 type AfterInsertProcessor interface {
 	AfterInsert()
 }
 
-// Executed after an object has been updated
+// AfterUpdateProcessor executed after an object has been updated
 type AfterUpdateProcessor interface {
 	AfterUpdate()
 }
 
-// Executed after an object has been deleted
+// AfterDeleteProcessor executed after an object has been deleted
 type AfterDeleteProcessor interface {
 	AfterDelete()
 }

+ 44 - 41
vendor/github.com/go-xorm/xorm/rows.go

@@ -12,16 +12,16 @@ import (
 	"github.com/go-xorm/core"
 )
 
+// Rows rows wrapper a rows to
 type Rows struct {
 	NoTypeCheck bool
 
-	session     *Session
-	stmt        *core.Stmt
-	rows        *core.Rows
-	fields      []string
-	fieldsCount int
-	beanType    reflect.Type
-	lastError   error
+	session   *Session
+	stmt      *core.Stmt
+	rows      *core.Rows
+	fields    []string
+	beanType  reflect.Type
+	lastError error
 }
 
 func newRows(session *Session, bean interface{}) (*Rows, error) {
@@ -29,13 +29,18 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 	rows.session = session
 	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
 
-	defer rows.session.Statement.Init()
+	defer rows.session.resetStatement()
 
 	var sqlStr string
 	var args []interface{}
-	rows.session.Statement.RefTable = rows.session.Engine.TableInfo(bean)
+
+	rows.session.Statement.setRefValue(rValue(bean))
+	if len(session.Statement.TableName()) <= 0 {
+		return nil, ErrTableNotFound
+	}
+
 	if rows.session.Statement.RawSQL == "" {
-		sqlStr, args = rows.session.Statement.genGetSql(bean)
+		sqlStr, args = rows.session.Statement.genGetSQL(bean)
 	} else {
 		sqlStr = rows.session.Statement.RawSQL
 		args = rows.session.Statement.RawParams
@@ -45,34 +50,42 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 		sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
 	}
 
-	rows.session.saveLastSQL(sqlStr, args)
+	rows.session.saveLastSQL(sqlStr, args...)
 	var err error
-	rows.stmt, err = rows.session.DB().Prepare(sqlStr)
-	if err != nil {
-		rows.lastError = err
-		defer rows.Close()
-		return nil, err
-	}
+	if rows.session.prepareStmt {
+		rows.stmt, err = rows.session.DB().Prepare(sqlStr)
+		if err != nil {
+			rows.lastError = err
+			rows.Close()
+			return nil, err
+		}
 
-	rows.rows, err = rows.stmt.Query(args...)
-	if err != nil {
-		rows.lastError = err
-		defer rows.Close()
-		return nil, err
+		rows.rows, err = rows.stmt.Query(args...)
+		if err != nil {
+			rows.lastError = err
+			rows.Close()
+			return nil, err
+		}
+	} else {
+		rows.rows, err = rows.session.DB().Query(sqlStr, args...)
+		if err != nil {
+			rows.lastError = err
+			rows.Close()
+			return nil, err
+		}
 	}
 
 	rows.fields, err = rows.rows.Columns()
 	if err != nil {
 		rows.lastError = err
-		defer rows.Close()
+		rows.Close()
 		return nil, err
 	}
-	rows.fieldsCount = len(rows.fields)
 
 	return rows, nil
 }
 
-// move cursor to next record, return false if end has reached
+// Next move cursor to next record, return false if end has reached
 func (rows *Rows) Next() bool {
 	if rows.lastError == nil && rows.rows != nil {
 		hasNext := rows.rows.Next()
@@ -89,7 +102,7 @@ func (rows *Rows) Err() error {
 	return rows.lastError
 }
 
-// scan row record to bean properties
+// Scan row record to bean properties
 func (rows *Rows) Scan(bean interface{}) error {
 	if rows.lastError != nil {
 		return rows.lastError
@@ -99,24 +112,14 @@ func (rows *Rows) Scan(bean interface{}) error {
 		return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
 	}
 
-	return rows.session.row2Bean(rows.rows, rows.fields, rows.fieldsCount, bean)
+	dataStruct := rValue(bean)
+	rows.session.Statement.setRefValue(dataStruct)
+	_, err := rows.session.row2Bean(rows.rows, rows.fields, len(rows.fields), bean, &dataStruct, rows.session.Statement.RefTable)
 
-	// result, err := row2map(rows.rows, rows.fields) // !nashtsai! TODO remove row2map then scanMapIntoStruct conversation for better performance
-	// if err == nil {
-	// 	err = rows.session.scanMapIntoStruct(bean, result)
-	// }
-	// return err
+	return err
 }
 
-// // Columns returns the column names. Columns returns an error if the rows are closed, or if the rows are from QueryRow and there was a deferred error.
-// func (rows *Rows) Columns() ([]string, error) {
-// 	if rows.lastError == nil && rows.rows != nil {
-// 		return rows.rows.Columns()
-// 	}
-// 	return nil, rows.lastError
-// }
-
-// close session if session.IsAutoClose is true, and claimed any opened resources
+// Close session if session.IsAutoClose is true, and claimed any opened resources
 func (rows *Rows) Close() error {
 	if rows.session.IsAutoClose {
 		defer rows.session.Close()

文件差异内容过多而无法显示
+ 213 - 1484
vendor/github.com/go-xorm/xorm/session.go


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

@@ -0,0 +1,84 @@
+// Copyright 2017 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+// Incr provides a query string like "count = count + 1"
+func (session *Session) Incr(column string, arg ...interface{}) *Session {
+	session.Statement.Incr(column, arg...)
+	return session
+}
+
+// Decr provides a query string like "count = count - 1"
+func (session *Session) Decr(column string, arg ...interface{}) *Session {
+	session.Statement.Decr(column, arg...)
+	return session
+}
+
+// SetExpr provides a query string like "column = {expression}"
+func (session *Session) SetExpr(column string, expression string) *Session {
+	session.Statement.SetExpr(column, expression)
+	return session
+}
+
+// Select provides some columns to special
+func (session *Session) Select(str string) *Session {
+	session.Statement.Select(str)
+	return session
+}
+
+// Cols provides some columns to special
+func (session *Session) Cols(columns ...string) *Session {
+	session.Statement.Cols(columns...)
+	return session
+}
+
+// AllCols ask all columns
+func (session *Session) AllCols() *Session {
+	session.Statement.AllCols()
+	return session
+}
+
+// MustCols specify some columns must use even if they are empty
+func (session *Session) MustCols(columns ...string) *Session {
+	session.Statement.MustCols(columns...)
+	return session
+}
+
+// UseBool automatically retrieve condition according struct, but
+// if struct has bool field, it will ignore them. So use UseBool
+// to tell system to do not ignore them.
+// If no parameters, it will use all the bool field of struct, or
+// it will use parameters's columns
+func (session *Session) UseBool(columns ...string) *Session {
+	session.Statement.UseBool(columns...)
+	return session
+}
+
+// Distinct use for distinct columns. Caution: when you are using cache,
+// distinct will not be cached because cache system need id,
+// but distinct will not provide id
+func (session *Session) Distinct(columns ...string) *Session {
+	session.Statement.Distinct(columns...)
+	return session
+}
+
+// Omit Only not use the parameters as select or update columns
+func (session *Session) Omit(columns ...string) *Session {
+	session.Statement.Omit(columns...)
+	return session
+}
+
+// Nullable Set null when column is zero-value and nullable for update
+func (session *Session) Nullable(columns ...string) *Session {
+	session.Statement.Nullable(columns...)
+	return session
+}
+
+// NoAutoTime means do not automatically give created field and updated field
+// the current time on the current session temporarily
+func (session *Session) NoAutoTime() *Session {
+	session.Statement.UseAutoTime = false
+	return session
+}

+ 70 - 0
vendor/github.com/go-xorm/xorm/session_cond.go

@@ -0,0 +1,70 @@
+// Copyright 2017 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import "github.com/go-xorm/builder"
+
+// Sql provides raw sql input parameter. When you have a complex SQL statement
+// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
+//
+// Deprecated: use SQL instead.
+func (session *Session) Sql(query string, args ...interface{}) *Session {
+	return session.SQL(query, args...)
+}
+
+// SQL provides raw sql input parameter. When you have a complex SQL statement
+// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
+func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
+	session.Statement.SQL(query, args...)
+	return session
+}
+
+// Where provides custom query condition.
+func (session *Session) Where(query interface{}, args ...interface{}) *Session {
+	session.Statement.Where(query, args...)
+	return session
+}
+
+// And provides custom query condition.
+func (session *Session) And(query interface{}, args ...interface{}) *Session {
+	session.Statement.And(query, args...)
+	return session
+}
+
+// Or provides custom query condition.
+func (session *Session) Or(query interface{}, args ...interface{}) *Session {
+	session.Statement.Or(query, args...)
+	return session
+}
+
+// Id provides converting id as a query condition
+//
+// Deprecated: use ID instead
+func (session *Session) Id(id interface{}) *Session {
+	return session.ID(id)
+}
+
+// ID provides converting id as a query condition
+func (session *Session) ID(id interface{}) *Session {
+	session.Statement.ID(id)
+	return session
+}
+
+// In provides a query string like "id in (1, 2, 3)"
+func (session *Session) In(column string, args ...interface{}) *Session {
+	session.Statement.In(column, args...)
+	return session
+}
+
+// NotIn provides a query string like "id in (1, 2, 3)"
+func (session *Session) NotIn(column string, args ...interface{}) *Session {
+	session.Statement.NotIn(column, args...)
+	return session
+}
+
+// Conds returns session query conditions
+func (session *Session) Conds() builder.Cond {
+	return session.Statement.cond
+}

+ 670 - 0
vendor/github.com/go-xorm/xorm/session_convert.go

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

+ 238 - 0
vendor/github.com/go-xorm/xorm/session_delete.go

@@ -0,0 +1,238 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+
+	"github.com/go-xorm/core"
+)
+
+func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
+	if session.Statement.RefTable == nil ||
+		session.Tx != nil {
+		return ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	newsql := session.Statement.convertIDSQL(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+
+	cacher := session.Engine.getCacher2(session.Statement.RefTable)
+	tableName := session.Statement.TableName()
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	if err != nil {
+		resultsSlice, err := session.query(newsql, args...)
+		if err != nil {
+			return err
+		}
+		ids = make([]core.PK, 0)
+		if len(resultsSlice) > 0 {
+			for _, data := range resultsSlice {
+				var id int64
+				var pk core.PK = make([]interface{}, 0)
+				for _, col := range session.Statement.RefTable.PKColumns() {
+					if v, ok := data[col.Name]; !ok {
+						return errors.New("no id")
+					} else if col.SQLType.IsText() {
+						pk = append(pk, string(v))
+					} else if col.SQLType.IsNumeric() {
+						id, err = strconv.ParseInt(string(v), 10, 64)
+						if err != nil {
+							return err
+						}
+						pk = append(pk, id)
+					} else {
+						return errors.New("not supported primary key type")
+					}
+				}
+				ids = append(ids, pk)
+			}
+		}
+	} /*else {
+	    session.Engine.LogDebug("delete cache sql %v", newsql)
+	    cacher.DelIds(tableName, genSqlKey(newsql, args))
+	}*/
+
+	for _, id := range ids {
+		session.Engine.logger.Debug("[cacheDelete] delete cache obj", tableName, id)
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		cacher.DelBean(tableName, sid)
+	}
+	session.Engine.logger.Debug("[cacheDelete] clear cache sql", tableName)
+	cacher.ClearIds(tableName)
+	return nil
+}
+
+// Delete records, bean's non-empty fields are conditions
+func (session *Session) Delete(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	session.Statement.setRefValue(rValue(bean))
+	var table = session.Statement.RefTable
+
+	// handle before delete processors
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures)
+
+	if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
+		processor.BeforeDelete()
+	}
+
+	// --
+	condSQL, condArgs, _ := session.Statement.genConds(bean)
+	if len(condSQL) == 0 && session.Statement.LimitN == 0 {
+		return 0, ErrNeedDeletedCond
+	}
+
+	var tableName = session.Engine.Quote(session.Statement.TableName())
+	var deleteSQL string
+	if len(condSQL) > 0 {
+		deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
+	} else {
+		deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
+	}
+
+	var orderSQL string
+	if len(session.Statement.OrderStr) > 0 {
+		orderSQL += fmt.Sprintf(" ORDER BY %s", session.Statement.OrderStr)
+	}
+	if session.Statement.LimitN > 0 {
+		orderSQL += fmt.Sprintf(" LIMIT %d", session.Statement.LimitN)
+	}
+
+	if len(orderSQL) > 0 {
+		switch session.Engine.dialect.DBType() {
+		case core.POSTGRES:
+			inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
+			if len(condSQL) > 0 {
+				deleteSQL += " AND " + inSQL
+			} else {
+				deleteSQL += " WHERE " + inSQL
+			}
+		case core.SQLITE:
+			inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
+			if len(condSQL) > 0 {
+				deleteSQL += " AND " + inSQL
+			} else {
+				deleteSQL += " WHERE " + inSQL
+			}
+		// TODO: how to handle delete limit on mssql?
+		case core.MSSQL:
+			return 0, ErrNotImplemented
+		default:
+			deleteSQL += orderSQL
+		}
+	}
+
+	var realSQL string
+	argsForCache := make([]interface{}, 0, len(condArgs)*2)
+	if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
+		realSQL = deleteSQL
+		copy(argsForCache, condArgs)
+		argsForCache = append(condArgs, argsForCache...)
+	} else {
+		// !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
+		copy(argsForCache, condArgs)
+		argsForCache = append(condArgs, argsForCache...)
+
+		deletedColumn := table.DeletedColumn()
+		realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
+			session.Engine.Quote(session.Statement.TableName()),
+			session.Engine.Quote(deletedColumn.Name),
+			condSQL)
+
+		if len(orderSQL) > 0 {
+			switch session.Engine.dialect.DBType() {
+			case core.POSTGRES:
+				inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
+				if len(condSQL) > 0 {
+					realSQL += " AND " + inSQL
+				} else {
+					realSQL += " WHERE " + inSQL
+				}
+			case core.SQLITE:
+				inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
+				if len(condSQL) > 0 {
+					realSQL += " AND " + inSQL
+				} else {
+					realSQL += " WHERE " + inSQL
+				}
+			// TODO: how to handle delete limit on mssql?
+			case core.MSSQL:
+				return 0, ErrNotImplemented
+			default:
+				realSQL += orderSQL
+			}
+		}
+
+		// !oinume! Insert NowTime to the head of session.Statement.Params
+		condArgs = append(condArgs, "")
+		paramsLen := len(condArgs)
+		copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
+
+		val, t := session.Engine.NowTime2(deletedColumn.SQLType.Name)
+		condArgs[0] = val
+
+		var colName = deletedColumn.Name
+		session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+			col := table.GetColumn(colName)
+			setColumnTime(bean, col, t)
+		})
+	}
+
+	if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
+		session.cacheDelete(deleteSQL, argsForCache...)
+	}
+
+	res, err := session.exec(realSQL, condArgs...)
+	if err != nil {
+		return 0, err
+	}
+
+	// handle after delete processors
+	if session.IsAutoCommit {
+		for _, closure := range session.afterClosures {
+			closure(bean)
+		}
+		if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
+			processor.AfterDelete()
+		}
+	} else {
+		lenAfterClosures := len(session.afterClosures)
+		if lenAfterClosures > 0 {
+			if value, has := session.afterDeleteBeans[bean]; has && value != nil {
+				*value = append(*value, session.afterClosures...)
+			} else {
+				afterClosures := make([]func(interface{}), lenAfterClosures)
+				copy(afterClosures, session.afterClosures)
+				session.afterDeleteBeans[bean] = &afterClosures
+			}
+		} else {
+			if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
+				session.afterDeleteBeans[bean] = nil
+			}
+		}
+	}
+	cleanupProcessorsClosures(&session.afterClosures)
+	// --
+
+	return res.RowsAffected()
+}

+ 461 - 0
vendor/github.com/go-xorm/xorm/session_find.go

@@ -0,0 +1,461 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/go-xorm/builder"
+	"github.com/go-xorm/core"
+)
+
+const (
+	tpStruct = iota
+	tpNonStruct
+)
+
+// Find retrieve records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
+		return errors.New("needs a pointer to a slice or a map")
+	}
+
+	sliceElementType := sliceValue.Type().Elem()
+
+	var tp = tpStruct
+	if session.Statement.RefTable == nil {
+		if sliceElementType.Kind() == reflect.Ptr {
+			if sliceElementType.Elem().Kind() == reflect.Struct {
+				pv := reflect.New(sliceElementType.Elem())
+				session.Statement.setRefValue(pv.Elem())
+			} else {
+				tp = tpNonStruct
+			}
+		} else if sliceElementType.Kind() == reflect.Struct {
+			pv := reflect.New(sliceElementType)
+			session.Statement.setRefValue(pv.Elem())
+		} else {
+			tp = tpNonStruct
+		}
+	}
+
+	var table = session.Statement.RefTable
+
+	var addedTableName = (len(session.Statement.JoinStr) > 0)
+	var autoCond builder.Cond
+	if tp == tpStruct {
+		if !session.Statement.noAutoCondition && len(condiBean) > 0 {
+			var err error
+			autoCond, err = session.Statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
+			if err != nil {
+				panic(err)
+			}
+		} else {
+			// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
+			// See https://github.com/go-xorm/xorm/issues/179
+			if col := table.DeletedColumn(); col != nil && !session.Statement.unscoped { // tag "deleted" is enabled
+				var colName = session.Engine.Quote(col.Name)
+				if addedTableName {
+					var nm = session.Statement.TableName()
+					if len(session.Statement.TableAlias) > 0 {
+						nm = session.Statement.TableAlias
+					}
+					colName = session.Engine.Quote(nm) + "." + colName
+				}
+				if session.Engine.dialect.DBType() == core.MSSQL {
+					autoCond = builder.IsNull{colName}
+				} else {
+					autoCond = builder.IsNull{colName}.Or(builder.Eq{colName: "0001-01-01 00:00:00"})
+				}
+			}
+		}
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if session.Statement.RawSQL == "" {
+		if len(session.Statement.TableName()) <= 0 {
+			return ErrTableNotFound
+		}
+
+		var columnStr = session.Statement.ColumnStr
+		if len(session.Statement.selectStr) > 0 {
+			columnStr = session.Statement.selectStr
+		} else {
+			if session.Statement.JoinStr == "" {
+				if columnStr == "" {
+					if session.Statement.GroupByStr != "" {
+						columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1))
+					} else {
+						columnStr = session.Statement.genColumnStr()
+					}
+				}
+			} else {
+				if columnStr == "" {
+					if session.Statement.GroupByStr != "" {
+						columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1))
+					} else {
+						columnStr = "*"
+					}
+				}
+			}
+			if columnStr == "" {
+				columnStr = "*"
+			}
+		}
+
+		condSQL, condArgs, _ := builder.ToSQL(session.Statement.cond.And(autoCond))
+
+		args = append(session.Statement.joinArgs, condArgs...)
+		sqlStr = session.Statement.genSelectSQL(columnStr, condSQL)
+		// for mssql and use limit
+		qs := strings.Count(sqlStr, "?")
+		if len(args)*2 == qs {
+			args = append(args, args...)
+		}
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	var err error
+	if session.canCache() {
+		if cacher := session.Engine.getCacher2(table); cacher != nil &&
+			!session.Statement.IsDistinct &&
+			!session.Statement.unscoped {
+			err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
+			if err != ErrCacheFailed {
+				return err
+			}
+			err = nil // !nashtsai! reset err to nil for ErrCacheFailed
+			session.Engine.logger.Warn("Cache Find Failed")
+		}
+	}
+
+	return session.noCacheFind(table, sliceValue, sqlStr, args...)
+}
+
+func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
+	var rawRows *core.Rows
+	var err error
+
+	session.queryPreprocess(&sqlStr, args...)
+	if session.IsAutoCommit {
+		_, rawRows, err = session.innerQuery(sqlStr, args...)
+	} else {
+		rawRows, err = session.Tx.Query(sqlStr, args...)
+	}
+	if err != nil {
+		return err
+	}
+	defer rawRows.Close()
+
+	fields, err := rawRows.Columns()
+	if err != nil {
+		return err
+	}
+
+	var newElemFunc func(fields []string) reflect.Value
+	elemType := containerValue.Type().Elem()
+	var isPointer bool
+	if elemType.Kind() == reflect.Ptr {
+		isPointer = true
+		elemType = elemType.Elem()
+	}
+	if elemType.Kind() == reflect.Ptr {
+		return errors.New("pointer to pointer is not supported")
+	}
+
+	newElemFunc = func(fields []string) reflect.Value {
+		switch elemType.Kind() {
+		case reflect.Slice:
+			slice := reflect.MakeSlice(elemType, len(fields), len(fields))
+			x := reflect.New(slice.Type())
+			x.Elem().Set(slice)
+			return x
+		case reflect.Map:
+			mp := reflect.MakeMap(elemType)
+			x := reflect.New(mp.Type())
+			x.Elem().Set(mp)
+			return x
+		}
+		return reflect.New(elemType)
+	}
+
+	var containerValueSetFunc func(*reflect.Value, core.PK) error
+
+	if containerValue.Kind() == reflect.Slice {
+		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
+			if isPointer {
+				containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
+			} else {
+				containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
+			}
+			return nil
+		}
+	} else {
+		keyType := containerValue.Type().Key()
+		if len(table.PrimaryKeys) == 0 {
+			return errors.New("don't support multiple primary key's map has non-slice key type")
+		}
+		if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
+			return errors.New("don't support multiple primary key's map has non-slice key type")
+		}
+
+		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
+			keyValue := reflect.New(keyType)
+			err := convertPKToValue(table, keyValue.Interface(), pk)
+			if err != nil {
+				return err
+			}
+			if isPointer {
+				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
+			} else {
+				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
+			}
+			return nil
+		}
+	}
+
+	if elemType.Kind() == reflect.Struct {
+		var newValue = newElemFunc(fields)
+		dataStruct := rValue(newValue.Interface())
+		return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, containerValueSetFunc)
+	}
+
+	for rawRows.Next() {
+		var newValue = newElemFunc(fields)
+		bean := newValue.Interface()
+
+		switch elemType.Kind() {
+		case reflect.Slice:
+			err = rawRows.ScanSlice(bean)
+		case reflect.Map:
+			err = rawRows.ScanMap(bean)
+		default:
+			err = rawRows.Scan(bean)
+		}
+
+		if err != nil {
+			return err
+		}
+
+		if err := containerValueSetFunc(&newValue, nil); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
+	cols := table.PKColumns()
+	if len(cols) == 1 {
+		return convertAssign(dst, pk[0])
+	}
+
+	dst = pk
+	return nil
+}
+
+func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
+	if !session.canCache() ||
+		indexNoCase(sqlStr, "having") != -1 ||
+		indexNoCase(sqlStr, "group by") != -1 {
+		return ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	newsql := session.Statement.convertIDSQL(sqlStr)
+	if newsql == "" {
+		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.DB().Query(newsql, args...)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		var i int
+		ids = make([]core.PK, 0)
+		for rows.Next() {
+			i++
+			if i > 500 {
+				session.Engine.logger.Debug("[cacheFind] ids length > 500, no cache")
+				return ErrCacheFailed
+			}
+			var res = make([]string, len(table.PrimaryKeys))
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return err
+			}
+
+			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+			for i, col := range table.PKColumns() {
+				if col.SQLType.IsNumeric() {
+					n, err := strconv.ParseInt(res[i], 10, 64)
+					if err != nil {
+						return err
+					}
+					pk[i] = n
+				} else if col.SQLType.IsText() {
+					pk[i] = res[i]
+				} else {
+					return errors.New("not supported")
+				}
+			}
+
+			ids = append(ids, pk)
+		}
+
+		session.Engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, newsql, args)
+		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
+		if err != nil {
+			return err
+		}
+	} else {
+		session.Engine.logger.Debug("[cacheFind] cache hit sql:", newsql, args)
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+
+	ididxes := make(map[string]int)
+	var ides []core.PK
+	var temps = make([]interface{}, len(ids))
+
+	for idx, id := range ids {
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		bean := cacher.GetBean(tableName, sid)
+		if bean == nil {
+			ides = append(ides, id)
+			ididxes[sid] = idx
+		} else {
+			session.Engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean)
+
+			pk := session.Engine.IdOf(bean)
+			xid, err := pk.ToString()
+			if err != nil {
+				return err
+			}
+
+			if sid != xid {
+				session.Engine.logger.Error("[cacheFind] error cache", xid, sid, bean)
+				return ErrCacheFailed
+			}
+			temps[idx] = bean
+		}
+	}
+
+	if len(ides) > 0 {
+		newSession := session.Engine.NewSession()
+		defer newSession.Close()
+
+		slices := reflect.New(reflect.SliceOf(t))
+		beans := slices.Interface()
+
+		if len(table.PrimaryKeys) == 1 {
+			ff := make([]interface{}, 0, len(ides))
+			for _, ie := range ides {
+				ff = append(ff, ie[0])
+			}
+
+			newSession.In("`"+table.PrimaryKeys[0]+"`", ff...)
+		} else {
+			for _, ie := range ides {
+				cond := builder.NewCond()
+				for i, name := range table.PrimaryKeys {
+					cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
+				}
+				newSession.Or(cond)
+			}
+		}
+
+		err = newSession.NoCache().Find(beans)
+		if err != nil {
+			return err
+		}
+
+		vs := reflect.Indirect(reflect.ValueOf(beans))
+		for i := 0; i < vs.Len(); i++ {
+			rv := vs.Index(i)
+			if rv.Kind() != reflect.Ptr {
+				rv = rv.Addr()
+			}
+			id := session.Engine.IdOfV(rv)
+			sid, err := id.ToString()
+			if err != nil {
+				return err
+			}
+
+			bean := rv.Interface()
+			temps[ididxes[sid]] = bean
+			session.Engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps)
+			cacher.PutBean(tableName, sid, bean)
+		}
+	}
+
+	for j := 0; j < len(temps); j++ {
+		bean := temps[j]
+		if bean == nil {
+			session.Engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps)
+			// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
+			continue
+		}
+		if sliceValue.Kind() == reflect.Slice {
+			if t.Kind() == reflect.Ptr {
+				sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
+			} else {
+				sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
+			}
+		} else if sliceValue.Kind() == reflect.Map {
+			var key = ids[j]
+			keyType := sliceValue.Type().Key()
+			var ikey interface{}
+			if len(key) == 1 {
+				ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
+				if err != nil {
+					return err
+				}
+			} else {
+				if keyType.Kind() != reflect.Slice {
+					return errors.New("table have multiple primary keys, key is not core.PK or slice")
+				}
+				ikey = key
+			}
+
+			if t.Kind() == reflect.Ptr {
+				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
+			} else {
+				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
+			}
+		}
+	}
+
+	return nil
+}

+ 192 - 0
vendor/github.com/go-xorm/xorm/session_get.go

@@ -0,0 +1,192 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"reflect"
+	"strconv"
+
+	"github.com/go-xorm/core"
+)
+
+// Get retrieve one record from database, bean's non-empty fields
+// will be as conditions
+func (session *Session) Get(bean interface{}) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	beanValue := reflect.ValueOf(bean)
+	if beanValue.Kind() != reflect.Ptr {
+		return false, errors.New("needs a pointer to a struct")
+	}
+
+	// FIXME: remove this after support non-struct Get
+	if beanValue.Elem().Kind() != reflect.Struct {
+		return false, errors.New("needs a pointer to a struct")
+	}
+
+	if beanValue.Elem().Kind() == reflect.Struct {
+		session.Statement.setRefValue(beanValue.Elem())
+	}
+
+	var sqlStr string
+	var args []interface{}
+
+	if session.Statement.RawSQL == "" {
+		if len(session.Statement.TableName()) <= 0 {
+			return false, ErrTableNotFound
+		}
+		session.Statement.Limit(1)
+		sqlStr, args = session.Statement.genGetSQL(bean)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	if session.canCache() {
+		if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil &&
+			!session.Statement.unscoped {
+			has, err := session.cacheGet(bean, sqlStr, args...)
+			if err != ErrCacheFailed {
+				return has, err
+			}
+		}
+	}
+
+	return session.nocacheGet(beanValue.Elem().Kind(), bean, sqlStr, args...)
+}
+
+func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
+	var rawRows *core.Rows
+	var err error
+	session.queryPreprocess(&sqlStr, args...)
+	if session.IsAutoCommit {
+		_, rawRows, err = session.innerQuery(sqlStr, args...)
+	} else {
+		rawRows, err = session.Tx.Query(sqlStr, args...)
+	}
+	if err != nil {
+		return false, err
+	}
+
+	defer rawRows.Close()
+
+	if rawRows.Next() {
+		fields, err := rawRows.Columns()
+		if err != nil {
+			// WARN: Alougth rawRows return true, but get fields failed
+			return true, err
+		}
+
+		switch beanKind {
+		case reflect.Struct:
+			dataStruct := rValue(bean)
+			session.Statement.setRefValue(dataStruct)
+			_, err = session.row2Bean(rawRows, fields, len(fields), bean, &dataStruct, session.Statement.RefTable)
+		case reflect.Slice:
+			err = rawRows.ScanSlice(bean)
+		case reflect.Map:
+			err = rawRows.ScanMap(bean)
+		default:
+			err = rawRows.Scan(bean)
+		}
+
+		return true, err
+	}
+	return false, nil
+}
+
+func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) {
+	// if has no reftable, then don't use cache currently
+	if !session.canCache() {
+		return false, ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+	newsql := session.Statement.convertIDSQL(sqlStr)
+	if newsql == "" {
+		return false, ErrCacheFailed
+	}
+
+	cacher := session.Engine.getCacher2(session.Statement.RefTable)
+	tableName := session.Statement.TableName()
+	session.Engine.logger.Debug("[cacheGet] find sql:", newsql, args)
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	table := session.Statement.RefTable
+	if err != nil {
+		var res = make([]string, len(table.PrimaryKeys))
+		rows, err := session.DB().Query(newsql, args...)
+		if err != nil {
+			return false, err
+		}
+		defer rows.Close()
+
+		if rows.Next() {
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return false, err
+			}
+		} else {
+			return false, ErrCacheFailed
+		}
+
+		var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+		for i, col := range table.PKColumns() {
+			if col.SQLType.IsText() {
+				pk[i] = res[i]
+			} else if col.SQLType.IsNumeric() {
+				n, err := strconv.ParseInt(res[i], 10, 64)
+				if err != nil {
+					return false, err
+				}
+				pk[i] = n
+			} else {
+				return false, errors.New("unsupported")
+			}
+		}
+
+		ids = []core.PK{pk}
+		session.Engine.logger.Debug("[cacheGet] cache ids:", newsql, ids)
+		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
+		if err != nil {
+			return false, err
+		}
+	} else {
+		session.Engine.logger.Debug("[cacheGet] cache hit sql:", newsql)
+	}
+
+	if len(ids) > 0 {
+		structValue := reflect.Indirect(reflect.ValueOf(bean))
+		id := ids[0]
+		session.Engine.logger.Debug("[cacheGet] get bean:", tableName, id)
+		sid, err := id.ToString()
+		if err != nil {
+			return false, err
+		}
+		cacheBean := cacher.GetBean(tableName, sid)
+		if cacheBean == nil {
+			cacheBean = bean
+			has, err = session.nocacheGet(reflect.Struct, cacheBean, sqlStr, args...)
+			if err != nil || !has {
+				return has, err
+			}
+
+			session.Engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean)
+			cacher.PutBean(tableName, sid, cacheBean)
+		} else {
+			session.Engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean)
+			has = true
+		}
+		structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean)))
+
+		return has, nil
+	}
+	return false, nil
+}

+ 543 - 0
vendor/github.com/go-xorm/xorm/session_insert.go

@@ -0,0 +1,543 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/go-xorm/core"
+)
+
+// Insert insert one or more beans
+func (session *Session) Insert(beans ...interface{}) (int64, error) {
+	var affected int64
+	var err error
+
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	defer session.resetStatement()
+
+	for _, bean := range beans {
+		sliceValue := reflect.Indirect(reflect.ValueOf(bean))
+		if sliceValue.Kind() == reflect.Slice {
+			size := sliceValue.Len()
+			if size > 0 {
+				if session.Engine.SupportInsertMany() {
+					cnt, err := session.innerInsertMulti(bean)
+					if err != nil {
+						return affected, err
+					}
+					affected += cnt
+				} else {
+					for i := 0; i < size; i++ {
+						cnt, err := session.innerInsert(sliceValue.Index(i).Interface())
+						if err != nil {
+							return affected, err
+						}
+						affected += cnt
+					}
+				}
+			}
+		} else {
+			cnt, err := session.innerInsert(bean)
+			if err != nil {
+				return affected, err
+			}
+			affected += cnt
+		}
+	}
+
+	return affected, err
+}
+
+func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) {
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice {
+		return 0, errors.New("needs a pointer to a slice")
+	}
+
+	if sliceValue.Len() <= 0 {
+		return 0, errors.New("could not insert a empty slice")
+	}
+
+	session.Statement.setRefValue(sliceValue.Index(0))
+
+	if len(session.Statement.TableName()) <= 0 {
+		return 0, ErrTableNotFound
+	}
+
+	table := session.Statement.RefTable
+	size := sliceValue.Len()
+
+	var colNames []string
+	var colMultiPlaces []string
+	var args []interface{}
+	var cols []*core.Column
+
+	for i := 0; i < size; i++ {
+		v := sliceValue.Index(i)
+		vv := reflect.Indirect(v)
+		elemValue := v.Interface()
+		var colPlaces []string
+
+		// handle BeforeInsertProcessor
+		// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
+		for _, closure := range session.beforeClosures {
+			closure(elemValue)
+		}
+
+		if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok {
+			processor.BeforeInsert()
+		}
+		// --
+
+		if i == 0 {
+			for _, col := range table.Columns() {
+				ptrFieldValue, err := col.ValueOfV(&vv)
+				if err != nil {
+					return 0, err
+				}
+				fieldValue := *ptrFieldValue
+				if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
+					continue
+				}
+				if col.MapType == core.ONLYFROMDB {
+					continue
+				}
+				if col.IsDeleted {
+					continue
+				}
+				if session.Statement.ColumnStr != "" {
+					if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
+						continue
+					}
+				}
+				if session.Statement.OmitStr != "" {
+					if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok {
+						continue
+					}
+				}
+				if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+					val, t := session.Engine.NowTime2(col.SQLType.Name)
+					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)
+					var colName = col.Name
+					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+						col := table.GetColumn(colName)
+						setColumnInt(bean, col, 1)
+					})
+				} else {
+					arg, err := session.value2Interface(col, fieldValue)
+					if err != nil {
+						return 0, err
+					}
+					args = append(args, arg)
+				}
+
+				colNames = append(colNames, col.Name)
+				cols = append(cols, col)
+				colPlaces = append(colPlaces, "?")
+			}
+		} else {
+			for _, col := range cols {
+				ptrFieldValue, err := col.ValueOfV(&vv)
+				if err != nil {
+					return 0, err
+				}
+				fieldValue := *ptrFieldValue
+
+				if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
+					continue
+				}
+				if col.MapType == core.ONLYFROMDB {
+					continue
+				}
+				if col.IsDeleted {
+					continue
+				}
+				if session.Statement.ColumnStr != "" {
+					if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
+						continue
+					}
+				}
+				if session.Statement.OmitStr != "" {
+					if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok {
+						continue
+					}
+				}
+				if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+					val, t := session.Engine.NowTime2(col.SQLType.Name)
+					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)
+					var colName = col.Name
+					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+						col := table.GetColumn(colName)
+						setColumnInt(bean, col, 1)
+					})
+				} else {
+					arg, err := session.value2Interface(col, fieldValue)
+					if err != nil {
+						return 0, err
+					}
+					args = append(args, arg)
+				}
+
+				colPlaces = append(colPlaces, "?")
+			}
+		}
+		colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", "))
+	}
+	cleanupProcessorsClosures(&session.beforeClosures)
+
+	var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
+	var statement string
+	if session.Engine.dialect.DBType() == core.ORACLE {
+		sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
+		temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
+			session.Engine.Quote(session.Statement.TableName()),
+			session.Engine.QuoteStr(),
+			strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
+			session.Engine.QuoteStr())
+		statement = fmt.Sprintf(sql,
+			session.Engine.Quote(session.Statement.TableName()),
+			session.Engine.QuoteStr(),
+			strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
+			session.Engine.QuoteStr(),
+			strings.Join(colMultiPlaces, temp))
+	} else {
+		statement = fmt.Sprintf(sql,
+			session.Engine.Quote(session.Statement.TableName()),
+			session.Engine.QuoteStr(),
+			strings.Join(colNames, session.Engine.QuoteStr() + ", " + session.Engine.QuoteStr()),
+			session.Engine.QuoteStr(),
+			strings.Join(colMultiPlaces, "),("))
+	}
+	res, err := session.exec(statement, args...)
+	if err != nil {
+		return 0, err
+	}
+
+	if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+		session.cacheInsert(session.Statement.TableName())
+	}
+
+	lenAfterClosures := len(session.afterClosures)
+	for i := 0; i < size; i++ {
+		elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface()
+
+		// handle AfterInsertProcessor
+		if session.IsAutoCommit {
+			// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
+			for _, closure := range session.afterClosures {
+				closure(elemValue)
+			}
+			if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
+				processor.AfterInsert()
+			}
+		} else {
+			if lenAfterClosures > 0 {
+				if value, has := session.afterInsertBeans[elemValue]; has && value != nil {
+					*value = append(*value, session.afterClosures...)
+				} else {
+					afterClosures := make([]func(interface{}), lenAfterClosures)
+					copy(afterClosures, session.afterClosures)
+					session.afterInsertBeans[elemValue] = &afterClosures
+				}
+			} else {
+				if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
+					session.afterInsertBeans[elemValue] = nil
+				}
+			}
+		}
+	}
+
+	cleanupProcessorsClosures(&session.afterClosures)
+	return res.RowsAffected()
+}
+
+// InsertMulti insert multiple records
+func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice {
+		return 0, ErrParamsType
+
+	}
+
+	if sliceValue.Len() <= 0 {
+		return 0, nil
+	}
+
+	return session.innerInsertMulti(rowsSlicePtr)
+}
+
+func (session *Session) innerInsert(bean interface{}) (int64, error) {
+	session.Statement.setRefValue(rValue(bean))
+	if len(session.Statement.TableName()) <= 0 {
+		return 0, ErrTableNotFound
+	}
+
+	table := session.Statement.RefTable
+
+	// handle BeforeInsertProcessor
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
+
+	if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
+		processor.BeforeInsert()
+	}
+	// --
+	colNames, args, err := genCols(session.Statement.RefTable, session, bean, false, false)
+	if err != nil {
+		return 0, err
+	}
+	// insert expr columns, override if exists
+	exprColumns := session.Statement.getExpr()
+	exprColVals := make([]string, 0, len(exprColumns))
+	for _, v := range exprColumns {
+		// remove the expr columns
+		for i, colName := range colNames {
+			if colName == v.colName {
+				colNames = append(colNames[:i], colNames[i + 1:]...)
+				args = append(args[:i], args[i + 1:]...)
+			}
+		}
+
+		// append expr column to the end
+		colNames = append(colNames, v.colName)
+		exprColVals = append(exprColVals, v.expr)
+	}
+
+	colPlaces := strings.Repeat("?, ", len(colNames) - len(exprColumns))
+	if len(exprColVals) > 0 {
+		colPlaces = colPlaces + strings.Join(exprColVals, ", ")
+	} else {
+		colPlaces = colPlaces[0 : len(colPlaces) - 2]
+	}
+
+	sqlStr := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
+		session.Engine.Quote(session.Statement.TableName()),
+		session.Engine.QuoteStr(),
+		strings.Join(colNames, session.Engine.Quote(", ")),
+		session.Engine.QuoteStr(),
+		colPlaces)
+
+	handleAfterInsertProcessorFunc := func(bean interface{}) {
+		if session.IsAutoCommit {
+			for _, closure := range session.afterClosures {
+				closure(bean)
+			}
+			if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
+				processor.AfterInsert()
+			}
+		} else {
+			lenAfterClosures := len(session.afterClosures)
+			if lenAfterClosures > 0 {
+				if value, has := session.afterInsertBeans[bean]; has && value != nil {
+					*value = append(*value, session.afterClosures...)
+				} else {
+					afterClosures := make([]func(interface{}), lenAfterClosures)
+					copy(afterClosures, session.afterClosures)
+					session.afterInsertBeans[bean] = &afterClosures
+				}
+
+			} else {
+				if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
+					session.afterInsertBeans[bean] = nil
+				}
+			}
+		}
+		cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
+	}
+
+	// for postgres, many of them didn't implement lastInsertId, so we should
+	// implemented it ourself.
+	if session.Engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
+		//assert table.AutoIncrement != ""
+		res, err := session.query("select seq_atable.currval from dual", args...)
+		if err != nil {
+			return 0, err
+		}
+
+		handleAfterInsertProcessorFunc(bean)
+
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			session.cacheInsert(session.Statement.TableName())
+		}
+
+		if table.Version != "" && session.Statement.checkVersion {
+			verValue, err := table.VersionColumn().ValueOf(bean)
+			if err != nil {
+				session.Engine.logger.Error(err)
+			} else if verValue.IsValid() && verValue.CanSet() {
+				verValue.SetInt(1)
+			}
+		}
+
+		if len(res) < 1 {
+			return 0, errors.New("insert no error but not returned id")
+		}
+
+		idByte := res[0][table.AutoIncrement]
+		id, err := strconv.ParseInt(string(idByte), 10, 64)
+		if err != nil || id <= 0 {
+			return 1, err
+		}
+
+		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
+		if err != nil {
+			session.Engine.logger.Error(err)
+		}
+
+		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
+			return 1, nil
+		}
+
+		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
+
+		return 1, nil
+	} else if session.Engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 {
+		//assert table.AutoIncrement != ""
+		sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement)
+		res, err := session.query(sqlStr, args...)
+
+		if err != nil {
+			return 0, err
+		}
+		handleAfterInsertProcessorFunc(bean)
+
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			session.cacheInsert(session.Statement.TableName())
+		}
+
+		if table.Version != "" && session.Statement.checkVersion {
+			verValue, err := table.VersionColumn().ValueOf(bean)
+			if err != nil {
+				session.Engine.logger.Error(err)
+			} else if verValue.IsValid() && verValue.CanSet() {
+				verValue.SetInt(1)
+			}
+		}
+
+		if len(res) < 1 {
+			return 0, errors.New("insert no error but not returned id")
+		}
+
+		idByte := res[0][table.AutoIncrement]
+		id, err := strconv.ParseInt(string(idByte), 10, 64)
+		if err != nil || id <= 0 {
+			return 1, err
+		}
+
+		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
+		if err != nil {
+			session.Engine.logger.Error(err)
+		}
+
+		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
+			return 1, nil
+		}
+
+		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
+
+		return 1, nil
+	} else {
+		res, err := session.exec(sqlStr, args...)
+		if err != nil {
+			return 0, err
+		}
+
+		defer handleAfterInsertProcessorFunc(bean)
+
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			session.cacheInsert(session.Statement.TableName())
+		}
+
+		if table.Version != "" && session.Statement.checkVersion {
+			verValue, err := table.VersionColumn().ValueOf(bean)
+			if err != nil {
+				session.Engine.logger.Error(err)
+			} else if verValue.IsValid() && verValue.CanSet() {
+				verValue.SetInt(1)
+			}
+		}
+
+		if table.AutoIncrement == "" {
+			return res.RowsAffected()
+		}
+
+		var id int64
+		id, err = res.LastInsertId()
+		if err != nil || id <= 0 {
+			return res.RowsAffected()
+		}
+
+		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
+		if err != nil {
+			session.Engine.logger.Error(err)
+		}
+
+		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
+			return res.RowsAffected()
+		}
+
+		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
+
+		return res.RowsAffected()
+	}
+}
+
+// InsertOne insert only one struct into database as a record.
+// The in parameter bean must a struct or a point to struct. The return
+// parameter is inserted and error
+func (session *Session) InsertOne(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.innerInsert(bean)
+}
+
+func (session *Session) cacheInsert(tables ...string) error {
+	if session.Statement.RefTable == nil {
+		return ErrCacheFailed
+	}
+
+	table := session.Statement.RefTable
+	cacher := session.Engine.getCacher2(table)
+
+	for _, t := range tables {
+		session.Engine.logger.Debug("[cache] clear sql:", t)
+		cacher.ClearIds(t)
+	}
+
+	return nil
+}

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

@@ -0,0 +1,42 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import "reflect"
+
+// IterFunc only use by Iterate
+type IterFunc func(idx int, bean interface{}) error
+
+// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
+// are conditions.
+func (session *Session) Rows(bean interface{}) (*Rows, error) {
+	return newRows(session, bean)
+}
+
+// Iterate record by record handle records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
+	rows, err := session.Rows(bean)
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	i := 0
+	for rows.Next() {
+		b := reflect.New(rows.beanType).Interface()
+		err = rows.Scan(b)
+		if err != nil {
+			return err
+		}
+		err = fun(i, b)
+		if err != nil {
+			return err
+		}
+		i++
+	}
+	return err
+}

+ 144 - 0
vendor/github.com/go-xorm/xorm/session_raw.go

@@ -0,0 +1,144 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql"
+
+	"github.com/go-xorm/core"
+)
+
+func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return session.innerQuery2(sqlStr, paramStr...)
+	}
+	return session.txQuery(session.Tx, sqlStr, paramStr...)
+}
+
+func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	rows, err := tx.Query(sqlStr, params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2maps(rows)
+}
+
+func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) {
+	var callback func() (*core.Stmt, *core.Rows, error)
+	if session.prepareStmt {
+		callback = func() (*core.Stmt, *core.Rows, error) {
+			stmt, err := session.doPrepare(sqlStr)
+			if err != nil {
+				return nil, nil, err
+			}
+			rows, err := stmt.Query(params...)
+			if err != nil {
+				return nil, nil, err
+			}
+			return stmt, rows, nil
+		}
+	} else {
+		callback = func() (*core.Stmt, *core.Rows, error) {
+			rows, err := session.DB().Query(sqlStr, params...)
+			if err != nil {
+				return nil, nil, err
+			}
+			return nil, rows, err
+		}
+	}
+	stmt, rows, err := session.Engine.logSQLQueryTime(sqlStr, params, callback)
+	if err != nil {
+		return nil, nil, err
+	}
+	return stmt, rows, nil
+}
+
+func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
+	_, rows, err := session.innerQuery(sqlStr, params...)
+	if rows != nil {
+		defer rows.Close()
+	}
+	if err != nil {
+		return nil, err
+	}
+	return rows2maps(rows)
+}
+
+// Query a raw sql and return records as []map[string][]byte
+func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.query(sqlStr, paramStr...)
+}
+
+// =============================
+// for string
+// =============================
+func (session *Session) query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) {
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return query2(session.DB(), sqlStr, paramStr...)
+	}
+	return txQuery2(session.Tx, sqlStr, paramStr...)
+}
+
+// Execute sql
+func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	if session.prepareStmt {
+		stmt, err := session.doPrepare(sqlStr)
+		if err != nil {
+			return nil, err
+		}
+
+		res, err := stmt.Exec(args...)
+		if err != nil {
+			return nil, err
+		}
+		return res, nil
+	}
+
+	return session.DB().Exec(sqlStr, args...)
+}
+
+func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	for _, filter := range session.Engine.dialect.Filters() {
+		// TODO: for table name, it's no need to RefTable
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	session.saveLastSQL(sqlStr, args...)
+
+	return session.Engine.logSQLExecutionTime(sqlStr, args, func() (sql.Result, error) {
+		if session.IsAutoCommit {
+			// FIXME: oci8 can not auto commit (github.com/mattn/go-oci8)
+			if session.Engine.dialect.DBType() == core.ORACLE {
+				session.Begin()
+				r, err := session.Tx.Exec(sqlStr, args...)
+				session.Commit()
+				return r, err
+			}
+			return session.innerExec(sqlStr, args...)
+		}
+		return session.Tx.Exec(sqlStr, args...)
+	})
+}
+
+// Exec raw sql
+func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.exec(sqlStr, args...)
+}

+ 489 - 0
vendor/github.com/go-xorm/xorm/session_schema.go

@@ -0,0 +1,489 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/go-xorm/core"
+)
+
+// Ping test if database is ok
+func (session *Session) Ping() error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.DB().Ping()
+}
+
+// CreateTable create a table according a bean
+func (session *Session) CreateTable(bean interface{}) error {
+	v := rValue(bean)
+	session.Statement.setRefValue(v)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.createOneTable()
+}
+
+// CreateIndexes create indexes
+func (session *Session) CreateIndexes(bean interface{}) error {
+	v := rValue(bean)
+	session.Statement.setRefValue(v)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genIndexSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// CreateUniques create uniques
+func (session *Session) CreateUniques(bean interface{}) error {
+	v := rValue(bean)
+	session.Statement.setRefValue(v)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genUniqueSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (session *Session) createOneTable() error {
+	sqlStr := session.Statement.genCreateTableSQL()
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// to be deleted
+func (session *Session) createAll() error {
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	for _, table := range session.Engine.Tables {
+		session.Statement.RefTable = table
+		session.Statement.tableName = table.Name
+		err := session.createOneTable()
+		session.resetStatement()
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// DropIndexes drop indexes
+func (session *Session) DropIndexes(bean interface{}) error {
+	v := rValue(bean)
+	session.Statement.setRefValue(v)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genDelIndexSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// DropTable drop table will drop table if exist, if drop failed, it will return error
+func (session *Session) DropTable(beanOrTableName interface{}) error {
+	tableName, err := session.Engine.tableName(beanOrTableName)
+	if err != nil {
+		return err
+	}
+
+	var needDrop = true
+	if !session.Engine.dialect.SupportDropIfExists() {
+		sqlStr, args := session.Engine.dialect.TableCheckSql(tableName)
+		results, err := session.query(sqlStr, args...)
+		if err != nil {
+			return err
+		}
+		needDrop = len(results) > 0
+	}
+
+	if needDrop {
+		sqlStr := session.Engine.Dialect().DropTableSql(tableName)
+		_, err = session.exec(sqlStr)
+		return err
+	}
+	return nil
+}
+
+// IsTableExist if a table is exist
+func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
+	tableName, err := session.Engine.tableName(beanOrTableName)
+	if err != nil {
+		return false, err
+	}
+
+	return session.isTableExist(tableName)
+}
+
+func (session *Session) isTableExist(tableName string) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	sqlStr, args := session.Engine.dialect.TableCheckSql(tableName)
+	results, err := session.query(sqlStr, args...)
+	return len(results) > 0, err
+}
+
+// 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 {
+		return session.isTableEmpty(bean.(string))
+	} else if t.Kind() == reflect.Struct {
+		rows, err := session.Count(bean)
+		return rows == 0, err
+	}
+	return false, errors.New("bean should be a struct or struct's point")
+}
+
+func (session *Session) isTableEmpty(tableName string) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var total int64
+	sqlStr := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName))
+	err := session.DB().QueryRow(sqlStr).Scan(&total)
+	session.saveLastSQL(sqlStr)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			err = nil
+		}
+		return true, err
+	}
+
+	return total == 0, nil
+}
+
+func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	var idx string
+	if unique {
+		idx = uniqueName(tableName, idxName)
+	} else {
+		idx = indexName(tableName, idxName)
+	}
+	sqlStr, args := session.Engine.dialect.IndexCheckSql(tableName, idx)
+	results, err := session.query(sqlStr, args...)
+	return len(results) > 0, err
+}
+
+// find if index is exist according cols
+func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	indexes, err := session.Engine.dialect.GetIndexes(tableName)
+	if err != nil {
+		return false, err
+	}
+
+	for _, index := range indexes {
+		if sliceEq(index.Cols, cols) {
+			if unique {
+				return index.Type == core.UniqueType, nil
+			}
+			return index.Type == core.IndexType, nil
+		}
+	}
+	return false, nil
+}
+
+func (session *Session) addColumn(colName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	col := session.Statement.RefTable.GetColumn(colName)
+	sql, args := session.Statement.genAddColumnStr(col)
+	_, err := session.exec(sql, args...)
+	return err
+}
+
+func (session *Session) addIndex(tableName, idxName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	index := session.Statement.RefTable.Indexes[idxName]
+	sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
+
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+func (session *Session) addUnique(tableName, uqeName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	index := session.Statement.RefTable.Indexes[uqeName]
+	sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// To be deleted
+func (session *Session) dropAll() error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	for _, table := range session.Engine.Tables {
+		session.Statement.Init()
+		session.Statement.RefTable = table
+		sqlStr := session.Engine.Dialect().DropTableSql(session.Statement.TableName())
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Sync2 synchronize structs to database tables
+func (session *Session) Sync2(beans ...interface{}) error {
+	engine := session.Engine
+
+	tables, err := engine.DBMetas()
+	if err != nil {
+		return err
+	}
+
+	var structTables []*core.Table
+
+	for _, bean := range beans {
+		v := rValue(bean)
+		table, err := engine.mapType(v)
+		if err != nil {
+			return err
+		}
+		structTables = append(structTables, table)
+		var tbName = session.tbNameNoSchema(table)
+
+		var oriTable *core.Table
+		for _, tb := range tables {
+			if strings.EqualFold(tb.Name, tbName) {
+				oriTable = tb
+				break
+			}
+		}
+
+		if oriTable == nil {
+			err = session.StoreEngine(session.Statement.StoreEngine).CreateTable(bean)
+			if err != nil {
+				return err
+			}
+
+			err = session.CreateUniques(bean)
+			if err != nil {
+				return err
+			}
+
+			err = session.CreateIndexes(bean)
+			if err != nil {
+				return err
+			}
+		} else {
+			for _, col := range table.Columns() {
+				var oriCol *core.Column
+				for _, col2 := range oriTable.Columns() {
+					if strings.EqualFold(col.Name, col2.Name) {
+						oriCol = col2
+						break
+					}
+				}
+
+				if oriCol != nil {
+					expectedType := engine.dialect.SqlType(col)
+					curType := engine.dialect.SqlType(oriCol)
+					if expectedType != curType {
+						if expectedType == core.Text &&
+							strings.HasPrefix(curType, core.Varchar) {
+							// currently only support mysql & postgres
+							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 = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col))
+							} else {
+								engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
+									tbName, 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 = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, 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)
+							}
+						}
+					} 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 = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col))
+							}
+						}
+					}
+					if col.Default != oriCol.Default {
+						engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s",
+							tbName, col.Name, oriCol.Default, col.Default)
+					}
+					if col.Nullable != oriCol.Nullable {
+						engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v",
+							tbName, col.Name, oriCol.Nullable, col.Nullable)
+					}
+				} else {
+					session := engine.NewSession()
+					session.Statement.RefTable = table
+					session.Statement.tableName = tbName
+					defer session.Close()
+					err = session.addColumn(col.Name)
+				}
+				if err != nil {
+					return err
+				}
+			}
+
+			var foundIndexNames = make(map[string]bool)
+			var addedNames = make(map[string]*core.Index)
+
+			for name, index := range table.Indexes {
+				var oriIndex *core.Index
+				for name2, index2 := range oriTable.Indexes {
+					if index.Equal(index2) {
+						oriIndex = index2
+						foundIndexNames[name2] = true
+						break
+					}
+				}
+
+				if oriIndex != nil {
+					if oriIndex.Type != index.Type {
+						sql := engine.dialect.DropIndexSql(tbName, oriIndex)
+						_, err = engine.Exec(sql)
+						if err != nil {
+							return err
+						}
+						oriIndex = nil
+					}
+				}
+
+				if oriIndex == nil {
+					addedNames[name] = index
+				}
+			}
+
+			for name2, index2 := range oriTable.Indexes {
+				if _, ok := foundIndexNames[name2]; !ok {
+					sql := engine.dialect.DropIndexSql(tbName, index2)
+					_, err = engine.Exec(sql)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			for name, index := range addedNames {
+				if index.Type == core.UniqueType {
+					session := engine.NewSession()
+					session.Statement.RefTable = table
+					session.Statement.tableName = tbName
+					defer session.Close()
+					err = session.addUnique(tbName, name)
+				} else if index.Type == core.IndexType {
+					session := engine.NewSession()
+					session.Statement.RefTable = table
+					session.Statement.tableName = tbName
+					defer session.Close()
+					err = session.addIndex(tbName, name)
+				}
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	for _, table := range tables {
+		var oriTable *core.Table
+		for _, structTable := range structTables {
+			if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) {
+				oriTable = structTable
+				break
+			}
+		}
+
+		if oriTable == nil {
+			//engine.LogWarnf("Table %s has no struct to mapping it", table.Name)
+			continue
+		}
+
+		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)
+			}
+		}
+	}
+	return nil
+}

+ 137 - 0
vendor/github.com/go-xorm/xorm/session_sum.go

@@ -0,0 +1,137 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import "database/sql"
+
+// Count counts the records. bean's non-empty fields
+// are conditions.
+func (session *Session) Count(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if session.Statement.RawSQL == "" {
+		sqlStr, args = session.Statement.genCountSQL(bean)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	var err error
+	var total int64
+	if session.IsAutoCommit {
+		err = session.DB().QueryRow(sqlStr, args...).Scan(&total)
+	} else {
+		err = session.Tx.QueryRow(sqlStr, args...).Scan(&total)
+	}
+
+	if err == sql.ErrNoRows || err == nil {
+		return total, nil
+	}
+
+	return 0, err
+}
+
+// Sum call sum some column. bean's non-empty fields are conditions.
+func (session *Session) Sum(bean interface{}, columnName string) (float64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if len(session.Statement.RawSQL) == 0 {
+		sqlStr, args = session.Statement.genSumSQL(bean, columnName)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	var err error
+	var res float64
+	if session.IsAutoCommit {
+		err = session.DB().QueryRow(sqlStr, args...).Scan(&res)
+	} else {
+		err = session.Tx.QueryRow(sqlStr, args...).Scan(&res)
+	}
+
+	if err == sql.ErrNoRows || err == nil {
+		return res, nil
+	}
+	return 0, err
+}
+
+// Sums call sum some columns. bean's non-empty fields are conditions.
+func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if len(session.Statement.RawSQL) == 0 {
+		sqlStr, args = session.Statement.genSumSQL(bean, columnNames...)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	var err error
+	var res = make([]float64, len(columnNames), len(columnNames))
+	if session.IsAutoCommit {
+		err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res)
+	} else {
+		err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res)
+	}
+
+	if err == sql.ErrNoRows || err == nil {
+		return res, nil
+	}
+	return nil, err
+}
+
+// SumsInt sum specify columns and return as []int64 instead of []float64
+func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if len(session.Statement.RawSQL) == 0 {
+		sqlStr, args = session.Statement.genSumSQL(bean, columnNames...)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	var err error
+	var res = make([]int64, len(columnNames), len(columnNames))
+	if session.IsAutoCommit {
+		err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res)
+	} else {
+		err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res)
+	}
+
+	if err == sql.ErrNoRows || err == nil {
+		return res, nil
+	}
+	return nil, err
+}

+ 83 - 0
vendor/github.com/go-xorm/xorm/session_tx.go

@@ -0,0 +1,83 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+// Begin a transaction
+func (session *Session) Begin() error {
+	if session.IsAutoCommit {
+		tx, err := session.DB().Begin()
+		if err != nil {
+			return err
+		}
+		session.IsAutoCommit = false
+		session.IsCommitedOrRollbacked = false
+		session.Tx = tx
+		session.saveLastSQL("BEGIN TRANSACTION")
+	}
+	return nil
+}
+
+// Rollback When using transaction, you can rollback if any error
+func (session *Session) Rollback() error {
+	if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
+		session.saveLastSQL(session.Engine.dialect.RollBackStr())
+		session.IsCommitedOrRollbacked = true
+		return session.Tx.Rollback()
+	}
+	return nil
+}
+
+// Commit When using transaction, Commit will commit all operations.
+func (session *Session) Commit() error {
+	if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
+		session.saveLastSQL("COMMIT")
+		session.IsCommitedOrRollbacked = true
+		var err error
+		if err = session.Tx.Commit(); err == nil {
+			// handle processors after tx committed
+
+			closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
+
+				if closuresPtr != nil {
+					for _, closure := range *closuresPtr {
+						closure(bean)
+					}
+				}
+			}
+
+			for bean, closuresPtr := range session.afterInsertBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
+					processor.AfterInsert()
+				}
+			}
+			for bean, closuresPtr := range session.afterUpdateBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
+					processor.AfterUpdate()
+				}
+			}
+			for bean, closuresPtr := range session.afterDeleteBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
+					processor.AfterDelete()
+				}
+			}
+			cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
+				if len(*slices) > 0 {
+					*slices = make(map[interface{}]*[]func(interface{}), 0)
+				}
+			}
+			cleanUpFunc(&session.afterInsertBeans)
+			cleanUpFunc(&session.afterUpdateBeans)
+			cleanUpFunc(&session.afterDeleteBeans)
+		}
+		return err
+	}
+	return nil
+}

+ 356 - 0
vendor/github.com/go-xorm/xorm/session_update.go

@@ -0,0 +1,356 @@
+// Copyright 2016 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/go-xorm/builder"
+	"github.com/go-xorm/core"
+)
+
+func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
+	if session.Statement.RefTable == nil ||
+		session.Tx != nil {
+		return ErrCacheFailed
+	}
+
+	oldhead, newsql := session.Statement.convertUpdateSQL(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+	for _, filter := range session.Engine.dialect.Filters() {
+		newsql = filter.Do(newsql, session.Engine.dialect, session.Statement.RefTable)
+	}
+	session.Engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql)
+
+	var nStart int
+	if len(args) > 0 {
+		if strings.Index(sqlStr, "?") > -1 {
+			nStart = strings.Count(oldhead, "?")
+		} else {
+			// only for pq, TODO: if any other databse?
+			nStart = strings.Count(oldhead, "$")
+		}
+	}
+	table := session.Statement.RefTable
+	cacher := session.Engine.getCacher2(table)
+	tableName := session.Statement.TableName()
+	session.Engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
+	if err != nil {
+		rows, err := session.DB().Query(newsql, args[nStart:]...)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		ids = make([]core.PK, 0)
+		for rows.Next() {
+			var res = make([]string, len(table.PrimaryKeys))
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return err
+			}
+			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+			for i, col := range table.PKColumns() {
+				if col.SQLType.IsNumeric() {
+					n, err := strconv.ParseInt(res[i], 10, 64)
+					if err != nil {
+						return err
+					}
+					pk[i] = n
+				} else if col.SQLType.IsText() {
+					pk[i] = res[i]
+				} else {
+					return errors.New("not supported")
+				}
+			}
+
+			ids = append(ids, pk)
+		}
+		session.Engine.logger.Debug("[cacheUpdate] find updated id", ids)
+	} /*else {
+	    session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
+	    cacher.DelIds(tableName, genSqlKey(newsql, args))
+	}*/
+
+	for _, id := range ids {
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		if bean := cacher.GetBean(tableName, sid); bean != nil {
+			sqls := splitNNoCase(sqlStr, "where", 2)
+			if len(sqls) == 0 || len(sqls) > 2 {
+				return ErrCacheFailed
+			}
+
+			sqls = splitNNoCase(sqls[0], "set", 2)
+			if len(sqls) != 2 {
+				return ErrCacheFailed
+			}
+			kvs := strings.Split(strings.TrimSpace(sqls[1]), ",")
+			for idx, kv := range kvs {
+				sps := strings.SplitN(kv, "=", 2)
+				sps2 := strings.Split(sps[0], ".")
+				colName := sps2[len(sps2)-1]
+				if strings.Contains(colName, "`") {
+					colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1))
+				} else if strings.Contains(colName, session.Engine.QuoteStr()) {
+					colName = strings.TrimSpace(strings.Replace(colName, session.Engine.QuoteStr(), "", -1))
+				} else {
+					session.Engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName)
+					return ErrCacheFailed
+				}
+
+				if col := table.GetColumn(colName); col != nil {
+					fieldValue, err := col.ValueOf(bean)
+					if err != nil {
+						session.Engine.logger.Error(err)
+					} else {
+						session.Engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
+						if col.IsVersion && session.Statement.checkVersion {
+							fieldValue.SetInt(fieldValue.Int() + 1)
+						} else {
+							fieldValue.Set(reflect.ValueOf(args[idx]))
+						}
+					}
+				} else {
+					session.Engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's",
+						colName, table.Name)
+				}
+			}
+
+			session.Engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean)
+			cacher.PutBean(tableName, sid, bean)
+		}
+	}
+	session.Engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName)
+	cacher.ClearIds(tableName)
+	return nil
+}
+
+// Update records, bean's non-empty fields are updated contents,
+// condiBean' non-empty filds are conditions
+// CAUTION:
+//        1.bool will defaultly be updated content nor conditions
+//         You should call UseBool if you have bool to use.
+//        2.float32 & float64 may be not inexact as conditions
+func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	v := rValue(bean)
+	t := v.Type()
+
+	var colNames []string
+	var args []interface{}
+
+	// handle before update processors
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
+	if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok {
+		processor.BeforeUpdate()
+	}
+	// --
+
+	var err error
+	var isMap = t.Kind() == reflect.Map
+	var isStruct = t.Kind() == reflect.Struct
+	if isStruct {
+		session.Statement.setRefValue(v)
+
+		if len(session.Statement.TableName()) <= 0 {
+			return 0, ErrTableNotFound
+		}
+
+		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)
+		} else {
+			colNames, args, err = genCols(session.Statement.RefTable, session, bean, true, true)
+			if err != nil {
+				return 0, err
+			}
+		}
+	} else if isMap {
+		colNames = make([]string, 0)
+		args = make([]interface{}, 0)
+		bValue := reflect.Indirect(reflect.ValueOf(bean))
+
+		for _, v := range bValue.MapKeys() {
+			colNames = append(colNames, session.Engine.Quote(v.String())+" = ?")
+			args = append(args, bValue.MapIndex(v).Interface())
+		}
+	} else {
+		return 0, ErrParamsType
+	}
+
+	table := session.Statement.RefTable
+
+	if session.Statement.UseAutoTime && table != nil && table.Updated != "" {
+		colNames = append(colNames, session.Engine.Quote(table.Updated)+" = ?")
+		col := table.UpdatedColumn()
+		val, t := session.Engine.NowTime2(col.SQLType.Name)
+		args = append(args, val)
+
+		var colName = col.Name
+		if isStruct {
+			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+				col := table.GetColumn(colName)
+				setColumnTime(bean, col, t)
+			})
+		}
+	}
+
+	//for update action to like "column = column + ?"
+	incColumns := session.Statement.getInc()
+	for _, v := range incColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" + ?")
+		args = append(args, v.arg)
+	}
+	//for update action to like "column = column - ?"
+	decColumns := session.Statement.getDec()
+	for _, v := range decColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" - ?")
+		args = append(args, v.arg)
+	}
+	//for update action to like "column = expression"
+	exprColumns := session.Statement.getExpr()
+	for _, v := range exprColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+v.expr)
+	}
+
+	session.Statement.processIDParam()
+
+	var autoCond builder.Cond
+	if !session.Statement.noAutoCondition && len(condiBean) > 0 {
+		var err error
+		autoCond, err = session.Statement.buildConds(session.Statement.RefTable, condiBean[0], true, true, false, true, false)
+		if err != nil {
+			return 0, err
+		}
+	}
+
+	st := session.Statement
+	defer session.resetStatement()
+
+	var sqlStr string
+	var condArgs []interface{}
+	var condSQL string
+	cond := session.Statement.cond.And(autoCond)
+
+	var doIncVer = (table != nil && table.Version != "" && session.Statement.checkVersion)
+	var verValue *reflect.Value
+	if doIncVer {
+		verValue, err = table.VersionColumn().ValueOf(bean)
+		if err != nil {
+			return 0, err
+		}
+
+		cond = cond.And(builder.Eq{session.Engine.Quote(table.Version): verValue.Interface()})
+		colNames = append(colNames, session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1")
+	}
+
+	condSQL, condArgs, _ = builder.ToSQL(cond)
+	if len(condSQL) > 0 {
+		condSQL = "WHERE " + condSQL
+	}
+
+	if st.OrderStr != "" {
+		condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
+	}
+
+	// TODO: Oracle support needed
+	var top string
+	if st.LimitN > 0 {
+		if st.Engine.dialect.DBType() == core.MYSQL {
+			condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+		} else if st.Engine.dialect.DBType() == core.SQLITE {
+			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+			cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",
+				session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...))
+			condSQL, condArgs, _ = builder.ToSQL(cond)
+			if len(condSQL) > 0 {
+				condSQL = "WHERE " + condSQL
+			}
+		} else if st.Engine.dialect.DBType() == core.POSTGRES {
+			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
+			cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
+				session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...))
+			condSQL, condArgs, _ = builder.ToSQL(cond)
+			if len(condSQL) > 0 {
+				condSQL = "WHERE " + condSQL
+			}
+		} else if st.Engine.dialect.DBType() == core.MSSQL {
+			top = fmt.Sprintf("top (%d) ", st.LimitN)
+		}
+	}
+
+	sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v",
+		top,
+		session.Engine.Quote(session.Statement.TableName()),
+		strings.Join(colNames, ", "),
+		condSQL)
+
+	res, err := session.exec(sqlStr, append(args, condArgs...)...)
+	if err != nil {
+		return 0, err
+	} else if doIncVer {
+		if verValue != nil && verValue.IsValid() && verValue.CanSet() {
+			verValue.SetInt(verValue.Int() + 1)
+		}
+	}
+
+	if table != nil {
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			cacher.ClearIds(session.Statement.TableName())
+			cacher.ClearBeans(session.Statement.TableName())
+		}
+	}
+
+	// handle after update processors
+	if session.IsAutoCommit {
+		for _, closure := range session.afterClosures {
+			closure(bean)
+		}
+		if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
+			session.Engine.logger.Debug("[event]", session.Statement.TableName(), " has after update processor")
+			processor.AfterUpdate()
+		}
+	} else {
+		lenAfterClosures := len(session.afterClosures)
+		if lenAfterClosures > 0 {
+			if value, has := session.afterUpdateBeans[bean]; has && value != nil {
+				*value = append(*value, session.afterClosures...)
+			} else {
+				afterClosures := make([]func(interface{}), lenAfterClosures)
+				copy(afterClosures, session.afterClosures)
+				// FIXME: if bean is a map type, it will panic because map cannot be as map key
+				session.afterUpdateBeans[bean] = &afterClosures
+			}
+
+		} else {
+			if _, ok := interface{}(bean).(AfterUpdateProcessor); ok {
+				session.afterUpdateBeans[bean] = nil
+			}
+		}
+	}
+	cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
+	// --
+
+	return res.RowsAffected()
+}

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

@@ -1,20 +0,0 @@
-// Copyright 2015 The Xorm Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xorm
-
-import (
-	"github.com/go-xorm/core"
-)
-
-// func init() {
-// 	core.RegisterDriver("sqlite3", &sqlite3Driver{})
-// }
-
-type sqlite3Driver struct {
-}
-
-func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
-	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
-}

文件差异内容过多而无法显示
+ 241 - 276
vendor/github.com/go-xorm/xorm/statement.go


+ 45 - 19
vendor/github.com/go-xorm/xorm/syslogger.go

@@ -13,51 +13,77 @@ import (
 	"github.com/go-xorm/core"
 )
 
+var _ core.ILogger = &SyslogLogger{}
+
+// SyslogLogger will be depricated
 type SyslogLogger struct {
-	w *syslog.Writer
+	w       *syslog.Writer
+	showSQL bool
 }
 
+// NewSyslogLogger implements core.ILogger
 func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 	return &SyslogLogger{w: w}
 }
 
-func (s *SyslogLogger) Debug(v ...interface{}) (err error) {
-	return s.w.Debug(fmt.Sprint(v...))
+// Debug log content as Debug
+func (s *SyslogLogger) Debug(v ...interface{}) {
+	s.w.Debug(fmt.Sprint(v...))
 }
 
-func (s *SyslogLogger) Debugf(format string, v ...interface{}) (err error) {
-	return s.w.Debug(fmt.Sprintf(format, v...))
+// Debugf log content as Debug and format
+func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
+	s.w.Debug(fmt.Sprintf(format, v...))
 }
 
-func (s *SyslogLogger) Err(v ...interface{}) (err error) {
-	return s.w.Err(fmt.Sprint(v...))
+// Error log content as Error
+func (s *SyslogLogger) Error(v ...interface{}) {
+	s.w.Err(fmt.Sprint(v...))
 }
 
-func (s *SyslogLogger) Errf(format string, v ...interface{}) (err error) {
-	return s.w.Err(fmt.Sprintf(format, v...))
+// Errorf log content as Errorf and format
+func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
+	s.w.Err(fmt.Sprintf(format, v...))
 }
 
-func (s *SyslogLogger) Info(v ...interface{}) (err error) {
-	return s.w.Info(fmt.Sprint(v...))
+// Info log content as Info
+func (s *SyslogLogger) Info(v ...interface{}) {
+	s.w.Info(fmt.Sprint(v...))
 }
 
-func (s *SyslogLogger) Infof(format string, v ...interface{}) (err error) {
-	return s.w.Info(fmt.Sprintf(format, v...))
+// Infof log content as Infof and format
+func (s *SyslogLogger) Infof(format string, v ...interface{}) {
+	s.w.Info(fmt.Sprintf(format, v...))
 }
 
-func (s *SyslogLogger) Warning(v ...interface{}) (err error) {
-	return s.w.Warning(fmt.Sprint(v...))
+// Warn log content as Warn
+func (s *SyslogLogger) Warn(v ...interface{}) {
+	s.w.Warning(fmt.Sprint(v...))
 }
 
-func (s *SyslogLogger) Warningf(format string, v ...interface{}) (err error) {
-	return s.w.Warning(fmt.Sprintf(format, v...))
+// Warnf log content as Warnf and format
+func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
+	s.w.Warning(fmt.Sprintf(format, v...))
 }
 
+// Level shows log level
 func (s *SyslogLogger) Level() core.LogLevel {
 	return core.LOG_UNKNOWN
 }
 
 // SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
-func (s *SyslogLogger) SetLevel(l core.LogLevel) (err error) {
-	return fmt.Errorf("unable to set syslog level")
+func (s *SyslogLogger) SetLevel(l core.LogLevel) {}
+
+// ShowSQL set if logging SQL
+func (s *SyslogLogger) ShowSQL(show ...bool) {
+	if len(show) == 0 {
+		s.showSQL = true
+		return
+	}
+	s.showSQL = show[0]
+}
+
+// IsShowSQL if logging SQL
+func (s *SyslogLogger) IsShowSQL() bool {
+	return s.showSQL
 }

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

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

+ 12 - 0
vendor/github.com/go-xorm/xorm/types.go

@@ -0,0 +1,12 @@
+package xorm
+
+import (
+	"reflect"
+
+	"github.com/go-xorm/core"
+)
+
+var (
+	ptrPkType = reflect.TypeOf(&core.PK{})
+	pkType    = reflect.TypeOf(core.PK{})
+)

+ 11 - 9
vendor/github.com/go-xorm/xorm/xorm.go

@@ -5,7 +5,6 @@
 package xorm
 
 import (
-	"errors"
 	"fmt"
 	"os"
 	"reflect"
@@ -17,7 +16,8 @@ import (
 )
 
 const (
-	Version string = "0.4.5.0204"
+	// Version show the xorm's version
+	Version string = "0.6.2.0326"
 )
 
 func regDrvsNDialects() bool {
@@ -31,6 +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{} }},
 		"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{} }},
@@ -49,13 +50,13 @@ func close(engine *Engine) {
 	engine.Close()
 }
 
-// new a db manager according to the parameter. Currently support four
+// NewEngine new a db manager according to the parameter. Currently support four
 // drivers
 func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	regDrvsNDialects()
 	driver := core.QueryDriver(driverName)
 	if driver == nil {
-		return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
+		return nil, fmt.Errorf("Unsupported driver name: %v", driverName)
 	}
 
 	uri, err := driver.Parse(driverName, dataSourceName)
@@ -65,7 +66,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 
 	dialect := core.QueryDialect(uri.DbType)
 	if dialect == nil {
-		return nil, errors.New(fmt.Sprintf("Unsupported dialect type: %v", uri.DbType))
+		return nil, fmt.Errorf("Unsupported dialect type: %v", uri.DbType)
 	}
 
 	db, err := core.Open(driverName, dataSourceName)
@@ -84,12 +85,13 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 		Tables:        make(map[reflect.Type]*core.Table),
 		mutex:         &sync.RWMutex{},
 		TagIdentifier: "xorm",
-		Logger:        NewSimpleLogger(os.Stdout),
 		TZLocation:    time.Local,
+		tagHandlers:   defaultTagHandlers,
 	}
 
-	engine.dialect.SetLogger(engine.Logger)
-
+	logger := NewSimpleLogger(os.Stdout)
+	logger.SetLevel(core.LOG_INFO)
+	engine.SetLogger(logger)
 	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
 
 	runtime.SetFinalizer(engine, close)
@@ -97,7 +99,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	return engine, nil
 }
 
-// clone an engine
+// Clone clone an engine
 func (engine *Engine) Clone() (*Engine, error) {
 	return NewEngine(engine.DriverName(), engine.DataSourceName())
 }

+ 22 - 0
vendor/vendor.json

@@ -332,6 +332,28 @@
 			"revision": "9dee4ca50b83acdf57a35fb9e6fb4be640afa2f3",
 			"revisionTime": "2017-03-27T11:30:21Z"
 		},
+		{
+			"checksumSHA1": "HHB+Jna1wv0cXLxtCyOnQqFwvn4=",
+			"path": "github.com/go-xorm/builder",
+			"revision": "c6e604e9c7b7461715091e14ad0c242ec44c26e4",
+			"revisionTime": "2017-02-24T04:30:50Z"
+		},
+		{
+			"checksumSHA1": "vt2CGANHLNXPAZ01ve3UlsgQ0uU=",
+			"path": "github.com/go-xorm/core",
+			"revision": "e8409d73255791843585964791443dbad877058c",
+			"revisionTime": "2017-03-17T12:25:07Z"
+		},
+		{
+			"path": "github.com/go-xorm/xor,m",
+			"revision": ""
+		},
+		{
+			"checksumSHA1": "xkwhf97yNV6tFwrOHCPeWtKW39E=",
+			"path": "github.com/go-xorm/xorm",
+			"revision": "6687a2b4e824f4d87f2d65060ec5cb0d896dff1e",
+			"revisionTime": "2017-03-30T09:59:41Z"
+		},
 		{
 			"checksumSHA1": "B4bk7vdV9aD7AhrtATXfgEacdqE=",
 			"path": "github.com/gorilla/websocket",

部分文件因为文件数量过多而无法显示