Browse Source

tech: updated xorm libs

Torkel Ödegaard 8 years ago
parent
commit
a7babfb7cf
91 changed files with 8372 additions and 4030 deletions
  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)
 	e.log.Debug("getEngine", "connection", cnnstr)
 
 
 	engine, err := xorm.NewEngine("mysql", cnnstr)
 	engine, err := xorm.NewEngine("mysql", cnnstr)
-	engine.SetMaxConns(10)
+	engine.SetMaxOpenConns(10)
 	engine.SetMaxIdleConns(10)
 	engine.SetMaxIdleConns(10)
 	if err != nil {
 	if err != nil {
 		return err
 		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.
 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
 # Open
 ```Go
 ```Go
 db, _ := core.Open(db, connstr)
 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
 // database column
 type Column struct {
 type Column struct {
 	Name            string
 	Name            string
+	TableName       string
 	FieldName       string
 	FieldName       string
 	SQLType         SQLType
 	SQLType         SQLType
 	Length          int
 	Length          int
 	Length2         int
 	Length2         int
 	Nullable        bool
 	Nullable        bool
 	Default         string
 	Default         string
-	Indexes         map[string]bool
+	Indexes         map[string]int
 	IsPrimaryKey    bool
 	IsPrimaryKey    bool
 	IsAutoIncrement bool
 	IsAutoIncrement bool
 	MapType         int
 	MapType         int
@@ -31,7 +32,6 @@ type Column struct {
 	IsDeleted       bool
 	IsDeleted       bool
 	IsCascade       bool
 	IsCascade       bool
 	IsVersion       bool
 	IsVersion       bool
-	fieldPath       []string
 	DefaultIsEmpty  bool
 	DefaultIsEmpty  bool
 	EnumOptions     map[string]int
 	EnumOptions     map[string]int
 	SetOptions      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 {
 func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
 	return &Column{
 	return &Column{
 		Name:            name,
 		Name:            name,
+		TableName:       "",
 		FieldName:       fieldName,
 		FieldName:       fieldName,
 		SQLType:         sqlType,
 		SQLType:         sqlType,
 		Length:          len1,
 		Length:          len1,
 		Length2:         len2,
 		Length2:         len2,
 		Nullable:        nullable,
 		Nullable:        nullable,
 		Default:         "",
 		Default:         "",
-		Indexes:         make(map[string]bool),
+		Indexes:         make(map[string]int),
 		IsPrimaryKey:    false,
 		IsPrimaryKey:    false,
 		IsAutoIncrement: false,
 		IsAutoIncrement: false,
 		MapType:         TWOSIDES,
 		MapType:         TWOSIDES,
@@ -57,7 +58,6 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable
 		IsDeleted:       false,
 		IsDeleted:       false,
 		IsCascade:       false,
 		IsCascade:       false,
 		IsVersion:       false,
 		IsVersion:       false,
-		fieldPath:       nil,
 		DefaultIsEmpty:  false,
 		DefaultIsEmpty:  false,
 		EnumOptions:     make(map[string]int),
 		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) {
 func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 	var fieldValue reflect.Value
 	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 {
 	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)
 		fieldValue = dataStruct.MapIndex(keyValue)
 		return &fieldValue, nil
 		return &fieldValue, nil
 	} else if dataStruct.Type().Kind() == reflect.Interface {
 	} else if dataStruct.Type().Kind() == reflect.Interface {
@@ -132,19 +130,19 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 		dataStruct = &structValue
 		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++ {
 	for i := 0; i < level-1; i++ {
 		if !fieldValue.IsValid() {
 		if !fieldValue.IsValid() {
 			break
 			break
 		}
 		}
 		if fieldValue.Kind() == reflect.Struct {
 		if fieldValue.Kind() == reflect.Struct {
-			fieldValue = fieldValue.FieldByName(col.fieldPath[i+1])
+			fieldValue = fieldValue.FieldByName(fieldPath[i+1])
 		} else if fieldValue.Kind() == reflect.Ptr {
 		} else if fieldValue.Kind() == reflect.Ptr {
 			if fieldValue.IsNil() {
 			if fieldValue.IsNil() {
 				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
 				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
 			}
 			}
-			fieldValue = fieldValue.Elem().FieldByName(col.fieldPath[i+1])
+			fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
 		} else {
 		} else {
 			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
 			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"
 	"database/sql/driver"
 	"database/sql/driver"
 	"errors"
 	"errors"
+	"fmt"
 	"reflect"
 	"reflect"
 	"regexp"
 	"regexp"
-	"sync"
 )
 )
 
 
 func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
 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
 		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 {
 	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 "?"
 	})
 	})
-	return query, args, nil
+
+	return query, args, err
 }
 }
 
 
 func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
 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...)
 	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 {
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 	rows, err := db.Query(query, args...)
 	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 {
 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...)
 	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 {
 type EmptyScanner struct {
 }
 }
 
 
@@ -373,185 +272,6 @@ func (EmptyScanner) Scan(src interface{}) error {
 	return nil
 	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 {
 type Tx struct {
 	*sql.Tx
 	*sql.Tx
 	Mapper IMapper
 	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
 	Laddr   string
 	Raddr   string
 	Raddr   string
 	Timeout time.Duration
 	Timeout time.Duration
+	Schema  string
 }
 }
 
 
 // a dialect is a driver's wrapper
 // a dialect is a driver's wrapper
@@ -84,7 +85,7 @@ type Base struct {
 	dialect        Dialect
 	dialect        Dialect
 	driverName     string
 	driverName     string
 	dataSourceName string
 	dataSourceName string
-	Logger         ILogger
+	logger         ILogger
 	*Uri
 	*Uri
 }
 }
 
 
@@ -93,7 +94,7 @@ func (b *Base) DB() *DB {
 }
 }
 
 
 func (b *Base) SetLogger(logger ILogger) {
 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 {
 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) {
 func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
+	db.LogSQL(query, args)
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -277,17 +276,32 @@ func (b *Base) ForUpdateSql(query string) string {
 	return query + " FOR UPDATE"
 	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 (
 var (
-	dialects = map[DbType]func() Dialect{}
+	dialects = map[string]func() Dialect{}
 )
 )
 
 
+// RegisterDialect register database dialect
 func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
 func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
 	if dialectFunc == nil {
 	if dialectFunc == nil {
 		panic("core: Register dialect is 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 {
 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 (
 var (
 	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
 	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
 	ErrNoStructPointer = errors.New("mp should be a struct'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 (
 const (
 	// !nashtsai! following level also match syslog.Priority value
 	// !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_WARNING
-	LOG_INFO LogLevel = iota + 6
-	LOG_DEBUG
+	LOG_ERR
+	LOG_OFF
+	LOG_UNKNOWN
 )
 )
 
 
 // logger interface
 // logger interface
 type ILogger 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
 	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 {
 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
 	return nil
 }
 }
 
 
 func (table *Table) GetColumnIdx(name string, idx int) *Column {
 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
 	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 {
 func (s *SQLType) IsJson() bool {
-	return s.Name == Json
+	return s.Name == Json || s.Name == Jsonb
 }
 }
 
 
 var (
 var (
@@ -105,7 +105,8 @@ var (
 	Serial    = "SERIAL"
 	Serial    = "SERIAL"
 	BigSerial = "BIGSERIAL"
 	BigSerial = "BIGSERIAL"
 
 
-	Json = "JSON"
+	Json  = "JSON"
+	Jsonb = "JSONB"
 
 
 	SqlTypes = map[string]int{
 	SqlTypes = map[string]int{
 		Bit:       NUMERIC_TYPE,
 		Bit:       NUMERIC_TYPE,
@@ -116,9 +117,10 @@ var (
 		Integer:   NUMERIC_TYPE,
 		Integer:   NUMERIC_TYPE,
 		BigInt:    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,
 		Char:       TEXT_TYPE,
 		Varchar:    TEXT_TYPE,
 		Varchar:    TEXT_TYPE,
@@ -205,6 +207,7 @@ var (
 	StringType = reflect.TypeOf(c_EMPTY_STRING)
 	StringType = reflect.TypeOf(c_EMPTY_STRING)
 	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
 	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
 	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
 	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
+	BytesType  = reflect.SliceOf(ByteType)
 
 
 	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
 	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
 )
 )
@@ -235,6 +238,7 @@ var (
 	PtrTimeType = reflect.PtrTo(TimeType)
 	PtrTimeType = reflect.PtrTo(TimeType)
 )
 )
 
 
+// Type2SQLType generate SQLType acorrding Go's type
 func Type2SQLType(t reflect.Type) (st SQLType) {
 func Type2SQLType(t reflect.Type) (st SQLType) {
 	switch k := t.Kind(); k {
 	switch k := t.Kind(); k {
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
 	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}
 			st = SQLType{Text, 0, 0}
 		}
 		}
 	case reflect.Ptr:
 	case reflect.Ptr:
-		st, _ = ptrType2SQLType(t)
+		st = Type2SQLType(t.Elem())
 	default:
 	default:
 		st = SQLType{Text, 0, 0}
 		st = SQLType{Text, 0, 0}
 	}
 	}
 	return
 	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
 // default sql type change to go types
 func SQLType2Type(st SQLType) reflect.Type {
 func SQLType2Type(st SQLType) reflect.Type {
 	name := strings.ToUpper(st.Name)
 	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)
 * [fork a repo](https://help.github.com/articles/fork-a-repo)
 * [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
 * [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
 ### Sign your codes with comments
 ```
 ```
 // !<you github id>! your 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.
 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
 # Features
 
 
@@ -26,6 +28,7 @@ Xorm is a simple and powerful ORM for Go.
 
 
 * Optimistic Locking support
 * Optimistic Locking support
 
 
+* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder)
 
 
 # Drivers Support
 # 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/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 
 
-* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
-
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 
 
-* ql: [github.com/cznic/ql](https://github.com/cznic/ql) (experiment)
-
 # Changelog
 # 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**
 * **v0.4.4**
     * ql database expriment support
     * ql database expriment support
     * tidb 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
     * select ForUpdate support
     * many bugs fixed
     * 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
 # Installation
 
 
-If you have [gopm](https://github.com/gpmgo/gopm) installed,
-
-	gopm get github.com/go-xorm/xorm
-
-Or
-
 	go get github.com/go-xorm/xorm
 	go get github.com/go-xorm/xorm
 
 
 # Documents
 # Documents
@@ -124,7 +123,7 @@ results, err := engine.Query("select * from user")
 affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
 affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
 ```
 ```
 
 
-* Insert one or multipe records to database
+* Insert one or multiple records to database
 
 
 ```Go
 ```Go
 affected, err := engine.Insert(&user)
 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
 // 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
 ```Go
 err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
 err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
@@ -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
 ```Go
 affected, err := engine.Id(1).Update(&user)
 affected, err := engine.Id(1).Update(&user)
@@ -201,7 +200,7 @@ affected, err := engine.Update(&user, &User{Name:name})
 // UPDATE user SET ... Where name = ?
 // UPDATE user SET ... Where name = ?
 
 
 var ids = []int64{1, 2, 3}
 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 (?, ?, ?)
 // UPDATE user SET ... Where id IN (?, ?, ?)
 
 
 // force update indicated columns by Cols
 // 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 = ?
 // 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
 ```Go
 affected, err := engine.Where(...).Delete(&user)
 affected, err := engine.Where(...).Delete(&user)
 // DELETE FROM user Where ...
 // DELETE FROM user Where ...
+affected, err := engine.Id(2).Delete(&user)
 ```
 ```
 
 
 * Count records
 * Count records
@@ -230,6 +230,13 @@ counts, err := engine.Count(&user)
 // SELECT count(*) AS total FROM 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
 # Cases
 
 
 * [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
 * [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库. 通过它可以使数据库操作非常简便。
 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数据库驱动和对应的数据库如下:
 目前支持的Go数据库驱动和对应的数据库如下:
@@ -48,10 +52,24 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 
 * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
 * 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**
 * **v0.4.4**
     * Tidb 数据库支持
     * Tidb 数据库支持
     * QL 试验性支持
     * QL 试验性支持
@@ -59,21 +77,10 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
     * ForUpdate 支持
     * ForUpdate 支持
     * bug修正
     * bug修正
 
 
-* **v0.4.3**
-    * Json 字段类型支持
-    * oracle实验性支持
-    * bug修正
-
 [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 
 
 ## 安装
 ## 安装
 
 
-推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
-
-	gopm get github.com/go-xorm/xorm
-
-或者您也可以使用go工具进行安装:
-
 	go get github.com/go-xorm/xorm
 	go get github.com/go-xorm/xorm
 
 
 ## 文档
 ## 文档
@@ -226,6 +233,13 @@ counts, err := engine.Count(&user)
 // SELECT count(*) AS total FROM 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)
 * [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"
 	"github.com/go-xorm/core"
 )
 )
 
 
-// func init() {
-// 	RegisterDialect("mssql", &mssql{})
-// }
-
 var (
 var (
 	mssqlReservedWords = map[string]bool{
 	mssqlReservedWords = map[string]bool{
 		"ADD":                    true,
 		"ADD":                    true,
@@ -247,10 +243,13 @@ func (db *mssql) SqlType(c *core.Column) string {
 		c.Length = 7
 		c.Length = 7
 	case core.MediumInt:
 	case core.MediumInt:
 		res = core.Int
 		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:
 	case core.Double:
 		res = core.Real
 		res = core.Real
+	case core.Uuid:
+		res = core.Varchar
+		c.Length = 40
 	default:
 	default:
 		res = t
 		res = t
 	}
 	}
@@ -259,8 +258,9 @@ func (db *mssql) SqlType(c *core.Column) string {
 		return core.Int
 		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 {
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
 	} 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) {
 func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 	args := []interface{}{}
 	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...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	if err != nil {
@@ -347,32 +350,38 @@ where a.object_id=object_id('` + tableName + `')`
 	cols := make(map[string]*core.Column)
 	cols := make(map[string]*core.Column)
 	colSeq := make([]string, 0)
 	colSeq := make([]string, 0)
 	for rows.Next() {
 	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 {
 		if err != nil {
 			return nil, nil, err
 			return nil, nil, err
 		}
 		}
 
 
 		col := new(core.Column)
 		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.Name = strings.Trim(name, "` ")
-
+		col.Nullable = nullable
+		col.Default = vdefault
 		ct := strings.ToUpper(ctype)
 		ct := strings.ToUpper(ctype)
+		if ct == "DECIMAL" {
+			col.Length = precision
+			col.Length2 = scale
+		} else {
+			col.Length = maxLen
+		}
 		switch ct {
 		switch ct {
 		case "DATETIMEOFFSET":
 		case "DATETIMEOFFSET":
-			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 		case "NVARCHAR":
 		case "NVARCHAR":
-			col.SQLType = core.SQLType{core.NVarchar, 0, 0}
+			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
 		case "IMAGE":
 		case "IMAGE":
-			col.SQLType = core.SQLType{core.VarBinary, 0, 0}
+			col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
 		default:
 		default:
 			if _, ok := core.SqlTypes[ct]; ok {
 			if _, ok := core.SqlTypes[ct]; ok {
-				col.SQLType = core.SQLType{ct, 0, 0}
+				col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
 			} else {
 			} 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) {
 func (db *mssql) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := `select name from sysobjects where xtype ='U'`
 	s := `select name from sysobjects where xtype ='U'`
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	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
 AND IXCS.COLUMN_ID=C.COLUMN_ID
 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 `
 `
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	if err != nil {
@@ -459,7 +470,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 		colName = strings.Trim(colName, "` ")
 		colName = strings.Trim(colName, "` ")
 
 
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			indexName = indexName[5+len(tableName) : len(indexName)]
+			indexName = indexName[5+len(tableName):]
 		}
 		}
 
 
 		var index *core.Index
 		var index *core.Index
@@ -516,3 +527,25 @@ func (db *mssql) ForUpdateSql(query string) string {
 func (db *mssql) Filters() []core.Filter {
 func (db *mssql) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 }
 }
+
+type odbcDriver struct {
+}
+
+func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	kv := strings.Split(dataSourceName, ";")
+	var dbName string
+
+	for _, c := range kv {
+		vv := strings.Split(strings.TrimSpace(c), "=")
+		if len(vv) == 2 {
+			switch strings.ToLower(vv[0]) {
+			case "database":
+				dbName = vv[1]
+			}
+		}
+	}
+	if dbName == "" {
+		return nil, errors.New("no db name provided")
+	}
+	return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
+}

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

+ 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 (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
 )
 )
 
 
-// func init() {
-// 	RegisterDialect("oracle", &oracle{})
-// }
-
 var (
 var (
 	oracleReservedWords = map[string]bool{
 	oracleReservedWords = map[string]bool{
 		"ACCESS":                    true,
 		"ACCESS":                    true,
@@ -530,8 +527,9 @@ func (db *oracle) SqlType(c *core.Column) string {
 		res = t
 		res = t
 	}
 	}
 
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
 	if hasLen2 {
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
 	} else if hasLen1 {
@@ -581,14 +579,14 @@ func (db *oracle) DropTableSql(tableName string) string {
 	return fmt.Sprintf("DROP TABLE `%s`", tableName)
 	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
 	var sql string
 	sql = "CREATE TABLE "
 	sql = "CREATE TABLE "
 	if tableName == "" {
 	if tableName == "" {
 		tableName = table.Name
 		tableName = table.Name
 	}
 	}
 
 
-	sql += b.Quote(tableName) + " ("
+	sql += db.Quote(tableName) + " ("
 
 
 	pkList := table.PrimaryKeys
 	pkList := table.PrimaryKeys
 
 
@@ -597,7 +595,7 @@ func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, chars
 		/*if col.IsPrimaryKey && len(pkList) == 1 {
 		/*if col.IsPrimaryKey && len(pkList) == 1 {
 			sql += col.String(b.dialect)
 			sql += col.String(b.dialect)
 		} else {*/
 		} else {*/
-		sql += col.StringNoPk(b)
+		sql += col.StringNoPk(db)
 		//}
 		//}
 		sql = strings.TrimSpace(sql)
 		sql = strings.TrimSpace(sql)
 		sql += ", "
 		sql += ", "
@@ -605,17 +603,17 @@ func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, chars
 
 
 	if len(pkList) > 0 {
 	if len(pkList) > 0 {
 		sql += "PRIMARY KEY ( "
 		sql += "PRIMARY KEY ( "
-		sql += b.Quote(strings.Join(pkList, b.Quote(",")))
+		sql += db.Quote(strings.Join(pkList, db.Quote(",")))
 		sql += " ), "
 		sql += " ), "
 	}
 	}
 
 
 	sql = sql[:len(sql)-2] + ")"
 	sql = sql[:len(sql)-2] + ")"
-	if b.SupportEngine() && storeEngine != "" {
+	if db.SupportEngine() && storeEngine != "" {
 		sql += " ENGINE=" + storeEngine
 		sql += " ENGINE=" + storeEngine
 	}
 	}
-	if b.SupportCharset() {
+	if db.SupportCharset() {
 		if len(charset) == 0 {
 		if len(charset) == 0 {
-			charset = b.URI().Charset
+			charset = db.URI().Charset
 		}
 		}
 		if len(charset) > 0 {
 		if len(charset) > 0 {
 			sql += " DEFAULT CHARSET " + charset
 			sql += " DEFAULT CHARSET " + charset
@@ -637,9 +635,7 @@ func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
 
 
 func (db *oracle) MustDropTable(tableName string) error {
 func (db *oracle) MustDropTable(tableName string) error {
 	sql, args := db.TableCheckSql(tableName)
 	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...)
 	rows, err := db.DB().Query(sql, args...)
 	if err != nil {
 	if err != nil {
@@ -652,9 +648,8 @@ func (db *oracle) MustDropTable(tableName string) error {
 	}
 	}
 
 
 	sql = "Drop Table \"" + tableName + "\""
 	sql = "Drop Table \"" + tableName + "\""
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", sql)
-	}
+	db.LogSQL(sql, args)
+
 	_, err = db.DB().Exec(sql)
 	_, err = db.DB().Exec(sql)
 	return err
 	return err
 }
 }
@@ -669,10 +664,9 @@ func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 		" AND column_name = :2"
 		" AND column_name = :2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -688,11 +682,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
 		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -702,7 +694,7 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 	colSeq := make([]string, 0)
 	colSeq := make([]string, 0)
 	for rows.Next() {
 	for rows.Next() {
 		col := new(core.Column)
 		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 colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
 		var dataLen int
 		var dataLen int
@@ -743,23 +735,23 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 
 
 		switch dt {
 		switch dt {
 		case "VARCHAR2":
 		case "VARCHAR2":
-			col.SQLType = core.SQLType{core.Varchar, len1, len2}
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
 		case "NVARCHAR2":
 		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":
 		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":
 		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":
 		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":
 		case "RAW":
-			col.SQLType = core.SQLType{core.Binary, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
 		case "ROWID":
 		case "ROWID":
-			col.SQLType = core.SQLType{core.Varchar, 18, 0}
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
 		case "AQ$_SUBSCRIBERS":
 		case "AQ$_SUBSCRIBERS":
 			ignore = true
 			ignore = true
 		default:
 		default:
-			col.SQLType = core.SQLType{strings.ToUpper(dt), len1, len2}
+			col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
 		}
 		}
 
 
 		if ignore {
 		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 {
 		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
 		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) {
 func (db *oracle) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := "SELECT table_name FROM user_tables"
 	s := "SELECT table_name FROM user_tables"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -814,11 +804,9 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
 	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"
 		"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...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -856,5 +844,56 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 }
 }
 
 
 func (db *oracle) Filters() []core.Filter {
 func (db *oracle) Filters() []core.Filter {
-	return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{":", 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 (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"net/url"
+	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
 )
 )
 
 
-// func init() {
-// 	RegisterDialect("postgres", &postgres{})
-// }
 // from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
 // from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
 var (
 var (
 	postgresReservedWords = map[string]bool{
 	postgresReservedWords = map[string]bool{
@@ -787,6 +786,11 @@ func (db *postgres) SqlType(c *core.Column) string {
 			return core.Serial
 			return core.Serial
 		}
 		}
 		return core.Integer
 		return core.Integer
+	case core.BigInt:
+		if c.IsAutoIncrement {
+			return core.BigSerial
+		}
+		return core.BigInt
 	case core.Serial, core.BigSerial:
 	case core.Serial, core.BigSerial:
 		c.IsAutoIncrement = true
 		c.IsAutoIncrement = true
 		c.Nullable = false
 		c.Nullable = false
@@ -816,8 +820,9 @@ func (db *postgres) SqlType(c *core.Column) string {
 		res = t
 		res = t
 	}
 	}
 
 
-	var hasLen1 bool = (c.Length > 0)
-	var hasLen2 bool = (c.Length2 > 0)
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
 	if hasLen2 {
 	if hasLen2 {
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 	} else if hasLen1 {
 	} else if hasLen1 {
@@ -836,6 +841,7 @@ func (db *postgres) IsReserved(name string) bool {
 }
 }
 
 
 func (db *postgres) Quote(name string) string {
 func (db *postgres) Quote(name string) string {
+	name = strings.Replace(name, ".", `"."`, -1)
 	return "\"" + name + "\""
 	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 {
 func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
-	quote := db.Quote
 	//var unique string
 	//var unique string
-	var idxName string = index.Name
+	quote := db.Quote
+	idxName := index.Name
+
 	if !strings.HasPrefix(idxName, "UQE_") &&
 	if !strings.HasPrefix(idxName, "UQE_") &&
 		!strings.HasPrefix(idxName, "IDX_") {
 		!strings.HasPrefix(idxName, "IDX_") {
 		if index.Type == core.UniqueType {
 		if index.Type == core.UniqueType {
@@ -900,10 +907,9 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
 	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
 		" AND column_name = $2"
 		" AND column_name = $2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		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) {
 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 ,
 	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
@@ -926,11 +932,9 @@ FROM pg_attribute f
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
     LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
     LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
 WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
 WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		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() {
 	for rows.Next() {
 		col := new(core.Column)
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 
 
 		var colName, isNullable, dataType string
 		var colName, isNullable, dataType string
 		var maxLenStr, colDefault, numPrecision, numRadix *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 {
 		switch dataType {
 		case "character varying", "character":
 		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":
 		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":
 		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":
 		case "double precision":
-			col.SQLType = core.SQLType{core.Double, 0, 0}
+			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0}
 		case "boolean":
 		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":
 		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:
 		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 {
 		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
 		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) {
 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...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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) {
 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...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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], ",")
 		colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
 
 
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			newIdxName := indexName[5+len(tableName) : len(indexName)]
+			newIdxName := indexName[5+len(tableName):]
 			if newIdxName != "" {
 			if newIdxName != "" {
 				indexName = newIdxName
 				indexName = newIdxName
 			}
 			}
@@ -1092,5 +1096,109 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
 }
 }
 
 
 func (db *postgres) Filters() []core.Filter {
 func (db *postgres) Filters() []core.Filter {
-	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{"$", 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 {
 func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
-	quote := db.Quote
 	//var unique string
 	//var unique string
-	var idxName string = index.Name
+	quote := db.Quote
+	idxName := index.Name
+
 	if !strings.HasPrefix(idxName, "UQE_") &&
 	if !strings.HasPrefix(idxName, "UQE_") &&
 		!strings.HasPrefix(idxName, "IDX_") {
 		!strings.HasPrefix(idxName, "IDX_") {
 		if index.Type == core.UniqueType {
 		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) {
 func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 	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...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		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) {
 func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
 	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
-
+	db.LogSQL(s, args)
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -316,15 +312,15 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 		colStr = reg.ReplaceAllString(colStr, ",")
 		colStr = reg.ReplaceAllString(colStr, ",")
 		fields := strings.Fields(strings.TrimSpace(colStr))
 		fields := strings.Fields(strings.TrimSpace(colStr))
 		col := new(core.Column)
 		col := new(core.Column)
-		col.Indexes = make(map[string]bool)
+		col.Indexes = make(map[string]int)
 		col.Nullable = true
 		col.Nullable = true
 		col.DefaultIsEmpty = true
 		col.DefaultIsEmpty = true
 		for idx, field := range fields {
 		for idx, field := range fields {
 			if idx == 0 {
 			if idx == 0 {
-				col.Name = strings.Trim(field, "`[] ")
+				col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
 				continue
 				continue
 			} else if idx == 1 {
 			} else if idx == 1 {
-				col.SQLType = core.SQLType{field, 0, 0}
+				col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
 			}
 			}
 			switch field {
 			switch field {
 			case "PRIMARY":
 			case "PRIMARY":
@@ -354,11 +350,9 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 func (db *sqlite3) GetTables() ([]*core.Table, error) {
 func (db *sqlite3) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := "SELECT name FROM sqlite_master WHERE type='table'"
 	s := "SELECT name FROM sqlite_master WHERE type='table'"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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) {
 func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
 	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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)
 	indexes := make(map[string]*core.Index, 0)
 	for rows.Next() {
 	for rows.Next() {
-		var tmpSql sql.NullString
-		err = rows.Scan(&tmpSql)
+		var tmpSQL sql.NullString
+		err = rows.Scan(&tmpSQL)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 
 
-		if !tmpSql.Valid {
+		if !tmpSQL.Valid {
 			continue
 			continue
 		}
 		}
-		sql := tmpSql.String
+		sql := tmpSQL.String
 
 
 		index := new(core.Index)
 		index := new(core.Index)
 		nNStart := strings.Index(sql, "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], "` []")
 		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
-			index.Name = indexName[5+len(tableName) : len(indexName)]
+			index.Name = indexName[5+len(tableName):]
 		} else {
 		} else {
 			index.Name = indexName
 			index.Name = indexName
 		}
 		}
@@ -442,3 +434,10 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
 func (db *sqlite3) Filters() []core.Filter {
 func (db *sqlite3) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}}
 	return []core.Filter{&core.IdFilter{}}
 }
 }
+
+type sqlite3Driver struct {
+}
+
+func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
+}

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

File diff suppressed because it is too large
+ 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 (
 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
 package xorm
 
 
 import (
 import (
+	"errors"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
 	"sort"
 	"sort"
@@ -15,6 +16,86 @@ import (
 	"github.com/go-xorm/core"
 	"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) {
 func splitTag(tag string) (tags []string) {
 	tag = strings.TrimSpace(tag)
 	tag = strings.TrimSpace(tag)
 	var hasQuote = false
 	var hasQuote = false
@@ -30,7 +111,7 @@ func splitTag(tag string) (tags []string) {
 		}
 		}
 	}
 	}
 	if lastIdx < len(tag) {
 	if lastIdx < len(tag) {
-		tags = append(tags, strings.TrimSpace(tag[lastIdx:len(tag)]))
+		tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
 	}
 	}
 	return
 	return
 }
 }
@@ -75,15 +156,55 @@ func isZero(k interface{}) bool {
 	return false
 	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:
 	case reflect.Int16:
 		v = int16(id)
 		v = int16(id)
 	case reflect.Int32:
 	case reflect.Int32:
 		v = int32(id)
 		v = int32(id)
 	case reflect.Int:
 	case reflect.Int:
 		v = int(id)
 		v = int(id)
+	case reflect.Int64:
+		v = id
 	case reflect.Uint16:
 	case reflect.Uint16:
 		v = uint16(id)
 		v = uint16(id)
 	case reflect.Uint32:
 	case reflect.Uint32:
@@ -93,7 +214,11 @@ func int64ToInt(id int64, k reflect.Kind) interface{} {
 	case reflect.Uint:
 	case reflect.Uint:
 		v = uint(id)
 		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 {
 func isPKZero(pk core.PK) bool {
@@ -105,10 +230,6 @@ func isPKZero(pk core.PK) bool {
 	return false
 	return false
 }
 }
 
 
-func equalNoCase(s1, s2 string) bool {
-	return strings.ToLower(s1) == strings.ToLower(s2)
-}
-
 func indexNoCase(s, sep string) int {
 func indexNoCase(s, sep string) int {
 	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 }
 }
@@ -154,6 +275,19 @@ func structName(v reflect.Type) string {
 	return v.Name()
 	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 {
 func sliceEq(left, right []string) bool {
 	if len(left) != len(right) {
 	if len(left) != len(right) {
 		return false
 		return false
@@ -188,7 +322,7 @@ func reflect2value(rawValue *reflect.Value) (str string, err error) {
 		default:
 		default:
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 		}
 		}
-	//时间类型
+	// time type
 	case reflect.Struct:
 	case reflect.Struct:
 		if aa.ConvertibleTo(core.TimeType) {
 		if aa.ConvertibleTo(core.TimeType) {
 			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
 			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)
 	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) {
 func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
 	v, err := col.ValueOf(bean)
 	v, err := col.ValueOf(bean)
 	if err != nil {
 	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) {
 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() {
 	for _, col := range table.Columns() {
-		lColName := strings.ToLower(col.Name)
 		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
 		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
-			if _, ok := session.Statement.columnMap[lColName]; !ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
 				continue
 				continue
 			}
 			}
 		}
 		}
@@ -376,8 +524,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 
 
 		fieldValuePtr, err := col.ValueOf(bean)
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
 		if err != nil {
-			session.Engine.LogError(err)
-			continue
+			return nil, nil, err
 		}
 		}
 		fieldValue := *fieldValuePtr
 		fieldValue := *fieldValuePtr
 
 
@@ -403,25 +550,26 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 		}
 		}
 
 
 		if session.Statement.ColumnStr != "" {
 		if session.Statement.ColumnStr != "" {
-			if _, ok := session.Statement.columnMap[lColName]; !ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok {
 				continue
 				continue
 			}
 			}
 		}
 		}
 		if session.Statement.OmitStr != "" {
 		if session.Statement.OmitStr != "" {
-			if _, ok := session.Statement.columnMap[lColName]; ok {
+			if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok {
 				continue
 				continue
 			}
 			}
 		}
 		}
 
 
 		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
 		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
-		if _, ok := session.Statement.nullableMap[lColName]; ok {
+		if _, ok := getFlagForColumn(session.Statement.nullableMap, col); ok {
 			if col.Nullable && isZero(fieldValue.Interface()) {
 			if col.Nullable && isZero(fieldValue.Interface()) {
 				var nilValue *int
 				var nilValue *int
 				fieldValue = reflect.ValueOf(nilValue)
 				fieldValue = reflect.ValueOf(nilValue)
 			}
 			}
 		}
 		}
 
 
-		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+		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)
 			val, t := session.Engine.NowTime2(col.SQLType.Name)
 			args = append(args, val)
 			args = append(args, val)
 
 
@@ -448,3 +596,27 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 	}
 	}
 	return colNames, args, nil
 	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"
 	"github.com/go-xorm/core"
 )
 )
 
 
+// default log options
 const (
 const (
 	DEFAULT_LOG_PREFIX = "[xorm]"
 	DEFAULT_LOG_PREFIX = "[xorm]"
 	DEFAULT_LOG_FLAG   = log.Ldate | log.Lmicroseconds
 	DEFAULT_LOG_FLAG   = log.Ldate | log.Lmicroseconds
 	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
 	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 {
 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 {
 func NewSimpleLogger(out io.Writer) *SimpleLogger {
 	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
 	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 {
 func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
 	return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
 	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 {
 func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
 	return &SimpleLogger{
 	return &SimpleLogger{
 		DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
 		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
 	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
 	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
 	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
 	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
 	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
 	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
 	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
 	return
 }
 }
 
 
+// Level implement core.ILogger
 func (s *SimpleLogger) Level() core.LogLevel {
 func (s *SimpleLogger) Level() core.LogLevel {
 	return s.level
 	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
 	s.level = l
 	return
 	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"
 	"github.com/go-xorm/core"
 )
 )
 
 
+// LRUCacher implments cache object facilities
 type LRUCacher struct {
 type LRUCacher struct {
 	idList   *list.List
 	idList   *list.List
 	sqlList  *list.List
 	sqlList  *list.List
@@ -26,10 +27,12 @@ type LRUCacher struct {
 	GcInterval     time.Duration
 	GcInterval     time.Duration
 }
 }
 
 
+// NewLRUCacher creates a cacher
 func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
 func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
 	return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
 	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 {
 func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
 	cacher := &LRUCacher{store: store, idList: list.New(),
 	cacher := &LRUCacher{store: store, idList: list.New(),
 		sqlList: list.New(), Expired: expired,
 		sqlList: list.New(), Expired: expired,
@@ -41,10 +44,6 @@ func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize
 	return cacher
 	return cacher
 }
 }
 
 
-//func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
-//    return newLRUCacher(store, expired, maxSize, 0)
-//}
-
 // RunGC run once every m.GcInterval
 // RunGC run once every m.GcInterval
 func (m *LRUCacher) RunGC() {
 func (m *LRUCacher) RunGC() {
 	time.AfterFunc(m.GcInterval, func() {
 	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{} {
 func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	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 v, err := m.store.Get(sql); err == nil {
 		if el, ok := m.sqlIndex[tableName][sql]; !ok {
 		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
 			m.sqlIndex[tableName][sql] = el
 		} else {
 		} else {
 			lastTime := el.Value.(*sqlNode).lastVisit
 			lastTime := el.Value.(*sqlNode).lastVisit
@@ -114,21 +113,21 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 			el.Value.(*sqlNode).lastVisit = time.Now()
 			el.Value.(*sqlNode).lastVisit = time.Now()
 		}
 		}
 		return v
 		return v
-	} else {
-		m.delIds(tableName, sql)
 	}
 	}
 
 
+	m.delIds(tableName, sql)
+
 	return nil
 	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{} {
 func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
 	if _, ok := m.idIndex[tableName]; !ok {
 	if _, ok := m.idIndex[tableName]; !ok {
 		m.idIndex[tableName] = make(map[string]*list.Element)
 		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 v, err := m.store.Get(tid); err == nil {
 		if el, ok := m.idIndex[tableName][id]; ok {
 		if el, ok := m.idIndex[tableName][id]; ok {
 			lastTime := el.Value.(*idNode).lastVisit
 			lastTime := el.Value.(*idNode).lastVisit
@@ -141,19 +140,19 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
 			m.idList.MoveToBack(el)
 			m.idList.MoveToBack(el)
 			el.Value.(*idNode).lastVisit = time.Now()
 			el.Value.(*idNode).lastVisit = time.Now()
 		} else {
 		} else {
-			el = m.idList.PushBack(newIdNode(tableName, id))
+			el = m.idList.PushBack(newIDNode(tableName, id))
 			m.idIndex[tableName][id] = el
 			m.idIndex[tableName][id] = el
 		}
 		}
 		return v
 		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) {
 func (m *LRUCacher) clearIds(tableName string) {
 	if tis, ok := m.sqlIndex[tableName]; ok {
 	if tis, ok := m.sqlIndex[tableName]; ok {
 		for sql, v := range tis {
 		for sql, v := range tis {
@@ -164,6 +163,7 @@ func (m *LRUCacher) clearIds(tableName string) {
 	m.sqlIndex[tableName] = make(map[string]*list.Element)
 	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) {
 func (m *LRUCacher) ClearIds(tableName string) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
@@ -174,19 +174,21 @@ func (m *LRUCacher) clearBeans(tableName string) {
 	if tis, ok := m.idIndex[tableName]; ok {
 	if tis, ok := m.idIndex[tableName]; ok {
 		for id, v := range tis {
 		for id, v := range tis {
 			m.idList.Remove(v)
 			m.idList.Remove(v)
-			tid := genId(tableName, id)
+			tid := genID(tableName, id)
 			m.store.Del(tid)
 			m.store.Del(tid)
 		}
 		}
 	}
 	}
 	m.idIndex[tableName] = make(map[string]*list.Element)
 	m.idIndex[tableName] = make(map[string]*list.Element)
 }
 }
 
 
+// ClearBeans clears all beans in some table
 func (m *LRUCacher) ClearBeans(tableName string) {
 func (m *LRUCacher) ClearBeans(tableName string) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
 	m.clearBeans(tableName)
 	m.clearBeans(tableName)
 }
 }
 
 
+// PutIds pus ids into table
 func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	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)
 		m.sqlIndex[tableName] = make(map[string]*list.Element)
 	}
 	}
 	if el, ok := m.sqlIndex[tableName][sql]; !ok {
 	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
 		m.sqlIndex[tableName][sql] = el
 	} else {
 	} else {
 		el.Value.(*sqlNode).lastVisit = time.Now()
 		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{}) {
 func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
@@ -214,13 +217,13 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
 	var ok bool
 	var ok bool
 
 
 	if el, ok = m.idIndex[tableName][id]; !ok {
 	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
 		m.idIndex[tableName][id] = el
 	} else {
 	} else {
 		el.Value.(*idNode).lastVisit = time.Now()
 		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 {
 	if m.idList.Len() > m.MaxElementSize {
 		e := m.idList.Front()
 		e := m.idList.Front()
 		node := e.Value.(*idNode)
 		node := e.Value.(*idNode)
@@ -238,6 +241,7 @@ func (m *LRUCacher) delIds(tableName, sql string) {
 	m.store.Del(sql)
 	m.store.Del(sql)
 }
 }
 
 
+// DelIds deletes ids
 func (m *LRUCacher) DelIds(tableName, sql string) {
 func (m *LRUCacher) DelIds(tableName, sql string) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
@@ -245,7 +249,7 @@ func (m *LRUCacher) DelIds(tableName, sql string) {
 }
 }
 
 
 func (m *LRUCacher) delBean(tableName string, id 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 {
 	if el, ok := m.idIndex[tableName][id]; ok {
 		delete(m.idIndex[tableName], id)
 		delete(m.idIndex[tableName], id)
 		m.idList.Remove(el)
 		m.idList.Remove(el)
@@ -254,6 +258,7 @@ func (m *LRUCacher) delBean(tableName string, id string) {
 	m.store.Del(tid)
 	m.store.Del(tid)
 }
 }
 
 
+// DelBean deletes beans in some table
 func (m *LRUCacher) DelBean(tableName string, id string) {
 func (m *LRUCacher) DelBean(tableName string, id string) {
 	m.mutex.Lock()
 	m.mutex.Lock()
 	defer m.mutex.Unlock()
 	defer m.mutex.Unlock()
@@ -272,18 +277,18 @@ type sqlNode struct {
 	lastVisit time.Time
 	lastVisit time.Time
 }
 }
 
 
-func genSqlKey(sql string, args interface{}) string {
+func genSQLKey(sql string, args interface{}) string {
 	return fmt.Sprintf("%v-%v", sql, args)
 	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)
 	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()}
 	return &idNode{tbName, id, time.Now()}
 }
 }
 
 
-func newSqlNode(tbName, sql string) *sqlNode {
+func newSQLNode(tbName, sql string) *sqlNode {
 	return &sqlNode{tbName, sql, time.Now()}
 	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()
 var _ core.CacheStore = NewMemoryStore()
 
 
-// memory store
+// MemoryStore represents in-memory store
 type MemoryStore struct {
 type MemoryStore struct {
 	store map[interface{}]interface{}
 	store map[interface{}]interface{}
 	mutex sync.RWMutex
 	mutex sync.RWMutex
 }
 }
 
 
+// NewMemoryStore creates a new store in memory
 func NewMemoryStore() *MemoryStore {
 func NewMemoryStore() *MemoryStore {
 	return &MemoryStore{store: make(map[interface{}]interface{})}
 	return &MemoryStore{store: make(map[interface{}]interface{})}
 }
 }
 
 
+// Put puts object into store
 func (s *MemoryStore) Put(key string, value interface{}) error {
 func (s *MemoryStore) Put(key string, value interface{}) error {
 	s.mutex.Lock()
 	s.mutex.Lock()
 	defer s.mutex.Unlock()
 	defer s.mutex.Unlock()
@@ -29,6 +31,7 @@ func (s *MemoryStore) Put(key string, value interface{}) error {
 	return nil
 	return nil
 }
 }
 
 
+// Get gets object from store
 func (s *MemoryStore) Get(key string) (interface{}, error) {
 func (s *MemoryStore) Get(key string) (interface{}, error) {
 	s.mutex.RLock()
 	s.mutex.RLock()
 	defer s.mutex.RUnlock()
 	defer s.mutex.RUnlock()
@@ -39,6 +42,7 @@ func (s *MemoryStore) Get(key string) (interface{}, error) {
 	return nil, ErrNotExist
 	return nil, ErrNotExist
 }
 }
 
 
+// Del deletes object
 func (s *MemoryStore) Del(key string) error {
 func (s *MemoryStore) Del(key string) error {
 	s.mutex.Lock()
 	s.mutex.Lock()
 	defer s.mutex.Unlock()
 	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
 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 {
 type BeforeInsertProcessor interface {
 	BeforeInsert()
 	BeforeInsert()
 }
 }
 
 
-// Executed before an object is updated
+// BeforeUpdateProcessor executed before an object is updated
 type BeforeUpdateProcessor interface {
 type BeforeUpdateProcessor interface {
 	BeforeUpdate()
 	BeforeUpdate()
 }
 }
 
 
-// Executed before an object is deleted
+// BeforeDeleteProcessor executed before an object is deleted
 type BeforeDeleteProcessor interface {
 type BeforeDeleteProcessor interface {
 	BeforeDelete()
 	BeforeDelete()
 }
 }
 
 
+// BeforeSetProcessor executed before data set to the struct fields
 type BeforeSetProcessor interface {
 type BeforeSetProcessor interface {
 	BeforeSet(string, Cell)
 	BeforeSet(string, Cell)
 }
 }
 
 
+// AfterSetProcessor executed after data set to the struct fields
 type AfterSetProcessor interface {
 type AfterSetProcessor interface {
 	AfterSet(string, Cell)
 	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 {
 type AfterInsertProcessor interface {
 	AfterInsert()
 	AfterInsert()
 }
 }
 
 
-// Executed after an object has been updated
+// AfterUpdateProcessor executed after an object has been updated
 type AfterUpdateProcessor interface {
 type AfterUpdateProcessor interface {
 	AfterUpdate()
 	AfterUpdate()
 }
 }
 
 
-// Executed after an object has been deleted
+// AfterDeleteProcessor executed after an object has been deleted
 type AfterDeleteProcessor interface {
 type AfterDeleteProcessor interface {
 	AfterDelete()
 	AfterDelete()
 }
 }

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

@@ -12,16 +12,16 @@ import (
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
 )
 )
 
 
+// Rows rows wrapper a rows to
 type Rows struct {
 type Rows struct {
 	NoTypeCheck bool
 	NoTypeCheck bool
 
 
-	session     *Session
-	stmt        *core.Stmt
-	rows        *core.Rows
-	fields      []string
-	fieldsCount int
-	beanType    reflect.Type
-	lastError   error
+	session   *Session
+	stmt      *core.Stmt
+	rows      *core.Rows
+	fields    []string
+	beanType  reflect.Type
+	lastError error
 }
 }
 
 
 func newRows(session *Session, bean interface{}) (*Rows, error) {
 func newRows(session *Session, bean interface{}) (*Rows, error) {
@@ -29,13 +29,18 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 	rows.session = session
 	rows.session = session
 	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
 	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
 
 
-	defer rows.session.Statement.Init()
+	defer rows.session.resetStatement()
 
 
 	var sqlStr string
 	var sqlStr string
 	var args []interface{}
 	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 == "" {
 	if rows.session.Statement.RawSQL == "" {
-		sqlStr, args = rows.session.Statement.genGetSql(bean)
+		sqlStr, args = rows.session.Statement.genGetSQL(bean)
 	} else {
 	} else {
 		sqlStr = rows.session.Statement.RawSQL
 		sqlStr = rows.session.Statement.RawSQL
 		args = rows.session.Statement.RawParams
 		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)
 		sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
 	}
 	}
 
 
-	rows.session.saveLastSQL(sqlStr, args)
+	rows.session.saveLastSQL(sqlStr, args...)
 	var err error
 	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()
 	rows.fields, err = rows.rows.Columns()
 	if err != nil {
 	if err != nil {
 		rows.lastError = err
 		rows.lastError = err
-		defer rows.Close()
+		rows.Close()
 		return nil, err
 		return nil, err
 	}
 	}
-	rows.fieldsCount = len(rows.fields)
 
 
 	return rows, nil
 	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 {
 func (rows *Rows) Next() bool {
 	if rows.lastError == nil && rows.rows != nil {
 	if rows.lastError == nil && rows.rows != nil {
 		hasNext := rows.rows.Next()
 		hasNext := rows.rows.Next()
@@ -89,7 +102,7 @@ func (rows *Rows) Err() error {
 	return rows.lastError
 	return rows.lastError
 }
 }
 
 
-// scan row record to bean properties
+// Scan row record to bean properties
 func (rows *Rows) Scan(bean interface{}) error {
 func (rows *Rows) Scan(bean interface{}) error {
 	if rows.lastError != nil {
 	if rows.lastError != nil {
 		return rows.lastError
 		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 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 {
 func (rows *Rows) Close() error {
 	if rows.session.IsAutoClose {
 	if rows.session.IsAutoClose {
 		defer rows.session.Close()
 		defer rows.session.Close()

File diff suppressed because it is too large
+ 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
-}

File diff suppressed because it is too large
+ 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"
 	"github.com/go-xorm/core"
 )
 )
 
 
+var _ core.ILogger = &SyslogLogger{}
+
+// SyslogLogger will be depricated
 type SyslogLogger struct {
 type SyslogLogger struct {
-	w *syslog.Writer
+	w       *syslog.Writer
+	showSQL bool
 }
 }
 
 
+// NewSyslogLogger implements core.ILogger
 func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 	return &SyslogLogger{w: w}
 	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 {
 func (s *SyslogLogger) Level() core.LogLevel {
 	return core.LOG_UNKNOWN
 	return core.LOG_UNKNOWN
 }
 }
 
 
 // SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
 // 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
 package xorm
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"reflect"
 	"reflect"
@@ -17,7 +16,8 @@ import (
 )
 )
 
 
 const (
 const (
-	Version string = "0.4.5.0204"
+	// Version show the xorm's version
+	Version string = "0.6.2.0326"
 )
 )
 
 
 func regDrvsNDialects() bool {
 func regDrvsNDialects() bool {
@@ -31,6 +31,7 @@ func regDrvsNDialects() bool {
 		"mysql":    {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 		"mysql":    {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 		"mymysql":  {"mysql", func() core.Driver { return &mymysqlDriver{} }, 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{} }},
 		"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{} }},
 		"sqlite3":  {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
 		"oci8":     {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
 		"oci8":     {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
 		"goracle":  {"oracle", func() core.Driver { return &goracleDriver{} }, 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()
 	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
 // drivers
 func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	regDrvsNDialects()
 	regDrvsNDialects()
 	driver := core.QueryDriver(driverName)
 	driver := core.QueryDriver(driverName)
 	if driver == nil {
 	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)
 	uri, err := driver.Parse(driverName, dataSourceName)
@@ -65,7 +66,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 
 
 	dialect := core.QueryDialect(uri.DbType)
 	dialect := core.QueryDialect(uri.DbType)
 	if dialect == nil {
 	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)
 	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),
 		Tables:        make(map[reflect.Type]*core.Table),
 		mutex:         &sync.RWMutex{},
 		mutex:         &sync.RWMutex{},
 		TagIdentifier: "xorm",
 		TagIdentifier: "xorm",
-		Logger:        NewSimpleLogger(os.Stdout),
 		TZLocation:    time.Local,
 		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)))
 	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
 
 
 	runtime.SetFinalizer(engine, close)
 	runtime.SetFinalizer(engine, close)
@@ -97,7 +99,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	return engine, nil
 	return engine, nil
 }
 }
 
 
-// clone an engine
+// Clone clone an engine
 func (engine *Engine) Clone() (*Engine, error) {
 func (engine *Engine) Clone() (*Engine, error) {
 	return NewEngine(engine.DriverName(), engine.DataSourceName())
 	return NewEngine(engine.DriverName(), engine.DataSourceName())
 }
 }

+ 22 - 0
vendor/vendor.json

@@ -332,6 +332,28 @@
 			"revision": "9dee4ca50b83acdf57a35fb9e6fb4be640afa2f3",
 			"revision": "9dee4ca50b83acdf57a35fb9e6fb4be640afa2f3",
 			"revisionTime": "2017-03-27T11:30:21Z"
 			"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=",
 			"checksumSHA1": "B4bk7vdV9aD7AhrtATXfgEacdqE=",
 			"path": "github.com/gorilla/websocket",
 			"path": "github.com/gorilla/websocket",

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