Selaa lähdekoodia

Vendored dependency update/cleanup

Achilleas Koutsou 5 vuotta sitten
vanhempi
commit
f8bc8e30fe
100 muutettua tiedostoa jossa 20526 lisäystä ja 0 poistoa
  1. 27 0
      vendor/gitea.com/xorm/builder/LICENSE
  2. 206 0
      vendor/gitea.com/xorm/builder/README.md
  3. 394 0
      vendor/gitea.com/xorm/builder/builder.go
  4. 27 0
      vendor/gitea.com/xorm/builder/builder_delete.go
  5. 89 0
      vendor/gitea.com/xorm/builder/builder_insert.go
  6. 100 0
      vendor/gitea.com/xorm/builder/builder_limit.go
  7. 145 0
      vendor/gitea.com/xorm/builder/builder_select.go
  8. 47 0
      vendor/gitea.com/xorm/builder/builder_union.go
  9. 46 0
      vendor/gitea.com/xorm/builder/builder_update.go
  10. 74 0
      vendor/gitea.com/xorm/builder/cond.go
  11. 61 0
      vendor/gitea.com/xorm/builder/cond_and.go
  12. 65 0
      vendor/gitea.com/xorm/builder/cond_between.go
  13. 160 0
      vendor/gitea.com/xorm/builder/cond_compare.go
  14. 112 0
      vendor/gitea.com/xorm/builder/cond_eq.go
  15. 39 0
      vendor/gitea.com/xorm/builder/cond_expr.go
  16. 49 0
      vendor/gitea.com/xorm/builder/cond_if.go
  17. 237 0
      vendor/gitea.com/xorm/builder/cond_in.go
  18. 41 0
      vendor/gitea.com/xorm/builder/cond_like.go
  19. 94 0
      vendor/gitea.com/xorm/builder/cond_neq.go
  20. 77 0
      vendor/gitea.com/xorm/builder/cond_not.go
  21. 234 0
      vendor/gitea.com/xorm/builder/cond_notin.go
  22. 59 0
      vendor/gitea.com/xorm/builder/cond_null.go
  23. 69 0
      vendor/gitea.com/xorm/builder/cond_or.go
  24. 120 0
      vendor/gitea.com/xorm/builder/doc.go
  25. 40 0
      vendor/gitea.com/xorm/builder/error.go
  26. 6 0
      vendor/gitea.com/xorm/builder/go.mod
  27. 9 0
      vendor/gitea.com/xorm/builder/go.sum
  28. 160 0
      vendor/gitea.com/xorm/builder/sql.go
  29. 119 0
      vendor/gitea.com/xorm/builder/string_builder.go
  30. 27 0
      vendor/gitea.com/xorm/core/LICENSE
  31. 116 0
      vendor/gitea.com/xorm/core/README.md
  32. 1 0
      vendor/gitea.com/xorm/core/benchmark.sh
  33. 95 0
      vendor/gitea.com/xorm/core/cache.go
  34. 166 0
      vendor/gitea.com/xorm/core/column.go
  35. 12 0
      vendor/gitea.com/xorm/core/converstion.go
  36. 225 0
      vendor/gitea.com/xorm/core/db.go
  37. 320 0
      vendor/gitea.com/xorm/core/dialect.go
  38. 31 0
      vendor/gitea.com/xorm/core/driver.go
  39. 12 0
      vendor/gitea.com/xorm/core/error.go
  40. 68 0
      vendor/gitea.com/xorm/core/filter.go
  41. 13 0
      vendor/gitea.com/xorm/core/go.mod
  42. 23 0
      vendor/gitea.com/xorm/core/go.sum
  43. 35 0
      vendor/gitea.com/xorm/core/ilogger.go
  44. 71 0
      vendor/gitea.com/xorm/core/index.go
  45. 258 0
      vendor/gitea.com/xorm/core/mapper.go
  46. 30 0
      vendor/gitea.com/xorm/core/pk.go
  47. 338 0
      vendor/gitea.com/xorm/core/rows.go
  48. 66 0
      vendor/gitea.com/xorm/core/scan.go
  49. 165 0
      vendor/gitea.com/xorm/core/stmt.go
  50. 154 0
      vendor/gitea.com/xorm/core/table.go
  51. 153 0
      vendor/gitea.com/xorm/core/tx.go
  52. 323 0
      vendor/gitea.com/xorm/core/type.go
  53. 46 0
      vendor/gitea.com/xorm/xorm/CONTRIBUTING.md
  54. 27 0
      vendor/gitea.com/xorm/xorm/LICENSE
  55. 496 0
      vendor/gitea.com/xorm/xorm/README.md
  56. 500 0
      vendor/gitea.com/xorm/xorm/README_CN.md
  57. 284 0
      vendor/gitea.com/xorm/xorm/cache_lru.go
  58. 51 0
      vendor/gitea.com/xorm/xorm/cache_memory_store.go
  59. 30 0
      vendor/gitea.com/xorm/xorm/context_cache.go
  60. 348 0
      vendor/gitea.com/xorm/xorm/convert.go
  61. 572 0
      vendor/gitea.com/xorm/xorm/dialect_mssql.go
  62. 662 0
      vendor/gitea.com/xorm/xorm/dialect_mysql.go
  63. 906 0
      vendor/gitea.com/xorm/xorm/dialect_oracle.go
  64. 1253 0
      vendor/gitea.com/xorm/xorm/dialect_postgres.go
  65. 460 0
      vendor/gitea.com/xorm/xorm/dialect_sqlite3.go
  66. 184 0
      vendor/gitea.com/xorm/xorm/doc.go
  67. 1644 0
      vendor/gitea.com/xorm/xorm/engine.go
  68. 232 0
      vendor/gitea.com/xorm/xorm/engine_cond.go
  69. 28 0
      vendor/gitea.com/xorm/xorm/engine_context.go
  70. 219 0
      vendor/gitea.com/xorm/xorm/engine_group.go
  71. 116 0
      vendor/gitea.com/xorm/xorm/engine_group_policy.go
  72. 113 0
      vendor/gitea.com/xorm/xorm/engine_table.go
  73. 51 0
      vendor/gitea.com/xorm/xorm/error.go
  74. 6 0
      vendor/gitea.com/xorm/xorm/gen_reserved.sh
  75. 19 0
      vendor/gitea.com/xorm/xorm/go.mod
  76. 159 0
      vendor/gitea.com/xorm/xorm/go.sum
  77. 311 0
      vendor/gitea.com/xorm/xorm/helpers.go
  78. 21 0
      vendor/gitea.com/xorm/xorm/helpler_time.go
  79. 118 0
      vendor/gitea.com/xorm/xorm/interface.go
  80. 31 0
      vendor/gitea.com/xorm/xorm/json.go
  81. 187 0
      vendor/gitea.com/xorm/xorm/logger.go
  82. 746 0
      vendor/gitea.com/xorm/xorm/pg_reserved.txt
  83. 78 0
      vendor/gitea.com/xorm/xorm/processors.go
  84. 121 0
      vendor/gitea.com/xorm/xorm/rows.go
  85. 866 0
      vendor/gitea.com/xorm/xorm/session.go
  86. 199 0
      vendor/gitea.com/xorm/xorm/session_cols.go
  87. 70 0
      vendor/gitea.com/xorm/xorm/session_cond.go
  88. 23 0
      vendor/gitea.com/xorm/xorm/session_context.go
  89. 661 0
      vendor/gitea.com/xorm/xorm/session_convert.go
  90. 244 0
      vendor/gitea.com/xorm/xorm/session_delete.go
  91. 96 0
      vendor/gitea.com/xorm/xorm/session_exist.go
  92. 503 0
      vendor/gitea.com/xorm/xorm/session_find.go
  93. 241 0
      vendor/gitea.com/xorm/xorm/session_get.go
  94. 747 0
      vendor/gitea.com/xorm/xorm/session_insert.go
  95. 100 0
      vendor/gitea.com/xorm/xorm/session_iterate.go
  96. 320 0
      vendor/gitea.com/xorm/xorm/session_query.go
  97. 227 0
      vendor/gitea.com/xorm/xorm/session_raw.go
  98. 421 0
      vendor/gitea.com/xorm/xorm/session_schema.go
  99. 98 0
      vendor/gitea.com/xorm/xorm/session_stats.go
  100. 83 0
      vendor/gitea.com/xorm/xorm/session_tx.go

+ 27 - 0
vendor/gitea.com/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.

+ 206 - 0
vendor/gitea.com/xorm/builder/README.md

@@ -0,0 +1,206 @@
+# SQL builder
+
+[![Build Status](https://drone.gitea.com/api/badges/xorm/builder/status.svg)](https://drone.gitea.com/xorm/builder) [![](http://gocover.io/_badge/xorm.io/builder)](http://gocover.io/xorm.io/builder)
+[![](https://goreportcard.com/badge/xorm.io/builder)](https://goreportcard.com/report/xorm.io/builder)
+
+Package builder is a lightweight and fast SQL builder for Go and XORM.
+
+Make sure you have installed Go 1.8+ and then:
+
+    go get xorm.io/builder
+
+# Insert
+
+```Go
+sql, args, err := builder.Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
+
+// INSERT INTO table1 SELECT * FROM table2
+sql, err := builder.Insert().Into("table1").Select().From("table2").ToBoundSQL()
+
+// INSERT INTO table1 (a, b) SELECT b, c FROM table2
+sql, err = builder.Insert("a, b").Into("table1").Select("b, c").From("table2").ToBoundSQL()
+```
+
+# Select
+
+```Go
+// Simple Query
+sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
+// With join
+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()
+// From sub query
+sql, args, err := Select("sub.id").From(Select("c").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
+// From union query
+sql, args, err = Select("sub.id").From(
+	Select("id").From("table1").Where(Eq{"a": 1}).Union("all", Select("id").From("table1").Where(Eq{"a": 2})),"sub").
+	Where(Eq{"b": 1}).ToSQL()
+// With order by
+sql, args, err = Select("a", "b", "c").From("table1").Where(Eq{"f1": "v1", "f2": "v2"}).
+		OrderBy("a ASC").ToSQL()
+// With limit.
+// Be careful! You should set up specific dialect for builder before performing a query with LIMIT
+sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
+		Limit(5, 10).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()
+```
+
+# Union
+
+```Go
+sql, args, err := Select("*").From("a").Where(Eq{"status": "1"}).
+		Union("all", Select("*").From("a").Where(Eq{"status": "2"})).
+		Union("distinct", Select("*").From("a").Where(Eq{"status": "3"})).
+		Union("", Select("*").From("a").Where(Eq{"status": "4"})).
+		ToSQL()
+```
+
+# Conditions
+
+* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
+
+```Go
+import . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/builder"
+
+sql, args, _ := ToSQL(Like{"a", "c"})
+// a LIKE ? [%c%]
+```
+
+* `Expr` you can customerize your sql with `Expr`
+
+```Go
+import . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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`.

+ 394 - 0
vendor/gitea.com/xorm/builder/builder.go

@@ -0,0 +1,394 @@
+// 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 (
+	sql2 "database/sql"
+	"fmt"
+	"sort"
+)
+
+type optype byte
+
+const (
+	condType   optype = iota // only conditions
+	selectType               // select
+	insertType               // insert
+	updateType               // update
+	deleteType               // delete
+	unionType                // union
+)
+
+const (
+	POSTGRES = "postgres"
+	SQLITE   = "sqlite3"
+	MYSQL    = "mysql"
+	MSSQL    = "mssql"
+	ORACLE   = "oracle"
+)
+
+type join struct {
+	joinType  string
+	joinTable string
+	joinCond  Cond
+}
+
+type union struct {
+	unionType string
+	builder   *Builder
+}
+
+type limit struct {
+	limitN int
+	offset int
+}
+
+// Builder describes a SQL statement
+type Builder struct {
+	optype
+	dialect    string
+	isNested   bool
+	into       string
+	from       string
+	subQuery   *Builder
+	cond       Cond
+	selects    []string
+	joins      []join
+	unions     []union
+	limitation *limit
+	insertCols []string
+	insertVals []interface{}
+	updates    []Eq
+	orderBy    string
+	groupBy    string
+	having     string
+}
+
+// Dialect sets the db dialect of Builder.
+func Dialect(dialect string) *Builder {
+	builder := &Builder{cond: NewCond(), dialect: dialect}
+	return builder
+}
+
+// MySQL is shortcut of Dialect(MySQL)
+func MySQL() *Builder {
+	return Dialect(MYSQL)
+}
+
+// MsSQL is shortcut of Dialect(MsSQL)
+func MsSQL() *Builder {
+	return Dialect(MSSQL)
+}
+
+// Oracle is shortcut of Dialect(Oracle)
+func Oracle() *Builder {
+	return Dialect(ORACLE)
+}
+
+// Postgres is shortcut of Dialect(Postgres)
+func Postgres() *Builder {
+	return Dialect(POSTGRES)
+}
+
+// SQLite is shortcut of Dialect(SQLITE)
+func SQLite() *Builder {
+	return Dialect(SQLITE)
+}
+
+// Where sets where SQL
+func (b *Builder) Where(cond Cond) *Builder {
+	if b.cond.IsValid() {
+		b.cond = b.cond.And(cond)
+	} else {
+		b.cond = cond
+	}
+	return b
+}
+
+// From sets from subject(can be a table name in string or a builder pointer) and its alias
+func (b *Builder) From(subject interface{}, alias ...string) *Builder {
+	switch subject.(type) {
+	case *Builder:
+		b.subQuery = subject.(*Builder)
+
+		if len(alias) > 0 {
+			b.from = alias[0]
+		} else {
+			b.isNested = true
+		}
+	case string:
+		b.from = subject.(string)
+
+		if len(alias) > 0 {
+			b.from = b.from + " " + alias[0]
+		}
+	}
+
+	return b
+}
+
+// TableName returns the table name
+func (b *Builder) TableName() string {
+	if b.optype == insertType {
+		return b.into
+	}
+	return b.from
+}
+
+// Into sets insert table name
+func (b *Builder) Into(tableName string) *Builder {
+	b.into = tableName
+	return b
+}
+
+// Join sets join table and conditions
+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
+}
+
+// Union sets union conditions
+func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
+	var builder *Builder
+	if b.optype != unionType {
+		builder = &Builder{cond: NewCond()}
+		builder.optype = unionType
+		builder.dialect = b.dialect
+		builder.selects = b.selects
+
+		currentUnions := b.unions
+		// erase sub unions (actually append to new Builder.unions)
+		b.unions = nil
+
+		for e := range currentUnions {
+			currentUnions[e].builder.dialect = b.dialect
+		}
+
+		builder.unions = append(append(builder.unions, union{"", b}), currentUnions...)
+	} else {
+		builder = b
+	}
+
+	if unionCond != nil {
+		if unionCond.dialect == "" && builder.dialect != "" {
+			unionCond.dialect = builder.dialect
+		}
+
+		builder.unions = append(builder.unions, union{unionTp, unionCond})
+	}
+
+	return builder
+}
+
+// Limit sets limitN condition
+func (b *Builder) Limit(limitN int, offset ...int) *Builder {
+	b.limitation = &limit{limitN: limitN}
+
+	if len(offset) > 0 {
+		b.limitation.offset = offset[0]
+	}
+
+	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
+	if b.optype == condType {
+		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
+}
+
+type insertColsSorter struct {
+	cols []string
+	vals []interface{}
+}
+
+func (s insertColsSorter) Len() int {
+	return len(s.cols)
+}
+func (s insertColsSorter) Swap(i, j int) {
+	s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
+	s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
+}
+
+func (s insertColsSorter) Less(i, j int) bool {
+	return s.cols[i] < s.cols[j]
+}
+
+// Insert sets insert SQL
+func (b *Builder) Insert(eq ...interface{}) *Builder {
+	if len(eq) > 0 {
+		var paramType = -1
+		for _, e := range eq {
+			switch t := e.(type) {
+			case Eq:
+				if paramType == -1 {
+					paramType = 0
+				}
+				if paramType != 0 {
+					break
+				}
+				for k, v := range t {
+					b.insertCols = append(b.insertCols, k)
+					b.insertVals = append(b.insertVals, v)
+				}
+			case string:
+				if paramType == -1 {
+					paramType = 1
+				}
+				if paramType != 1 {
+					break
+				}
+				b.insertCols = append(b.insertCols, t)
+			}
+		}
+	}
+
+	if len(b.insertCols) == len(b.insertVals) {
+		sort.Sort(insertColsSorter{
+			cols: b.insertCols,
+			vals: b.insertVals,
+		})
+	}
+	b.optype = insertType
+	return b
+}
+
+// Update sets update SQL
+func (b *Builder) Update(updates ...Eq) *Builder {
+	b.updates = make([]Eq, 0, len(updates))
+	for _, update := range updates {
+		if update.IsValid() {
+			b.updates = append(b.updates, update)
+		}
+	}
+	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)
+	case unionType:
+		return b.unionWriteTo(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
+	}
+
+	// in case of sql.NamedArg in args
+	for e := range w.args {
+		if namedArg, ok := w.args[e].(sql2.NamedArg); ok {
+			w.args[e] = namedArg.Value
+		}
+	}
+
+	var sql = w.writer.String()
+	var err error
+
+	switch b.dialect {
+	case ORACLE, MSSQL:
+		// This is for compatibility with different sql drivers
+		for e := range w.args {
+			w.args[e] = sql2.Named(fmt.Sprintf("p%d", e+1), w.args[e])
+		}
+
+		var prefix string
+		if b.dialect == ORACLE {
+			prefix = ":p"
+		} else {
+			prefix = "@p"
+		}
+
+		if sql, err = ConvertPlaceholder(sql, prefix); err != nil {
+			return "", nil, err
+		}
+	case POSTGRES:
+		if sql, err = ConvertPlaceholder(sql, "$"); err != nil {
+			return "", nil, err
+		}
+	}
+
+	return sql, w.args, nil
+}
+
+// ToBoundSQL
+func (b *Builder) ToBoundSQL() (string, error) {
+	w := NewWriter()
+	if err := b.WriteTo(w); err != nil {
+		return "", err
+	}
+
+	return ConvertToBoundSQL(w.writer.String(), w.args)
+}

+ 27 - 0
vendor/gitea.com/xorm/builder/builder_delete.go

@@ -0,0 +1,27 @@
+// 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"
+)
+
+// Delete creates a delete Builder
+func Delete(conds ...Cond) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Delete(conds...)
+}
+
+func (b *Builder) deleteWriteTo(w Writer) error {
+	if len(b.from) <= 0 {
+		return ErrNoTableName
+	}
+
+	if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.from); err != nil {
+		return err
+	}
+
+	return b.cond.WriteTo(w)
+}

+ 89 - 0
vendor/gitea.com/xorm/builder/builder_insert.go

@@ -0,0 +1,89 @@
+// 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"
+	"fmt"
+)
+
+// Insert creates an insert Builder
+func Insert(eq ...interface{}) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Insert(eq...)
+}
+
+func (b *Builder) insertSelectWriteTo(w Writer) error {
+	if _, err := fmt.Fprintf(w, "INSERT INTO %s ", b.into); err != nil {
+		return err
+	}
+
+	if len(b.insertCols) > 0 {
+		fmt.Fprintf(w, "(")
+		for _, col := range b.insertCols {
+			fmt.Fprintf(w, col)
+		}
+		fmt.Fprintf(w, ") ")
+	}
+
+	return b.selectWriteTo(w)
+}
+
+func (b *Builder) insertWriteTo(w Writer) error {
+	if len(b.into) <= 0 {
+		return ErrNoTableName
+	}
+	if len(b.insertCols) <= 0 && b.from == "" {
+		return ErrNoColumnToInsert
+	}
+
+	if b.into != "" && b.from != "" {
+		return b.insertSelectWriteTo(w)
+	}
+
+	if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.into); err != nil {
+		return err
+	}
+
+	var args = make([]interface{}, 0)
+	var bs []byte
+	var valBuffer = bytes.NewBuffer(bs)
+
+	for i, col := range b.insertCols {
+		value := b.insertVals[i]
+		fmt.Fprint(w, col)
+		if e, ok := value.(expr); ok {
+			fmt.Fprintf(valBuffer, "(%s)", e.sql)
+			args = append(args, e.args...)
+		} else {
+			fmt.Fprint(valBuffer, "?")
+			args = append(args, value)
+		}
+
+		if i != len(b.insertCols)-1 {
+			if _, err := fmt.Fprint(w, ","); err != nil {
+				return err
+			}
+			if _, err := fmt.Fprint(valBuffer, ","); err != nil {
+				return err
+			}
+		}
+	}
+
+	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
+}

+ 100 - 0
vendor/gitea.com/xorm/builder/builder_limit.go

@@ -0,0 +1,100 @@
+// Copyright 2018 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"fmt"
+	"strings"
+)
+
+func (b *Builder) limitWriteTo(w Writer) error {
+	if strings.TrimSpace(b.dialect) == "" {
+		return ErrDialectNotSetUp
+	}
+
+	if b.limitation != nil {
+		limit := b.limitation
+		if limit.offset < 0 || limit.limitN <= 0 {
+			return ErrInvalidLimitation
+		}
+		// erase limit condition
+		b.limitation = nil
+		ow := w.(*BytesWriter)
+
+		switch strings.ToLower(strings.TrimSpace(b.dialect)) {
+		case ORACLE:
+			if len(b.selects) == 0 {
+				b.selects = append(b.selects, "*")
+			}
+
+			var final *Builder
+			selects := b.selects
+			b.selects = append(selects, "ROWNUM RN")
+
+			var wb *Builder
+			if b.optype == unionType {
+				wb = Dialect(b.dialect).Select("at.*", "ROWNUM RN").
+					From(b, "at")
+			} else {
+				wb = b
+			}
+
+			if limit.offset == 0 {
+				final = Dialect(b.dialect).Select(selects...).From(wb, "at").
+					Where(Lte{"at.RN": limit.limitN})
+			} else {
+				sub := Dialect(b.dialect).Select("*").
+					From(b, "at").Where(Lte{"at.RN": limit.offset + limit.limitN})
+
+				final = Dialect(b.dialect).Select(selects...).From(sub, "att").
+					Where(Gt{"att.RN": limit.offset})
+			}
+
+			return final.WriteTo(ow)
+		case SQLITE, MYSQL, POSTGRES:
+			// if type UNION, we need to write previous content back to current writer
+			if b.optype == unionType {
+				if err := b.WriteTo(ow); err != nil {
+					return err
+				}
+			}
+
+			if limit.offset == 0 {
+				fmt.Fprint(ow, " LIMIT ", limit.limitN)
+			} else {
+				fmt.Fprintf(ow, " LIMIT %v OFFSET %v", limit.limitN, limit.offset)
+			}
+		case MSSQL:
+			if len(b.selects) == 0 {
+				b.selects = append(b.selects, "*")
+			}
+
+			var final *Builder
+			selects := b.selects
+			b.selects = append(append([]string{fmt.Sprintf("TOP %d %v", limit.limitN+limit.offset, b.selects[0])},
+				b.selects[1:]...), "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN")
+
+			var wb *Builder
+			if b.optype == unionType {
+				wb = Dialect(b.dialect).Select("*", "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN").
+					From(b, "at")
+			} else {
+				wb = b
+			}
+
+			if limit.offset == 0 {
+				final = Dialect(b.dialect).Select(selects...).From(wb, "at")
+			} else {
+				final = Dialect(b.dialect).Select(selects...).From(wb, "at").Where(Gt{"at.RN": limit.offset})
+			}
+
+			return final.WriteTo(ow)
+		default:
+			return ErrNotSupportType
+		}
+	}
+
+	return nil
+}

+ 145 - 0
vendor/gitea.com/xorm/builder/builder_select.go

@@ -0,0 +1,145 @@
+// 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"
+)
+
+// Select creates a select Builder
+func Select(cols ...string) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Select(cols...)
+}
+
+func (b *Builder) selectWriteTo(w Writer) error {
+	if len(b.from) <= 0 && !b.isNested {
+		return ErrNoTableName
+	}
+
+	// perform limit before writing to writer when b.dialect between ORACLE and MSSQL
+	// this avoid a duplicate writing problem in simple limit query
+	if b.limitation != nil && (b.dialect == ORACLE || b.dialect == MSSQL) {
+		return b.limitWriteTo(w)
+	}
+
+	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 b.subQuery == nil {
+		if _, err := fmt.Fprint(w, " FROM ", b.from); err != nil {
+			return err
+		}
+	} else {
+		if b.cond.IsValid() && len(b.from) <= 0 {
+			return ErrUnnamedDerivedTable
+		}
+		if b.subQuery.dialect != "" && b.dialect != b.subQuery.dialect {
+			return ErrInconsistentDialect
+		}
+
+		// dialect of sub-query will inherit from the main one (if not set up)
+		if b.dialect != "" && b.subQuery.dialect == "" {
+			b.subQuery.dialect = b.dialect
+		}
+
+		switch b.subQuery.optype {
+		case selectType, unionType:
+			fmt.Fprint(w, " FROM (")
+			if err := b.subQuery.WriteTo(w); err != nil {
+				return err
+			}
+
+			if len(b.from) == 0 {
+				fmt.Fprintf(w, ")")
+			} else {
+				fmt.Fprintf(w, ") %v", b.from)
+			}
+		default:
+			return ErrUnexpectedSubQuery
+		}
+	}
+
+	for _, v := range b.joins {
+		if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil {
+			return err
+		}
+
+		if err := v.joinCond.WriteTo(w); err != nil {
+			return err
+		}
+	}
+
+	if b.cond.IsValid() {
+		if _, err := fmt.Fprint(w, " WHERE "); err != nil {
+			return err
+		}
+
+		if err := b.cond.WriteTo(w); err != nil {
+			return err
+		}
+	}
+
+	if len(b.groupBy) > 0 {
+		if _, err := fmt.Fprint(w, " GROUP BY ", b.groupBy); err != nil {
+			return err
+		}
+	}
+
+	if len(b.having) > 0 {
+		if _, err := fmt.Fprint(w, " HAVING ", b.having); err != nil {
+			return err
+		}
+	}
+
+	if len(b.orderBy) > 0 {
+		if _, err := fmt.Fprint(w, " ORDER BY ", b.orderBy); err != nil {
+			return err
+		}
+	}
+
+	if b.limitation != nil {
+		if err := b.limitWriteTo(w); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// OrderBy orderBy SQL
+func (b *Builder) OrderBy(orderBy string) *Builder {
+	b.orderBy = orderBy
+	return b
+}
+
+// GroupBy groupby SQL
+func (b *Builder) GroupBy(groupby string) *Builder {
+	b.groupBy = groupby
+	return b
+}
+
+// Having having SQL
+func (b *Builder) Having(having string) *Builder {
+	b.having = having
+	return b
+}

+ 47 - 0
vendor/gitea.com/xorm/builder/builder_union.go

@@ -0,0 +1,47 @@
+// Copyright 2018 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	"fmt"
+	"strings"
+)
+
+func (b *Builder) unionWriteTo(w Writer) error {
+	if b.limitation != nil || b.cond.IsValid() ||
+		b.orderBy != "" || b.having != "" || b.groupBy != "" {
+		return ErrNotUnexpectedUnionConditions
+	}
+
+	for idx, u := range b.unions {
+		current := u.builder
+		if current.optype != selectType {
+			return ErrUnsupportedUnionMembers
+		}
+
+		if len(b.unions) == 1 {
+			if err := current.selectWriteTo(w); err != nil {
+				return err
+			}
+		} else {
+			if b.dialect != "" && b.dialect != current.dialect {
+				return ErrInconsistentDialect
+			}
+
+			if idx != 0 {
+				fmt.Fprint(w, fmt.Sprintf(" UNION %v ", strings.ToUpper(u.unionType)))
+			}
+			fmt.Fprint(w, "(")
+
+			if err := current.selectWriteTo(w); err != nil {
+				return err
+			}
+
+			fmt.Fprint(w, ")")
+		}
+	}
+
+	return nil
+}

+ 46 - 0
vendor/gitea.com/xorm/builder/builder_update.go

@@ -0,0 +1,46 @@
+// 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"
+)
+
+// Update creates an update Builder
+func Update(updates ...Eq) *Builder {
+	builder := &Builder{cond: NewCond()}
+	return builder.Update(updates...)
+}
+
+func (b *Builder) updateWriteTo(w Writer) error {
+	if len(b.from) <= 0 {
+		return ErrNoTableName
+	}
+	if len(b.updates) <= 0 {
+		return ErrNoColumnToUpdate
+	}
+
+	if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.from); 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)
+}

+ 74 - 0
vendor/gitea.com/xorm/builder/cond.go

@@ -0,0 +1,74 @@
+// 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 (
+	"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 *StringBuilder
+	args   []interface{}
+}
+
+// NewWriter creates a new string writer
+func NewWriter() *BytesWriter {
+	w := &BytesWriter{
+		writer: &StringBuilder{},
+	}
+	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
+}

+ 61 - 0
vendor/gitea.com/xorm/builder/cond_and.go

@@ -0,0 +1,61 @@
+// 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)
+		_, isExpr := cond.(expr)
+		wrap := isOr || isExpr
+		if wrap {
+			fmt.Fprint(w, "(")
+		}
+
+		err := cond.WriteTo(w)
+		if err != nil {
+			return err
+		}
+
+		if wrap {
+			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
+}

+ 65 - 0
vendor/gitea.com/xorm/builder/cond_between.go

@@ -0,0 +1,65 @@
+// 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 ", between.Col); err != nil {
+		return err
+	}
+	if lv, ok := between.LessVal.(expr); ok {
+		if err := lv.WriteTo(w); err != nil {
+			return err
+		}
+	} else {
+		if _, err := fmt.Fprint(w, "?"); err != nil {
+			return err
+		}
+		w.Append(between.LessVal)
+	}
+
+	if _, err := fmt.Fprint(w, " AND "); err != nil {
+		return err
+	}
+
+	if mv, ok := between.MoreVal.(expr); ok {
+		if err := mv.WriteTo(w); err != nil {
+			return err
+		}
+	} else {
+		if _, err := fmt.Fprint(w, "?"); err != nil {
+			return err
+		}
+		w.Append(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
+}

+ 160 - 0
vendor/gitea.com/xorm/builder/cond_compare.go

@@ -0,0 +1,160 @@
+// 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
+	keys := make([]string, 0, len(data))
+	for k := range data {
+		keys = append(keys, k)
+	}
+
+	for _, k := range keys {
+		v := data[k]
+		switch v.(type) {
+		case expr:
+			if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
+				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
+}

+ 112 - 0
vendor/gitea.com/xorm/builder/cond_eq.go

@@ -0,0 +1,112 @@
+// 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"
+	"sort"
+)
+
+// 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 := range eq.sortedKeys() {
+		v := eq[k]
+		switch v.(type) {
+		case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
+			if err := In(k, v).WriteTo(w); err != nil {
+				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
+}
+
+// sortedKeys returns all keys of this Eq sorted with sort.Strings.
+// It is used internally for consistent ordering when generating
+// SQL, see https://gitea.com/xorm/builder/issues/10
+func (eq Eq) sortedKeys() []string {
+	keys := make([]string, 0, len(eq))
+	for key := range eq {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	return keys
+}

+ 39 - 0
vendor/gitea.com/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
+}

+ 49 - 0
vendor/gitea.com/xorm/builder/cond_if.go

@@ -0,0 +1,49 @@
+// Copyright 2019 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 condIf struct {
+	condition bool
+	condTrue  Cond
+	condFalse Cond
+}
+
+var _ Cond = condIf{}
+
+// If returns Cond via condition
+func If(condition bool, condTrue Cond, condFalse ...Cond) Cond {
+	var c = condIf{
+		condition: condition,
+		condTrue:  condTrue,
+	}
+	if len(condFalse) > 0 {
+		c.condFalse = condFalse[0]
+	}
+	return c
+}
+
+func (condIf condIf) WriteTo(w Writer) error {
+	if condIf.condition {
+		return condIf.condTrue.WriteTo(w)
+	} else if condIf.condFalse != nil {
+		return condIf.condFalse.WriteTo(w)
+	}
+	return nil
+}
+
+func (condIf condIf) And(conds ...Cond) Cond {
+	return And(condIf, And(conds...))
+}
+
+func (condIf condIf) Or(conds ...Cond) Cond {
+	return Or(condIf, Or(conds...))
+}
+
+func (condIf condIf) IsValid() bool {
+	if condIf.condition {
+		return condIf.condTrue != nil
+	}
+	return condIf.condFalse != nil
+}

+ 237 - 0
vendor/gitea.com/xorm/builder/cond_in.go

@@ -0,0 +1,237 @@
+// 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 {
+	_, err := fmt.Fprint(w, "0=1")
+	return err
+}
+
+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/gitea.com/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 compatible, 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
+}

+ 94 - 0
vendor/gitea.com/xorm/builder/cond_neq.go

@@ -0,0 +1,94 @@
+// 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"
+	"sort"
+)
+
+// 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 := range neq.sortedKeys() {
+		v := neq[k]
+		switch v.(type) {
+		case []int, []int64, []string, []int32, []int16, []int8:
+			if err := NotIn(k, v).WriteTo(w); err != nil {
+				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
+}
+
+// sortedKeys returns all keys of this Neq sorted with sort.Strings.
+// It is used internally for consistent ordering when generating
+// SQL, see https://gitea.com/xorm/builder/issues/10
+func (neq Neq) sortedKeys() []string {
+	keys := make([]string, 0, len(neq))
+	for key := range neq {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	return keys
+}

+ 77 - 0
vendor/gitea.com/xorm/builder/cond_not.go

@@ -0,0 +1,77 @@
+// 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
+		}
+	case Eq:
+		if len(not[0].(Eq)) > 1 {
+			if _, err := fmt.Fprint(w, "("); err != nil {
+				return err
+			}
+		}
+	case Neq:
+		if len(not[0].(Neq)) > 1 {
+			if _, err := fmt.Fprint(w, "("); err != nil {
+				return err
+			}
+		}
+	}
+
+	if err := not[0].WriteTo(w); err != nil {
+		return err
+	}
+
+	switch not[0].(type) {
+	case condAnd, condOr:
+		if _, err := fmt.Fprint(w, ")"); err != nil {
+			return err
+		}
+	case Eq:
+		if len(not[0].(Eq)) > 1 {
+			if _, err := fmt.Fprint(w, ")"); err != nil {
+				return err
+			}
+		}
+	case Neq:
+		if len(not[0].(Neq)) > 1 {
+			if _, err := fmt.Fprint(w, ")"); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+// 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()
+}

+ 234 - 0
vendor/gitea.com/xorm/builder/cond_notin.go

@@ -0,0 +1,234 @@
+// 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 {
+	_, err := fmt.Fprint(w, "0=0")
+	return err
+}
+
+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/gitea.com/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
+}

+ 69 - 0
vendor/gitea.com/xorm/builder/cond_or.go

@@ -0,0 +1,69 @@
+// 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, expr:
+			needQuote = true
+		case Eq:
+			needQuote = (len(cond.(Eq)) > 1)
+		case Neq:
+			needQuote = (len(cond.(Neq)) > 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/gitea.com/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 xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/builder"
+
+    sql, args, _ := ToSQL(Like{"a", "c"})
+    // a LIKE ? [%c%]
+
+5. Expr you can customerize your sql with Expr
+
+    import . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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 . "xorm.io/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

+ 40 - 0
vendor/gitea.com/xorm/builder/error.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 "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")
+	// ErrNeedMoreArguments need more arguments
+	ErrNeedMoreArguments = errors.New("Need more sql arguments")
+	// ErrNoTableName no table name
+	ErrNoTableName = errors.New("No table indicated")
+	// ErrNoColumnToInsert no column to update
+	ErrNoColumnToUpdate = errors.New("No column(s) to update")
+	// ErrNoColumnToInsert no column to update
+	ErrNoColumnToInsert = errors.New("No column(s) to insert")
+	// ErrNotSupportDialectType not supported dialect type error
+	ErrNotSupportDialectType = errors.New("Not supported dialect type")
+	// ErrNotUnexpectedUnionConditions using union in a wrong way
+	ErrNotUnexpectedUnionConditions = errors.New("Unexpected conditional fields in UNION query")
+	// ErrUnsupportedUnionMembers unexpected members in UNION query
+	ErrUnsupportedUnionMembers = errors.New("Unexpected members in UNION query")
+	// ErrUnexpectedSubQuery Unexpected sub-query in SELECT query
+	ErrUnexpectedSubQuery = errors.New("Unexpected sub-query in SELECT query")
+	// ErrDialectNotSetUp dialect is not setup yet
+	ErrDialectNotSetUp = errors.New("Dialect is not setup yet, try to use `Dialect(dbType)` at first")
+	// ErrInvalidLimitation offset or limit is not correct
+	ErrInvalidLimitation = errors.New("Offset or limit is not correct")
+	// ErrUnnamedDerivedTable Every derived table must have its own alias
+	ErrUnnamedDerivedTable = errors.New("Every derived table must have its own alias")
+	// ErrInconsistentDialect Inconsistent dialect in same builder
+	ErrInconsistentDialect = errors.New("Inconsistent dialect in same builder")
+)

+ 6 - 0
vendor/gitea.com/xorm/builder/go.mod

@@ -0,0 +1,6 @@
+module xorm.io/builder
+
+require (
+	github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a
+	github.com/stretchr/testify v1.3.0
+)

+ 9 - 0
vendor/gitea.com/xorm/builder/go.sum

@@ -0,0 +1,9 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

+ 160 - 0
vendor/gitea.com/xorm/builder/sql.go

@@ -0,0 +1,160 @@
+// Copyright 2018 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package builder
+
+import (
+	sql2 "database/sql"
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+)
+
+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
+}
+
+func condToBoundSQL(cond Cond) (string, error) {
+	if cond == nil || !cond.IsValid() {
+		return "", nil
+	}
+
+	w := NewWriter()
+	if err := cond.WriteTo(w); err != nil {
+		return "", err
+	}
+	return ConvertToBoundSQL(w.writer.String(), w.args)
+}
+
+// ToSQL convert a builder or conditions 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
+}
+
+// ToBoundSQL convert a builder or conditions to parameters bound SQL
+func ToBoundSQL(cond interface{}) (string, error) {
+	switch cond.(type) {
+	case Cond:
+		return condToBoundSQL(cond.(Cond))
+	case *Builder:
+		return cond.(*Builder).ToBoundSQL()
+	}
+	return "", ErrNotSupportType
+}
+
+func noSQLQuoteNeeded(a interface{}) bool {
+	switch a.(type) {
+	case int, int8, int16, int32, int64:
+		return true
+	case uint, uint8, uint16, uint32, uint64:
+		return true
+	case float32, float64:
+		return true
+	case bool:
+		return true
+	case string:
+		return false
+	case time.Time, *time.Time:
+		return false
+	}
+
+	t := reflect.TypeOf(a)
+	switch t.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return true
+	case reflect.Float32, reflect.Float64:
+		return true
+	case reflect.Bool:
+		return true
+	case reflect.String:
+		return false
+	}
+
+	return false
+}
+
+// ConvertToBoundSQL will convert SQL and args to a bound SQL
+func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
+	buf := StringBuilder{}
+	var i, j, start int
+	for ; i < len(sql); i++ {
+		if sql[i] == '?' {
+			_, err := buf.WriteString(sql[start:i])
+			if err != nil {
+				return "", err
+			}
+			start = i + 1
+
+			if len(args) == j {
+				return "", ErrNeedMoreArguments
+			}
+
+			arg := args[j]
+			if namedArg, ok := arg.(sql2.NamedArg); ok {
+				arg = namedArg.Value
+			}
+
+			if noSQLQuoteNeeded(arg) {
+				_, err = fmt.Fprint(&buf, arg)
+			} else {
+				// replace ' -> '' (standard replacement) to avoid critical SQL injection,
+				// NOTICE: may allow some injection like % (or _) in LIKE query
+				_, err = fmt.Fprintf(&buf, "'%v'", strings.Replace(fmt.Sprintf("%v", arg), "'",
+					"''", -1))
+			}
+			if err != nil {
+				return "", err
+			}
+			j = j + 1
+		}
+	}
+	_, err := buf.WriteString(sql[start:])
+	if err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+}
+
+// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
+func ConvertPlaceholder(sql, prefix string) (string, error) {
+	buf := StringBuilder{}
+	var i, j, start int
+	for ; i < len(sql); i++ {
+		if sql[i] == '?' {
+			if _, err := buf.WriteString(sql[start:i]); err != nil {
+				return "", err
+			}
+
+			start = i + 1
+			j = j + 1
+
+			if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil {
+				return "", err
+			}
+		}
+	}
+
+	if _, err := buf.WriteString(sql[start:]); err != nil {
+		return "", err
+	}
+
+	return buf.String(), nil
+}

+ 119 - 0
vendor/gitea.com/xorm/builder/string_builder.go

@@ -0,0 +1,119 @@
+// Copyright 2017 The Go 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 (
+	"unicode/utf8"
+	"unsafe"
+)
+
+// A StringBuilder is used to efficiently build a string using Write methods.
+// It minimizes memory copying. The zero value is ready to use.
+// Do not copy a non-zero Builder.
+type StringBuilder struct {
+	addr *StringBuilder // of receiver, to detect copies by value
+	buf  []byte
+}
+
+// noescape hides a pointer from escape analysis.  noescape is
+// the identity function but escape analysis doesn't think the
+// output depends on the input. noescape is inlined and currently
+// compiles down to zero instructions.
+// USE CAREFULLY!
+// This was copied from the runtime; see issues 23382 and 7921.
+//go:nosplit
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+	x := uintptr(p)
+	return unsafe.Pointer(x ^ 0)
+}
+
+func (b *StringBuilder) copyCheck() {
+	if b.addr == nil {
+		// This hack works around a failing of Go's escape analysis
+		// that was causing b to escape and be heap allocated.
+		// See issue 23382.
+		// TODO: once issue 7921 is fixed, this should be reverted to
+		// just "b.addr = b".
+		b.addr = (*StringBuilder)(noescape(unsafe.Pointer(b)))
+	} else if b.addr != b {
+		panic("strings: illegal use of non-zero Builder copied by value")
+	}
+}
+
+// String returns the accumulated string.
+func (b *StringBuilder) String() string {
+	return *(*string)(unsafe.Pointer(&b.buf))
+}
+
+// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
+func (b *StringBuilder) Len() int { return len(b.buf) }
+
+// Reset resets the Builder to be empty.
+func (b *StringBuilder) Reset() {
+	b.addr = nil
+	b.buf = nil
+}
+
+// grow copies the buffer to a new, larger buffer so that there are at least n
+// bytes of capacity beyond len(b.buf).
+func (b *StringBuilder) grow(n int) {
+	buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
+	copy(buf, b.buf)
+	b.buf = buf
+}
+
+// Grow grows b's capacity, if necessary, to guarantee space for
+// another n bytes. After Grow(n), at least n bytes can be written to b
+// without another allocation. If n is negative, Grow panics.
+func (b *StringBuilder) Grow(n int) {
+	b.copyCheck()
+	if n < 0 {
+		panic("strings.Builder.Grow: negative count")
+	}
+	if cap(b.buf)-len(b.buf) < n {
+		b.grow(n)
+	}
+}
+
+// Write appends the contents of p to b's buffer.
+// Write always returns len(p), nil.
+func (b *StringBuilder) Write(p []byte) (int, error) {
+	b.copyCheck()
+	b.buf = append(b.buf, p...)
+	return len(p), nil
+}
+
+// WriteByte appends the byte c to b's buffer.
+// The returned error is always nil.
+func (b *StringBuilder) WriteByte(c byte) error {
+	b.copyCheck()
+	b.buf = append(b.buf, c)
+	return nil
+}
+
+// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
+// It returns the length of r and a nil error.
+func (b *StringBuilder) WriteRune(r rune) (int, error) {
+	b.copyCheck()
+	if r < utf8.RuneSelf {
+		b.buf = append(b.buf, byte(r))
+		return 1, nil
+	}
+	l := len(b.buf)
+	if cap(b.buf)-l < utf8.UTFMax {
+		b.grow(utf8.UTFMax)
+	}
+	n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r)
+	b.buf = b.buf[:l+n]
+	return n, nil
+}
+
+// WriteString appends the contents of s to b's buffer.
+// It returns the length of s and a nil error.
+func (b *StringBuilder) WriteString(s string) (int, error) {
+	b.copyCheck()
+	b.buf = append(b.buf, s...)
+	return len(s), nil
+}

+ 27 - 0
vendor/gitea.com/xorm/core/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2013 - 2015 Lunny Xiao <xiaolunwen@gmail.com>
+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.

+ 116 - 0
vendor/gitea.com/xorm/core/README.md

@@ -0,0 +1,116 @@
+Core is a lightweight wrapper of sql.DB.
+
+[![Build Status](https://drone.gitea.com/api/badges/xorm/core/status.svg)](https://drone.gitea.com/xorm/core)
+
+# Open
+```Go
+db, _ := core.Open(db, connstr)
+```
+
+# SetMapper
+```Go
+db.SetMapper(SameMapper())
+```
+
+## Scan usage
+
+### Scan
+```Go
+rows, _ := db.Query()
+for rows.Next() {
+    rows.Scan()
+}
+```
+
+### ScanMap
+```Go
+rows, _ := db.Query()
+for rows.Next() {
+    rows.ScanMap()
+```
+
+### ScanSlice
+
+You can use `[]string`, `[][]byte`, `[]interface{}`, `[]*string`, `[]sql.NullString` to ScanSclice. Notice, slice's length should be equal or less than select columns.
+
+```Go
+rows, _ := db.Query()
+cols, _ := rows.Columns()
+for rows.Next() {
+    var s = make([]string, len(cols))
+    rows.ScanSlice(&s)
+}
+```
+
+```Go
+rows, _ := db.Query()
+cols, _ := rows.Columns()
+for rows.Next() {
+    var s = make([]*string, len(cols))
+    rows.ScanSlice(&s)
+}
+```
+
+### ScanStruct
+```Go
+rows, _ := db.Query()
+for rows.Next() {
+    rows.ScanStructByName()
+    rows.ScanStructByIndex()
+}
+```
+
+## Query usage
+```Go
+rows, err := db.Query("select * from table where name = ?", name)
+
+user = User{
+    Name:"lunny",
+}
+rows, err := db.QueryStruct("select * from table where name = ?Name",
+            &user)
+
+var user = map[string]interface{}{
+    "name": "lunny",
+}
+rows, err = db.QueryMap("select * from table where name = ?name",
+            &user)
+```
+
+## QueryRow usage
+```Go
+row := db.QueryRow("select * from table where name = ?", name)
+
+user = User{
+    Name:"lunny",
+}
+row := db.QueryRowStruct("select * from table where name = ?Name",
+            &user)
+
+var user = map[string]interface{}{
+    "name": "lunny",
+}
+row = db.QueryRowMap("select * from table where name = ?name",
+            &user)
+```
+
+## Exec usage
+```Go
+db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)", name, title, age, alias...)
+
+user = User{
+    Name:"lunny",
+    Title:"test",
+    Age: 18,
+}
+result, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
+            &user)
+
+var user = map[string]interface{}{
+    "Name": "lunny",
+    "Title": "test",
+    "Age": 18,
+}
+result, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
+            &user)
+```

+ 1 - 0
vendor/gitea.com/xorm/core/benchmark.sh

@@ -0,0 +1 @@
+go test -v -bench=. -run=XXX

+ 95 - 0
vendor/gitea.com/xorm/core/cache.go

@@ -0,0 +1,95 @@
+// Copyright 2019 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 core
+
+import (
+	"bytes"
+	"encoding/gob"
+	"errors"
+	"fmt"
+	"strings"
+	"time"
+)
+
+const (
+	// CacheExpired is default cache expired time
+	CacheExpired = 60 * time.Minute
+	// CacheMaxMemory is not use now
+	CacheMaxMemory = 256
+	// CacheGcInterval represents interval time to clear all expired nodes
+	CacheGcInterval = 10 * time.Minute
+	// CacheGcMaxRemoved represents max nodes removed when gc
+	CacheGcMaxRemoved = 20
+)
+
+// list all the errors
+var (
+	ErrCacheMiss = errors.New("xorm/cache: key not found")
+	ErrNotStored = errors.New("xorm/cache: not stored")
+)
+
+// CacheStore is a interface to store cache
+type CacheStore interface {
+	// key is primary key or composite primary key
+	// value is struct's pointer
+	// key format : <tablename>-p-<pk1>-<pk2>...
+	Put(key string, value interface{}) error
+	Get(key string) (interface{}, error)
+	Del(key string) error
+}
+
+// Cacher is an interface to provide cache
+// id format : u-<pk1>-<pk2>...
+type Cacher interface {
+	GetIds(tableName, sql string) interface{}
+	GetBean(tableName string, id string) interface{}
+	PutIds(tableName, sql string, ids interface{})
+	PutBean(tableName string, id string, obj interface{})
+	DelIds(tableName, sql string)
+	DelBean(tableName string, id string)
+	ClearIds(tableName string)
+	ClearBeans(tableName string)
+}
+
+func encodeIds(ids []PK) (string, error) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(ids)
+
+	return buf.String(), err
+}
+
+func decodeIds(s string) ([]PK, error) {
+	pks := make([]PK, 0)
+
+	dec := gob.NewDecoder(strings.NewReader(s))
+	err := dec.Decode(&pks)
+
+	return pks, err
+}
+
+// GetCacheSql returns cacher PKs via SQL
+func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) {
+	bytes := m.GetIds(tableName, GenSqlKey(sql, args))
+	if bytes == nil {
+		return nil, errors.New("Not Exist")
+	}
+	return decodeIds(bytes.(string))
+}
+
+// PutCacheSql puts cacher SQL and PKs
+func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error {
+	bytes, err := encodeIds(ids)
+	if err != nil {
+		return err
+	}
+	m.PutIds(tableName, GenSqlKey(sql, args), bytes)
+	return nil
+}
+
+// GenSqlKey generates cache key
+func GenSqlKey(sql string, args interface{}) string {
+	return fmt.Sprintf("%v-%v", sql, args)
+}

+ 166 - 0
vendor/gitea.com/xorm/core/column.go

@@ -0,0 +1,166 @@
+// Copyright 2019 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 core
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+)
+
+const (
+	TWOSIDES = iota + 1
+	ONLYTODB
+	ONLYFROMDB
+)
+
+// Column defines database column
+type Column struct {
+	Name            string
+	TableName       string
+	FieldName       string
+	SQLType         SQLType
+	IsJSON          bool
+	Length          int
+	Length2         int
+	Nullable        bool
+	Default         string
+	Indexes         map[string]int
+	IsPrimaryKey    bool
+	IsAutoIncrement bool
+	MapType         int
+	IsCreated       bool
+	IsUpdated       bool
+	IsDeleted       bool
+	IsCascade       bool
+	IsVersion       bool
+	DefaultIsEmpty  bool
+	EnumOptions     map[string]int
+	SetOptions      map[string]int
+	DisableTimeZone bool
+	TimeZone        *time.Location // column specified time zone
+	Comment         string
+}
+
+// NewColumn creates a new column
+func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
+	return &Column{
+		Name:            name,
+		TableName:       "",
+		FieldName:       fieldName,
+		SQLType:         sqlType,
+		Length:          len1,
+		Length2:         len2,
+		Nullable:        nullable,
+		Default:         "",
+		Indexes:         make(map[string]int),
+		IsPrimaryKey:    false,
+		IsAutoIncrement: false,
+		MapType:         TWOSIDES,
+		IsCreated:       false,
+		IsUpdated:       false,
+		IsDeleted:       false,
+		IsCascade:       false,
+		IsVersion:       false,
+		DefaultIsEmpty:  false,
+		EnumOptions:     make(map[string]int),
+		Comment:         "",
+	}
+}
+
+// String generate column description string according dialect
+func (col *Column) String(d Dialect) string {
+	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
+
+	sql += d.SqlType(col) + " "
+
+	if col.IsPrimaryKey {
+		sql += "PRIMARY KEY "
+		if col.IsAutoIncrement {
+			sql += d.AutoIncrStr() + " "
+		}
+	}
+
+	if col.Default != "" {
+		sql += "DEFAULT " + col.Default + " "
+	}
+
+	if d.ShowCreateNull() {
+		if col.Nullable {
+			sql += "NULL "
+		} else {
+			sql += "NOT NULL "
+		}
+	}
+
+	return sql
+}
+
+// StringNoPk generate column description string according dialect without primary keys
+func (col *Column) StringNoPk(d Dialect) string {
+	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
+
+	sql += d.SqlType(col) + " "
+
+	if col.Default != "" {
+		sql += "DEFAULT " + col.Default + " "
+	}
+
+	if d.ShowCreateNull() {
+		if col.Nullable {
+			sql += "NULL "
+		} else {
+			sql += "NOT NULL "
+		}
+	}
+
+	return sql
+}
+
+// ValueOf returns column's filed of struct's value
+func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
+	dataStruct := reflect.Indirect(reflect.ValueOf(bean))
+	return col.ValueOfV(&dataStruct)
+}
+
+// ValueOfV returns column's filed of struct's value accept reflevt value
+func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
+	var fieldValue reflect.Value
+	fieldPath := strings.Split(col.FieldName, ".")
+
+	if dataStruct.Type().Kind() == reflect.Map {
+		keyValue := reflect.ValueOf(fieldPath[len(fieldPath)-1])
+		fieldValue = dataStruct.MapIndex(keyValue)
+		return &fieldValue, nil
+	} else if dataStruct.Type().Kind() == reflect.Interface {
+		structValue := reflect.ValueOf(dataStruct.Interface())
+		dataStruct = &structValue
+	}
+
+	level := len(fieldPath)
+	fieldValue = dataStruct.FieldByName(fieldPath[0])
+	for i := 0; i < level-1; i++ {
+		if !fieldValue.IsValid() {
+			break
+		}
+		if fieldValue.Kind() == reflect.Struct {
+			fieldValue = fieldValue.FieldByName(fieldPath[i+1])
+		} else if fieldValue.Kind() == reflect.Ptr {
+			if fieldValue.IsNil() {
+				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+			}
+			fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
+		} else {
+			return nil, fmt.Errorf("field %v is not valid", col.FieldName)
+		}
+	}
+
+	if !fieldValue.IsValid() {
+		return nil, fmt.Errorf("field %v is not valid", col.FieldName)
+	}
+
+	return &fieldValue, nil
+}

+ 12 - 0
vendor/gitea.com/xorm/core/converstion.go

@@ -0,0 +1,12 @@
+// Copyright 2019 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 core
+
+// Conversion is an interface. A type implements Conversion will according
+// the custom method to fill into database and retrieve from database.
+type Conversion interface {
+	FromDB([]byte) error
+	ToDB() ([]byte, error)
+}

+ 225 - 0
vendor/gitea.com/xorm/core/db.go

@@ -0,0 +1,225 @@
+// Copyright 2019 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 core
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"fmt"
+	"reflect"
+	"regexp"
+	"sync"
+)
+
+var (
+	DefaultCacheSize = 200
+)
+
+func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
+	vv := reflect.ValueOf(mp)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return "", []interface{}{}, ErrNoMapPointer
+	}
+
+	args := make([]interface{}, 0, len(vv.Elem().MapKeys()))
+	var err error
+	query = re.ReplaceAllStringFunc(query, func(src string) string {
+		v := vv.Elem().MapIndex(reflect.ValueOf(src[1:]))
+		if !v.IsValid() {
+			err = fmt.Errorf("map key %s is missing", src[1:])
+		} else {
+			args = append(args, v.Interface())
+		}
+		return "?"
+	})
+
+	return query, args, err
+}
+
+func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
+	vv := reflect.ValueOf(st)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return "", []interface{}{}, ErrNoStructPointer
+	}
+
+	args := make([]interface{}, 0)
+	var err error
+	query = re.ReplaceAllStringFunc(query, func(src string) string {
+		fv := vv.Elem().FieldByName(src[1:]).Interface()
+		if v, ok := fv.(driver.Valuer); ok {
+			var value driver.Value
+			value, err = v.Value()
+			if err != nil {
+				return "?"
+			}
+			args = append(args, value)
+		} else {
+			args = append(args, fv)
+		}
+		return "?"
+	})
+	if err != nil {
+		return "", []interface{}{}, err
+	}
+	return query, args, nil
+}
+
+type cacheStruct struct {
+	value reflect.Value
+	idx   int
+}
+
+// DB is a wrap of sql.DB with extra contents
+type DB struct {
+	*sql.DB
+	Mapper            IMapper
+	reflectCache      map[reflect.Type]*cacheStruct
+	reflectCacheMutex sync.RWMutex
+}
+
+// Open opens a database
+func Open(driverName, dataSourceName string) (*DB, error) {
+	db, err := sql.Open(driverName, dataSourceName)
+	if err != nil {
+		return nil, err
+	}
+	return &DB{
+		DB:           db,
+		Mapper:       NewCacheMapper(&SnakeMapper{}),
+		reflectCache: make(map[reflect.Type]*cacheStruct),
+	}, nil
+}
+
+// FromDB creates a DB from a sql.DB
+func FromDB(db *sql.DB) *DB {
+	return &DB{
+		DB:           db,
+		Mapper:       NewCacheMapper(&SnakeMapper{}),
+		reflectCache: make(map[reflect.Type]*cacheStruct),
+	}
+}
+
+func (db *DB) reflectNew(typ reflect.Type) reflect.Value {
+	db.reflectCacheMutex.Lock()
+	defer db.reflectCacheMutex.Unlock()
+	cs, ok := db.reflectCache[typ]
+	if !ok || cs.idx+1 > DefaultCacheSize-1 {
+		cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
+		db.reflectCache[typ] = cs
+	} else {
+		cs.idx = cs.idx + 1
+	}
+	return cs.value.Index(cs.idx).Addr()
+}
+
+// QueryContext overwrites sql.DB.QueryContext
+func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+	rows, err := db.DB.QueryContext(ctx, query, args...)
+	if err != nil {
+		if rows != nil {
+			rows.Close()
+		}
+		return nil, err
+	}
+	return &Rows{rows, db}, nil
+}
+
+// Query overwrites sql.DB.Query
+func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+	return db.QueryContext(context.Background(), query, args...)
+}
+
+// QueryMapContext executes query with parameters via map and context
+func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return nil, err
+	}
+	return db.QueryContext(ctx, query, args...)
+}
+
+// QueryMap executes query with parameters via map
+func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
+	return db.QueryMapContext(context.Background(), query, mp)
+}
+
+func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return nil, err
+	}
+	return db.QueryContext(ctx, query, args...)
+}
+
+func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
+	return db.QueryStructContext(context.Background(), query, st)
+}
+
+func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
+	rows, err := db.QueryContext(ctx, query, args...)
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return &Row{rows, nil}
+}
+
+func (db *DB) QueryRow(query string, args ...interface{}) *Row {
+	return db.QueryRowContext(context.Background(), query, args...)
+}
+
+func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return db.QueryRowContext(ctx, query, args...)
+}
+
+func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
+	return db.QueryRowMapContext(context.Background(), query, mp)
+}
+
+func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return db.QueryRowContext(ctx, query, args...)
+}
+
+func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
+	return db.QueryRowStructContext(context.Background(), query, st)
+}
+
+var (
+	re = regexp.MustCompile(`[?](\w+)`)
+)
+
+// insert into (name) values (?)
+// insert into (name) values (?name)
+func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return nil, err
+	}
+	return db.DB.ExecContext(ctx, query, args...)
+}
+
+func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) {
+	return db.ExecMapContext(context.Background(), query, mp)
+}
+
+func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return nil, err
+	}
+	return db.DB.ExecContext(ctx, query, args...)
+}
+
+func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
+	return db.ExecStructContext(context.Background(), query, st)
+}

+ 320 - 0
vendor/gitea.com/xorm/core/dialect.go

@@ -0,0 +1,320 @@
+// Copyright 2019 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 core
+
+import (
+	"fmt"
+	"strings"
+	"time"
+)
+
+type DbType string
+
+type Uri struct {
+	DbType  DbType
+	Proto   string
+	Host    string
+	Port    string
+	DbName  string
+	User    string
+	Passwd  string
+	Charset string
+	Laddr   string
+	Raddr   string
+	Timeout time.Duration
+	Schema  string
+}
+
+// a dialect is a driver's wrapper
+type Dialect interface {
+	SetLogger(logger ILogger)
+	Init(*DB, *Uri, string, string) error
+	URI() *Uri
+	DB() *DB
+	DBType() DbType
+	SqlType(*Column) string
+	FormatBytes(b []byte) string
+
+	DriverName() string
+	DataSourceName() string
+
+	QuoteStr() string
+	IsReserved(string) bool
+	Quote(string) string
+	AndStr() string
+	OrStr() string
+	EqStr() string
+	RollBackStr() string
+	AutoIncrStr() string
+
+	SupportInsertMany() bool
+	SupportEngine() bool
+	SupportCharset() bool
+	SupportDropIfExists() bool
+	IndexOnTable() bool
+	ShowCreateNull() bool
+
+	IndexCheckSql(tableName, idxName string) (string, []interface{})
+	TableCheckSql(tableName string) (string, []interface{})
+
+	IsColumnExist(tableName string, colName string) (bool, error)
+
+	CreateTableSql(table *Table, tableName, storeEngine, charset string) string
+	DropTableSql(tableName string) string
+	CreateIndexSql(tableName string, index *Index) string
+	DropIndexSql(tableName string, index *Index) string
+
+	ModifyColumnSql(tableName string, col *Column) string
+
+	ForUpdateSql(query string) string
+
+	//CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
+	//MustDropTable(tableName string) error
+
+	GetColumns(tableName string) ([]string, map[string]*Column, error)
+	GetTables() ([]*Table, error)
+	GetIndexes(tableName string) (map[string]*Index, error)
+
+	Filters() []Filter
+	SetParams(params map[string]string)
+}
+
+func OpenDialect(dialect Dialect) (*DB, error) {
+	return Open(dialect.DriverName(), dialect.DataSourceName())
+}
+
+// Base represents a basic dialect and all real dialects could embed this struct
+type Base struct {
+	db             *DB
+	dialect        Dialect
+	driverName     string
+	dataSourceName string
+	logger         ILogger
+	*Uri
+}
+
+func (b *Base) DB() *DB {
+	return b.db
+}
+
+func (b *Base) SetLogger(logger ILogger) {
+	b.logger = logger
+}
+
+func (b *Base) Init(db *DB, dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
+	b.db, b.dialect, b.Uri = db, dialect, uri
+	b.driverName, b.dataSourceName = drivername, dataSourceName
+	return nil
+}
+
+func (b *Base) URI() *Uri {
+	return b.Uri
+}
+
+func (b *Base) DBType() DbType {
+	return b.Uri.DbType
+}
+
+func (b *Base) FormatBytes(bs []byte) string {
+	return fmt.Sprintf("0x%x", bs)
+}
+
+func (b *Base) DriverName() string {
+	return b.driverName
+}
+
+func (b *Base) ShowCreateNull() bool {
+	return true
+}
+
+func (b *Base) DataSourceName() string {
+	return b.dataSourceName
+}
+
+func (b *Base) AndStr() string {
+	return "AND"
+}
+
+func (b *Base) OrStr() string {
+	return "OR"
+}
+
+func (b *Base) EqStr() string {
+	return "="
+}
+
+func (db *Base) RollBackStr() string {
+	return "ROLL BACK"
+}
+
+func (db *Base) SupportDropIfExists() bool {
+	return true
+}
+
+func (db *Base) DropTableSql(tableName string) string {
+	quote := db.dialect.Quote
+	return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))
+}
+
+func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
+	db.LogSQL(query, args)
+	rows, err := db.DB().Query(query, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (db *Base) IsColumnExist(tableName, colName string) (bool, error) {
+	query := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
+	query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1)
+	return db.HasRecords(query, db.DbName, tableName, colName)
+}
+
+/*
+func (db *Base) CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error {
+	sql, args := db.dialect.TableCheckSql(tableName)
+	rows, err := db.DB().Query(sql, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", sql, args)
+	}
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return nil
+	}
+
+	sql = db.dialect.CreateTableSql(table, tableName, storeEngine, charset)
+	_, err = db.DB().Exec(sql)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", sql)
+	}
+	return err
+}*/
+
+func (db *Base) CreateIndexSql(tableName string, index *Index) string {
+	quote := db.dialect.Quote
+	var unique string
+	var idxName string
+	if index.Type == UniqueType {
+		unique = " UNIQUE"
+	}
+	idxName = index.XName(tableName)
+	return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v)", unique,
+		quote(idxName), quote(tableName),
+		quote(strings.Join(index.Cols, quote(","))))
+}
+
+func (db *Base) DropIndexSql(tableName string, index *Index) string {
+	quote := db.dialect.Quote
+	var name string
+	if index.IsRegular {
+		name = index.XName(tableName)
+	} else {
+		name = index.Name
+	}
+	return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
+}
+
+func (db *Base) ModifyColumnSql(tableName string, col *Column) string {
+	return fmt.Sprintf("alter table %s MODIFY COLUMN %s", tableName, col.StringNoPk(db.dialect))
+}
+
+func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
+	var sql string
+	sql = "CREATE TABLE IF NOT EXISTS "
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql += b.dialect.Quote(tableName)
+	sql += " ("
+
+	if len(table.ColumnsSeq()) > 0 {
+		pkList := table.PrimaryKeys
+
+		for _, colName := range table.ColumnsSeq() {
+			col := table.GetColumn(colName)
+			if col.IsPrimaryKey && len(pkList) == 1 {
+				sql += col.String(b.dialect)
+			} else {
+				sql += col.StringNoPk(b.dialect)
+			}
+			sql = strings.TrimSpace(sql)
+			if b.DriverName() == MYSQL && len(col.Comment) > 0 {
+				sql += " COMMENT '" + col.Comment + "'"
+			}
+			sql += ", "
+		}
+
+		if len(pkList) > 1 {
+			sql += "PRIMARY KEY ( "
+			sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
+			sql += " ), "
+		}
+
+		sql = sql[:len(sql)-2]
+	}
+	sql += ")"
+
+	if b.dialect.SupportEngine() && storeEngine != "" {
+		sql += " ENGINE=" + storeEngine
+	}
+	if b.dialect.SupportCharset() {
+		if len(charset) == 0 {
+			charset = b.dialect.URI().Charset
+		}
+		if len(charset) > 0 {
+			sql += " DEFAULT CHARSET " + charset
+		}
+	}
+
+	return sql
+}
+
+func (b *Base) ForUpdateSql(query string) string {
+	return query + " FOR UPDATE"
+}
+
+func (b *Base) LogSQL(sql string, args []interface{}) {
+	if b.logger != nil && b.logger.IsShowSQL() {
+		if len(args) > 0 {
+			b.logger.Infof("[SQL] %v %v", sql, args)
+		} else {
+			b.logger.Infof("[SQL] %v", sql)
+		}
+	}
+}
+
+func (b *Base) SetParams(params map[string]string) {
+}
+
+var (
+	dialects = map[string]func() Dialect{}
+)
+
+// RegisterDialect register database dialect
+func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
+	if dialectFunc == nil {
+		panic("core: Register dialect is nil")
+	}
+	dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect
+}
+
+// QueryDialect query if registed database dialect
+func QueryDialect(dbName DbType) Dialect {
+	if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
+		return d()
+	}
+	return nil
+}

+ 31 - 0
vendor/gitea.com/xorm/core/driver.go

@@ -0,0 +1,31 @@
+// Copyright 2019 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 core
+
+type Driver interface {
+	Parse(string, string) (*Uri, error)
+}
+
+var (
+	drivers = map[string]Driver{}
+)
+
+func RegisterDriver(driverName string, driver Driver) {
+	if driver == nil {
+		panic("core: Register driver is nil")
+	}
+	if _, dup := drivers[driverName]; dup {
+		panic("core: Register called twice for driver " + driverName)
+	}
+	drivers[driverName] = driver
+}
+
+func QueryDriver(driverName string) Driver {
+	return drivers[driverName]
+}
+
+func RegisteredDriverSize() int {
+	return len(drivers)
+}

+ 12 - 0
vendor/gitea.com/xorm/core/error.go

@@ -0,0 +1,12 @@
+// Copyright 2019 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 core
+
+import "errors"
+
+var (
+	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
+	ErrNoStructPointer = errors.New("mp should be a struct's pointer")
+)

+ 68 - 0
vendor/gitea.com/xorm/core/filter.go

@@ -0,0 +1,68 @@
+// Copyright 2019 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 core
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Filter is an interface to filter SQL
+type Filter interface {
+	Do(sql string, dialect Dialect, table *Table) string
+}
+
+// QuoteFilter filter SQL replace ` to database's own quote character
+type QuoteFilter struct {
+}
+
+func (s *QuoteFilter) Do(sql string, dialect Dialect, table *Table) string {
+	return strings.Replace(sql, "`", dialect.QuoteStr(), -1)
+}
+
+// IdFilter filter SQL replace (id) to primary key column name
+type IdFilter struct {
+}
+
+type Quoter struct {
+	dialect Dialect
+}
+
+func NewQuoter(dialect Dialect) *Quoter {
+	return &Quoter{dialect}
+}
+
+func (q *Quoter) Quote(content string) string {
+	return q.dialect.QuoteStr() + content + q.dialect.QuoteStr()
+}
+
+func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string {
+	quoter := NewQuoter(dialect)
+	if table != nil && len(table.PrimaryKeys) == 1 {
+		sql = strings.Replace(sql, " `(id)` ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
+		sql = strings.Replace(sql, " "+quoter.Quote("(id)")+" ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
+		return strings.Replace(sql, " (id) ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
+	}
+	return sql
+}
+
+// SeqFilter filter SQL replace ?, ? ... to $1, $2 ...
+type SeqFilter struct {
+	Prefix string
+	Start  int
+}
+
+func (s *SeqFilter) Do(sql string, dialect Dialect, table *Table) string {
+	segs := strings.Split(sql, "?")
+	size := len(segs)
+	res := ""
+	for i, c := range segs {
+		if i < size-1 {
+			res += c + fmt.Sprintf("%s%v", s.Prefix, i+s.Start)
+		}
+	}
+	res += segs[size-1]
+	return res
+}

+ 13 - 0
vendor/gitea.com/xorm/core/go.mod

@@ -0,0 +1,13 @@
+module xorm.io/core
+
+require (
+	github.com/go-sql-driver/mysql v1.4.1
+	github.com/golang/protobuf v1.3.1 // indirect
+	github.com/mattn/go-sqlite3 v1.10.0
+	golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect
+	golang.org/x/net v0.0.0-20190603091049-60506f45cf65 // indirect
+	golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect
+	golang.org/x/text v0.3.2 // indirect
+	golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 // indirect
+	google.golang.org/appengine v1.6.0 // indirect
+)

+ 23 - 0
vendor/gitea.com/xorm/core/go.sum

@@ -0,0 +1,23 @@
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

+ 35 - 0
vendor/gitea.com/xorm/core/ilogger.go

@@ -0,0 +1,35 @@
+// Copyright 2019 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 core
+
+type LogLevel int
+
+const (
+	// !nashtsai! following level also match syslog.Priority value
+	LOG_DEBUG LogLevel = iota
+	LOG_INFO
+	LOG_WARNING
+	LOG_ERR
+	LOG_OFF
+	LOG_UNKNOWN
+)
+
+// logger interface
+type ILogger interface {
+	Debug(v ...interface{})
+	Debugf(format string, v ...interface{})
+	Error(v ...interface{})
+	Errorf(format string, v ...interface{})
+	Info(v ...interface{})
+	Infof(format string, v ...interface{})
+	Warn(v ...interface{})
+	Warnf(format string, v ...interface{})
+
+	Level() LogLevel
+	SetLevel(l LogLevel)
+
+	ShowSQL(show ...bool)
+	IsShowSQL() bool
+}

+ 71 - 0
vendor/gitea.com/xorm/core/index.go

@@ -0,0 +1,71 @@
+// Copyright 2019 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 core
+
+import (
+	"fmt"
+	"strings"
+)
+
+const (
+	IndexType = iota + 1
+	UniqueType
+)
+
+// database index
+type Index struct {
+	IsRegular bool
+	Name      string
+	Type      int
+	Cols      []string
+}
+
+func (index *Index) XName(tableName string) string {
+	if !strings.HasPrefix(index.Name, "UQE_") &&
+		!strings.HasPrefix(index.Name, "IDX_") {
+		tableName = strings.Replace(tableName, `"`, "", -1)
+		tableName = strings.Replace(tableName, `.`, "_", -1)
+		if index.Type == UniqueType {
+			return fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+		}
+		return fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+	}
+	return index.Name
+}
+
+// add columns which will be composite index
+func (index *Index) AddColumn(cols ...string) {
+	for _, col := range cols {
+		index.Cols = append(index.Cols, col)
+	}
+}
+
+func (index *Index) Equal(dst *Index) bool {
+	if index.Type != dst.Type {
+		return false
+	}
+	if len(index.Cols) != len(dst.Cols) {
+		return false
+	}
+
+	for i := 0; i < len(index.Cols); i++ {
+		var found bool
+		for j := 0; j < len(dst.Cols); j++ {
+			if index.Cols[i] == dst.Cols[j] {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return false
+		}
+	}
+	return true
+}
+
+// new an index
+func NewIndex(name string, indexType int) *Index {
+	return &Index{true, name, indexType, make([]string, 0)}
+}

+ 258 - 0
vendor/gitea.com/xorm/core/mapper.go

@@ -0,0 +1,258 @@
+// Copyright 2019 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 core
+
+import (
+	"strings"
+	"sync"
+)
+
+// name translation between struct, fields names and table, column names
+type IMapper interface {
+	Obj2Table(string) string
+	Table2Obj(string) string
+}
+
+type CacheMapper struct {
+	oriMapper      IMapper
+	obj2tableCache map[string]string
+	obj2tableMutex sync.RWMutex
+	table2objCache map[string]string
+	table2objMutex sync.RWMutex
+}
+
+func NewCacheMapper(mapper IMapper) *CacheMapper {
+	return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string),
+		table2objCache: make(map[string]string),
+	}
+}
+
+func (m *CacheMapper) Obj2Table(o string) string {
+	m.obj2tableMutex.RLock()
+	t, ok := m.obj2tableCache[o]
+	m.obj2tableMutex.RUnlock()
+	if ok {
+		return t
+	}
+
+	t = m.oriMapper.Obj2Table(o)
+	m.obj2tableMutex.Lock()
+	m.obj2tableCache[o] = t
+	m.obj2tableMutex.Unlock()
+	return t
+}
+
+func (m *CacheMapper) Table2Obj(t string) string {
+	m.table2objMutex.RLock()
+	o, ok := m.table2objCache[t]
+	m.table2objMutex.RUnlock()
+	if ok {
+		return o
+	}
+
+	o = m.oriMapper.Table2Obj(t)
+	m.table2objMutex.Lock()
+	m.table2objCache[t] = o
+	m.table2objMutex.Unlock()
+	return o
+}
+
+// SameMapper implements IMapper and provides same name between struct and
+// database table
+type SameMapper struct {
+}
+
+func (m SameMapper) Obj2Table(o string) string {
+	return o
+}
+
+func (m SameMapper) Table2Obj(t string) string {
+	return t
+}
+
+// SnakeMapper implements IMapper and provides name transaltion between
+// struct and database table
+type SnakeMapper struct {
+}
+
+func snakeCasedName(name string) string {
+	newstr := make([]rune, 0)
+	for idx, chr := range name {
+		if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
+			if idx > 0 {
+				newstr = append(newstr, '_')
+			}
+			chr -= ('A' - 'a')
+		}
+		newstr = append(newstr, chr)
+	}
+
+	return string(newstr)
+}
+
+func (mapper SnakeMapper) Obj2Table(name string) string {
+	return snakeCasedName(name)
+}
+
+func titleCasedName(name string) string {
+	newstr := make([]rune, 0)
+	upNextChar := true
+
+	name = strings.ToLower(name)
+
+	for _, chr := range name {
+		switch {
+		case upNextChar:
+			upNextChar = false
+			if 'a' <= chr && chr <= 'z' {
+				chr -= ('a' - 'A')
+			}
+		case chr == '_':
+			upNextChar = true
+			continue
+		}
+
+		newstr = append(newstr, chr)
+	}
+
+	return string(newstr)
+}
+
+func (mapper SnakeMapper) Table2Obj(name string) string {
+	return titleCasedName(name)
+}
+
+// GonicMapper implements IMapper. It will consider initialisms when mapping names.
+// E.g. id -> ID, user -> User and to table names: UserID -> user_id, MyUID -> my_uid
+type GonicMapper map[string]bool
+
+func isASCIIUpper(r rune) bool {
+	return 'A' <= r && r <= 'Z'
+}
+
+func toASCIIUpper(r rune) rune {
+	if 'a' <= r && r <= 'z' {
+		r -= ('a' - 'A')
+	}
+	return r
+}
+
+func gonicCasedName(name string) string {
+	newstr := make([]rune, 0, len(name)+3)
+	for idx, chr := range name {
+		if isASCIIUpper(chr) && idx > 0 {
+			if !isASCIIUpper(newstr[len(newstr)-1]) {
+				newstr = append(newstr, '_')
+			}
+		}
+
+		if !isASCIIUpper(chr) && idx > 1 {
+			l := len(newstr)
+			if isASCIIUpper(newstr[l-1]) && isASCIIUpper(newstr[l-2]) {
+				newstr = append(newstr, newstr[l-1])
+				newstr[l-1] = '_'
+			}
+		}
+
+		newstr = append(newstr, chr)
+	}
+	return strings.ToLower(string(newstr))
+}
+
+func (mapper GonicMapper) Obj2Table(name string) string {
+	return gonicCasedName(name)
+}
+
+func (mapper GonicMapper) Table2Obj(name string) string {
+	newstr := make([]rune, 0)
+
+	name = strings.ToLower(name)
+	parts := strings.Split(name, "_")
+
+	for _, p := range parts {
+		_, isInitialism := mapper[strings.ToUpper(p)]
+		for i, r := range p {
+			if i == 0 || isInitialism {
+				r = toASCIIUpper(r)
+			}
+			newstr = append(newstr, r)
+		}
+	}
+
+	return string(newstr)
+}
+
+// A GonicMapper that contains a list of common initialisms taken from golang/lint
+var LintGonicMapper = GonicMapper{
+	"API":   true,
+	"ASCII": true,
+	"CPU":   true,
+	"CSS":   true,
+	"DNS":   true,
+	"EOF":   true,
+	"GUID":  true,
+	"HTML":  true,
+	"HTTP":  true,
+	"HTTPS": true,
+	"ID":    true,
+	"IP":    true,
+	"JSON":  true,
+	"LHS":   true,
+	"QPS":   true,
+	"RAM":   true,
+	"RHS":   true,
+	"RPC":   true,
+	"SLA":   true,
+	"SMTP":  true,
+	"SSH":   true,
+	"TLS":   true,
+	"TTL":   true,
+	"UI":    true,
+	"UID":   true,
+	"UUID":  true,
+	"URI":   true,
+	"URL":   true,
+	"UTF8":  true,
+	"VM":    true,
+	"XML":   true,
+	"XSRF":  true,
+	"XSS":   true,
+}
+
+// provide prefix table name support
+type PrefixMapper struct {
+	Mapper IMapper
+	Prefix string
+}
+
+func (mapper PrefixMapper) Obj2Table(name string) string {
+	return mapper.Prefix + mapper.Mapper.Obj2Table(name)
+}
+
+func (mapper PrefixMapper) Table2Obj(name string) string {
+	return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):])
+}
+
+func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper {
+	return PrefixMapper{mapper, prefix}
+}
+
+// provide suffix table name support
+type SuffixMapper struct {
+	Mapper IMapper
+	Suffix string
+}
+
+func (mapper SuffixMapper) Obj2Table(name string) string {
+	return mapper.Mapper.Obj2Table(name) + mapper.Suffix
+}
+
+func (mapper SuffixMapper) Table2Obj(name string) string {
+	return mapper.Mapper.Table2Obj(name[:len(name)-len(mapper.Suffix)])
+}
+
+func NewSuffixMapper(mapper IMapper, suffix string) SuffixMapper {
+	return SuffixMapper{mapper, suffix}
+}

+ 30 - 0
vendor/gitea.com/xorm/core/pk.go

@@ -0,0 +1,30 @@
+// Copyright 2019 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 core
+
+import (
+	"bytes"
+	"encoding/gob"
+)
+
+type PK []interface{}
+
+func NewPK(pks ...interface{}) *PK {
+	p := PK(pks)
+	return &p
+}
+
+func (p *PK) ToString() (string, error) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(*p)
+	return buf.String(), err
+}
+
+func (p *PK) FromString(content string) error {
+	dec := gob.NewDecoder(bytes.NewBufferString(content))
+	err := dec.Decode(p)
+	return err
+}

+ 338 - 0
vendor/gitea.com/xorm/core/rows.go

@@ -0,0 +1,338 @@
+// Copyright 2019 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 core
+
+import (
+	"database/sql"
+	"errors"
+	"reflect"
+	"sync"
+)
+
+type Rows struct {
+	*sql.Rows
+	db *DB
+}
+
+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.db.Mapper.Table2Obj(name))
+		if f.IsValid() {
+			newDest[j] = f.Addr().Interface()
+		} else {
+			newDest[j] = &v
+		}
+	}
+
+	return rs.Rows.Scan(newDest...)
+}
+
+// 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] = rs.db.reflectNew(vvv.Type().Elem()).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
+}
+
+type Row struct {
+	rows *Rows
+	// One of these two will be non-nil:
+	err error // deferred error for easy chaining
+}
+
+// ErrorRow return an error row
+func ErrorRow(err error) *Row {
+	return &Row{
+		err: err,
+	}
+}
+
+// NewRow from rows
+func NewRow(rows *Rows, err error) *Row {
+	return &Row{rows, err}
+}
+
+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
+}

+ 66 - 0
vendor/gitea.com/xorm/core/scan.go

@@ -0,0 +1,66 @@
+// Copyright 2019 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 core
+
+import (
+	"database/sql/driver"
+	"fmt"
+	"time"
+)
+
+type NullTime time.Time
+
+var (
+	_ driver.Valuer = NullTime{}
+)
+
+func (ns *NullTime) Scan(value interface{}) error {
+	if value == nil {
+		return nil
+	}
+	return convertTime(ns, value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullTime) Value() (driver.Value, error) {
+	if (time.Time)(ns).IsZero() {
+		return nil, nil
+	}
+	return (time.Time)(ns).Format("2006-01-02 15:04:05"), nil
+}
+
+func convertTime(dest *NullTime, src interface{}) error {
+	// Common cases, without reflect.
+	switch s := src.(type) {
+	case string:
+		t, err := time.Parse("2006-01-02 15:04:05", s)
+		if err != nil {
+			return err
+		}
+		*dest = NullTime(t)
+		return nil
+	case []uint8:
+		t, err := time.Parse("2006-01-02 15:04:05", string(s))
+		if err != nil {
+			return err
+		}
+		*dest = NullTime(t)
+		return nil
+	case time.Time:
+		*dest = NullTime(s)
+		return nil
+	case nil:
+	default:
+		return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
+	}
+	return nil
+}
+
+type EmptyScanner struct {
+}
+
+func (EmptyScanner) Scan(src interface{}) error {
+	return nil
+}

+ 165 - 0
vendor/gitea.com/xorm/core/stmt.go

@@ -0,0 +1,165 @@
+// Copyright 2019 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 core
+
+import (
+	"context"
+	"database/sql"
+	"errors"
+	"reflect"
+)
+
+type Stmt struct {
+	*sql.Stmt
+	db    *DB
+	names map[string]int
+}
+
+func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+	names := make(map[string]int)
+	var i int
+	query = re.ReplaceAllStringFunc(query, func(src string) string {
+		names[src[1:]] = i
+		i += 1
+		return "?"
+	})
+
+	stmt, err := db.DB.PrepareContext(ctx, query)
+	if err != nil {
+		return nil, err
+	}
+	return &Stmt{stmt, db, names}, nil
+}
+
+func (db *DB) Prepare(query string) (*Stmt, error) {
+	return db.PrepareContext(context.Background(), query)
+}
+
+func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) {
+	vv := reflect.ValueOf(mp)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return nil, errors.New("mp should be a map's pointer")
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
+	}
+	return s.Stmt.ExecContext(ctx, args...)
+}
+
+func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
+	return s.ExecMapContext(context.Background(), mp)
+}
+
+func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) {
+	vv := reflect.ValueOf(st)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return nil, errors.New("mp should be a map's pointer")
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().FieldByName(k).Interface()
+	}
+	return s.Stmt.ExecContext(ctx, args...)
+}
+
+func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
+	return s.ExecStructContext(context.Background(), st)
+}
+
+func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
+	rows, err := s.Stmt.QueryContext(ctx, args...)
+	if err != nil {
+		return nil, err
+	}
+	return &Rows{rows, s.db}, nil
+}
+
+func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
+	return s.QueryContext(context.Background(), args...)
+}
+
+func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) {
+	vv := reflect.ValueOf(mp)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return nil, errors.New("mp should be a map's pointer")
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
+	}
+
+	return s.QueryContext(ctx, args...)
+}
+
+func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
+	return s.QueryMapContext(context.Background(), mp)
+}
+
+func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) {
+	vv := reflect.ValueOf(st)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return nil, errors.New("mp should be a map's pointer")
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().FieldByName(k).Interface()
+	}
+
+	return s.Query(args...)
+}
+
+func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
+	return s.QueryStructContext(context.Background(), st)
+}
+
+func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
+	rows, err := s.QueryContext(ctx, args...)
+	return &Row{rows, err}
+}
+
+func (s *Stmt) QueryRow(args ...interface{}) *Row {
+	return s.QueryRowContext(context.Background(), args...)
+}
+
+func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row {
+	vv := reflect.ValueOf(mp)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return &Row{nil, errors.New("mp should be a map's pointer")}
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
+	}
+
+	return s.QueryRowContext(ctx, args...)
+}
+
+func (s *Stmt) QueryRowMap(mp interface{}) *Row {
+	return s.QueryRowMapContext(context.Background(), mp)
+}
+
+func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row {
+	vv := reflect.ValueOf(st)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return &Row{nil, errors.New("st should be a struct's pointer")}
+	}
+
+	args := make([]interface{}, len(s.names))
+	for k, i := range s.names {
+		args[i] = vv.Elem().FieldByName(k).Interface()
+	}
+
+	return s.QueryRowContext(ctx, args...)
+}
+
+func (s *Stmt) QueryRowStruct(st interface{}) *Row {
+	return s.QueryRowStructContext(context.Background(), st)
+}

+ 154 - 0
vendor/gitea.com/xorm/core/table.go

@@ -0,0 +1,154 @@
+// Copyright 2019 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 core
+
+import (
+	"reflect"
+	"strings"
+)
+
+// database table
+type Table struct {
+	Name          string
+	Type          reflect.Type
+	columnsSeq    []string
+	columnsMap    map[string][]*Column
+	columns       []*Column
+	Indexes       map[string]*Index
+	PrimaryKeys   []string
+	AutoIncrement string
+	Created       map[string]bool
+	Updated       string
+	Deleted       string
+	Version       string
+	Cacher        Cacher
+	StoreEngine   string
+	Charset       string
+	Comment       string
+}
+
+func (table *Table) Columns() []*Column {
+	return table.columns
+}
+
+func (table *Table) ColumnsSeq() []string {
+	return table.columnsSeq
+}
+
+func NewEmptyTable() *Table {
+	return NewTable("", nil)
+}
+
+func NewTable(name string, t reflect.Type) *Table {
+	return &Table{Name: name, Type: t,
+		columnsSeq:  make([]string, 0),
+		columns:     make([]*Column, 0),
+		columnsMap:  make(map[string][]*Column),
+		Indexes:     make(map[string]*Index),
+		Created:     make(map[string]bool),
+		PrimaryKeys: make([]string, 0),
+	}
+}
+
+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 {
+
+	cols := table.columnsByName(name)
+
+	if cols != nil {
+		return cols[0]
+	}
+
+	return nil
+}
+
+func (table *Table) GetColumnIdx(name string, idx int) *Column {
+	cols := table.columnsByName(name)
+
+	if cols != nil && idx < len(cols) {
+		return cols[idx]
+	}
+
+	return nil
+}
+
+// if has primary key, return column
+func (table *Table) PKColumns() []*Column {
+	columns := make([]*Column, len(table.PrimaryKeys))
+	for i, name := range table.PrimaryKeys {
+		columns[i] = table.GetColumn(name)
+	}
+	return columns
+}
+
+func (table *Table) ColumnType(name string) reflect.Type {
+	t, _ := table.Type.FieldByName(name)
+	return t.Type
+}
+
+func (table *Table) AutoIncrColumn() *Column {
+	return table.GetColumn(table.AutoIncrement)
+}
+
+func (table *Table) VersionColumn() *Column {
+	return table.GetColumn(table.Version)
+}
+
+func (table *Table) UpdatedColumn() *Column {
+	return table.GetColumn(table.Updated)
+}
+
+func (table *Table) DeletedColumn() *Column {
+	return table.GetColumn(table.Deleted)
+}
+
+// add a column to table
+func (table *Table) AddColumn(col *Column) {
+	table.columnsSeq = append(table.columnsSeq, col.Name)
+	table.columns = append(table.columns, col)
+	colName := strings.ToLower(col.Name)
+	if c, ok := table.columnsMap[colName]; ok {
+		table.columnsMap[colName] = append(c, col)
+	} else {
+		table.columnsMap[colName] = []*Column{col}
+	}
+
+	if col.IsPrimaryKey {
+		table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
+	}
+	if col.IsAutoIncrement {
+		table.AutoIncrement = col.Name
+	}
+	if col.IsCreated {
+		table.Created[col.Name] = true
+	}
+	if col.IsUpdated {
+		table.Updated = col.Name
+	}
+	if col.IsDeleted {
+		table.Deleted = col.Name
+	}
+	if col.IsVersion {
+		table.Version = col.Name
+	}
+}
+
+// add an index or an unique to table
+func (table *Table) AddIndex(index *Index) {
+	table.Indexes[index.Name] = index
+}

+ 153 - 0
vendor/gitea.com/xorm/core/tx.go

@@ -0,0 +1,153 @@
+// Copyright 2019 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 core
+
+import (
+	"context"
+	"database/sql"
+)
+
+type Tx struct {
+	*sql.Tx
+	db *DB
+}
+
+func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
+	tx, err := db.DB.BeginTx(ctx, opts)
+	if err != nil {
+		return nil, err
+	}
+	return &Tx{tx, db}, nil
+}
+
+func (db *DB) Begin() (*Tx, error) {
+	tx, err := db.DB.Begin()
+	if err != nil {
+		return nil, err
+	}
+	return &Tx{tx, db}, nil
+}
+
+func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+	names := make(map[string]int)
+	var i int
+	query = re.ReplaceAllStringFunc(query, func(src string) string {
+		names[src[1:]] = i
+		i += 1
+		return "?"
+	})
+
+	stmt, err := tx.Tx.PrepareContext(ctx, query)
+	if err != nil {
+		return nil, err
+	}
+	return &Stmt{stmt, tx.db, names}, nil
+}
+
+func (tx *Tx) Prepare(query string) (*Stmt, error) {
+	return tx.PrepareContext(context.Background(), query)
+}
+
+func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
+	stmt.Stmt = tx.Tx.StmtContext(ctx, stmt.Stmt)
+	return stmt
+}
+
+func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+	return tx.StmtContext(context.Background(), stmt)
+}
+
+func (tx *Tx) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return nil, err
+	}
+	return tx.Tx.ExecContext(ctx, query, args...)
+}
+
+func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) {
+	return tx.ExecMapContext(context.Background(), query, mp)
+}
+
+func (tx *Tx) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return nil, err
+	}
+	return tx.Tx.ExecContext(ctx, query, args...)
+}
+
+func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) {
+	return tx.ExecStructContext(context.Background(), query, st)
+}
+
+func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+	rows, err := tx.Tx.QueryContext(ctx, query, args...)
+	if err != nil {
+		return nil, err
+	}
+	return &Rows{rows, tx.db}, nil
+}
+
+func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
+	return tx.QueryContext(context.Background(), query, args...)
+}
+
+func (tx *Tx) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return nil, err
+	}
+	return tx.QueryContext(ctx, query, args...)
+}
+
+func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) {
+	return tx.QueryMapContext(context.Background(), query, mp)
+}
+
+func (tx *Tx) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return nil, err
+	}
+	return tx.QueryContext(ctx, query, args...)
+}
+
+func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) {
+	return tx.QueryStructContext(context.Background(), query, st)
+}
+
+func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
+	rows, err := tx.QueryContext(ctx, query, args...)
+	return &Row{rows, err}
+}
+
+func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
+	return tx.QueryRowContext(context.Background(), query, args...)
+}
+
+func (tx *Tx) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row {
+	query, args, err := MapToSlice(query, mp)
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return tx.QueryRowContext(ctx, query, args...)
+}
+
+func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
+	return tx.QueryRowMapContext(context.Background(), query, mp)
+}
+
+func (tx *Tx) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row {
+	query, args, err := StructToSlice(query, st)
+	if err != nil {
+		return &Row{nil, err}
+	}
+	return tx.QueryRowContext(ctx, query, args...)
+}
+
+func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
+	return tx.QueryRowStructContext(context.Background(), query, st)
+}

+ 323 - 0
vendor/gitea.com/xorm/core/type.go

@@ -0,0 +1,323 @@
+// Copyright 2019 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 core
+
+import (
+	"reflect"
+	"sort"
+	"strings"
+	"time"
+)
+
+const (
+	POSTGRES = "postgres"
+	SQLITE   = "sqlite3"
+	MYSQL    = "mysql"
+	MSSQL    = "mssql"
+	ORACLE   = "oracle"
+)
+
+// xorm SQL types
+type SQLType struct {
+	Name           string
+	DefaultLength  int
+	DefaultLength2 int
+}
+
+const (
+	UNKNOW_TYPE = iota
+	TEXT_TYPE
+	BLOB_TYPE
+	TIME_TYPE
+	NUMERIC_TYPE
+)
+
+func (s *SQLType) IsType(st int) bool {
+	if t, ok := SqlTypes[s.Name]; ok && t == st {
+		return true
+	}
+	return false
+}
+
+func (s *SQLType) IsText() bool {
+	return s.IsType(TEXT_TYPE)
+}
+
+func (s *SQLType) IsBlob() bool {
+	return s.IsType(BLOB_TYPE)
+}
+
+func (s *SQLType) IsTime() bool {
+	return s.IsType(TIME_TYPE)
+}
+
+func (s *SQLType) IsNumeric() bool {
+	return s.IsType(NUMERIC_TYPE)
+}
+
+func (s *SQLType) IsJson() bool {
+	return s.Name == Json || s.Name == Jsonb
+}
+
+var (
+	Bit       = "BIT"
+	TinyInt   = "TINYINT"
+	SmallInt  = "SMALLINT"
+	MediumInt = "MEDIUMINT"
+	Int       = "INT"
+	Integer   = "INTEGER"
+	BigInt    = "BIGINT"
+
+	Enum = "ENUM"
+	Set  = "SET"
+
+	Char             = "CHAR"
+	Varchar          = "VARCHAR"
+	NChar            = "NCHAR"
+	NVarchar         = "NVARCHAR"
+	TinyText         = "TINYTEXT"
+	Text             = "TEXT"
+	NText            = "NTEXT"
+	Clob             = "CLOB"
+	MediumText       = "MEDIUMTEXT"
+	LongText         = "LONGTEXT"
+	Uuid             = "UUID"
+	UniqueIdentifier = "UNIQUEIDENTIFIER"
+	SysName          = "SYSNAME"
+
+	Date       = "DATE"
+	DateTime   = "DATETIME"
+	SmallDateTime   = "SMALLDATETIME"
+	Time       = "TIME"
+	TimeStamp  = "TIMESTAMP"
+	TimeStampz = "TIMESTAMPZ"
+
+	Decimal = "DECIMAL"
+	Numeric = "NUMERIC"
+	Money   = "MONEY"
+	SmallMoney = "SMALLMONEY"
+
+	Real   = "REAL"
+	Float  = "FLOAT"
+	Double = "DOUBLE"
+
+	Binary     = "BINARY"
+	VarBinary  = "VARBINARY"
+	TinyBlob   = "TINYBLOB"
+	Blob       = "BLOB"
+	MediumBlob = "MEDIUMBLOB"
+	LongBlob   = "LONGBLOB"
+	Bytea      = "BYTEA"
+
+	Bool    = "BOOL"
+	Boolean = "BOOLEAN"
+
+	Serial    = "SERIAL"
+	BigSerial = "BIGSERIAL"
+
+	Json  = "JSON"
+	Jsonb = "JSONB"
+
+	SqlTypes = map[string]int{
+		Bit:       NUMERIC_TYPE,
+		TinyInt:   NUMERIC_TYPE,
+		SmallInt:  NUMERIC_TYPE,
+		MediumInt: NUMERIC_TYPE,
+		Int:       NUMERIC_TYPE,
+		Integer:   NUMERIC_TYPE,
+		BigInt:    NUMERIC_TYPE,
+
+		Enum:  TEXT_TYPE,
+		Set:   TEXT_TYPE,
+		Json:  TEXT_TYPE,
+		Jsonb: TEXT_TYPE,
+
+		Char:       TEXT_TYPE,
+		NChar:      TEXT_TYPE,
+		Varchar:    TEXT_TYPE,
+		NVarchar:   TEXT_TYPE,
+		TinyText:   TEXT_TYPE,
+		Text:       TEXT_TYPE,
+		NText:      TEXT_TYPE,
+		MediumText: TEXT_TYPE,
+		LongText:   TEXT_TYPE,
+		Uuid:       TEXT_TYPE,
+		Clob:       TEXT_TYPE,
+		SysName:    TEXT_TYPE,
+
+		Date:       TIME_TYPE,
+		DateTime:   TIME_TYPE,
+		Time:       TIME_TYPE,
+		TimeStamp:  TIME_TYPE,
+		TimeStampz: TIME_TYPE,
+		SmallDateTime:   TIME_TYPE,
+
+		Decimal: NUMERIC_TYPE,
+		Numeric: NUMERIC_TYPE,
+		Real:    NUMERIC_TYPE,
+		Float:   NUMERIC_TYPE,
+		Double:  NUMERIC_TYPE,
+		Money:   NUMERIC_TYPE,
+		SmallMoney: NUMERIC_TYPE,
+
+		Binary:    BLOB_TYPE,
+		VarBinary: BLOB_TYPE,
+
+		TinyBlob:         BLOB_TYPE,
+		Blob:             BLOB_TYPE,
+		MediumBlob:       BLOB_TYPE,
+		LongBlob:         BLOB_TYPE,
+		Bytea:            BLOB_TYPE,
+		UniqueIdentifier: BLOB_TYPE,
+
+		Bool: NUMERIC_TYPE,
+
+		Serial:    NUMERIC_TYPE,
+		BigSerial: NUMERIC_TYPE,
+	}
+
+	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
+	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
+)
+
+// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
+var (
+	c_EMPTY_STRING       string
+	c_BOOL_DEFAULT       bool
+	c_BYTE_DEFAULT       byte
+	c_COMPLEX64_DEFAULT  complex64
+	c_COMPLEX128_DEFAULT complex128
+	c_FLOAT32_DEFAULT    float32
+	c_FLOAT64_DEFAULT    float64
+	c_INT64_DEFAULT      int64
+	c_UINT64_DEFAULT     uint64
+	c_INT32_DEFAULT      int32
+	c_UINT32_DEFAULT     uint32
+	c_INT16_DEFAULT      int16
+	c_UINT16_DEFAULT     uint16
+	c_INT8_DEFAULT       int8
+	c_UINT8_DEFAULT      uint8
+	c_INT_DEFAULT        int
+	c_UINT_DEFAULT       uint
+	c_TIME_DEFAULT       time.Time
+)
+
+var (
+	IntType   = reflect.TypeOf(c_INT_DEFAULT)
+	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
+	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
+	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
+	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)
+
+	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
+	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
+	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
+	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
+	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)
+
+	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
+	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)
+
+	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
+	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)
+
+	StringType = reflect.TypeOf(c_EMPTY_STRING)
+	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
+	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
+	BytesType  = reflect.SliceOf(ByteType)
+
+	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
+)
+
+var (
+	PtrIntType   = reflect.PtrTo(IntType)
+	PtrInt8Type  = reflect.PtrTo(Int8Type)
+	PtrInt16Type = reflect.PtrTo(Int16Type)
+	PtrInt32Type = reflect.PtrTo(Int32Type)
+	PtrInt64Type = reflect.PtrTo(Int64Type)
+
+	PtrUintType   = reflect.PtrTo(UintType)
+	PtrUint8Type  = reflect.PtrTo(Uint8Type)
+	PtrUint16Type = reflect.PtrTo(Uint16Type)
+	PtrUint32Type = reflect.PtrTo(Uint32Type)
+	PtrUint64Type = reflect.PtrTo(Uint64Type)
+
+	PtrFloat32Type = reflect.PtrTo(Float32Type)
+	PtrFloat64Type = reflect.PtrTo(Float64Type)
+
+	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
+	PtrComplex128Type = reflect.PtrTo(Complex128Type)
+
+	PtrStringType = reflect.PtrTo(StringType)
+	PtrBoolType   = reflect.PtrTo(BoolType)
+	PtrByteType   = reflect.PtrTo(ByteType)
+
+	PtrTimeType = reflect.PtrTo(TimeType)
+)
+
+// Type2SQLType generate SQLType acorrding Go's type
+func Type2SQLType(t reflect.Type) (st SQLType) {
+	switch k := t.Kind(); k {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+		st = SQLType{Int, 0, 0}
+	case reflect.Int64, reflect.Uint64:
+		st = SQLType{BigInt, 0, 0}
+	case reflect.Float32:
+		st = SQLType{Float, 0, 0}
+	case reflect.Float64:
+		st = SQLType{Double, 0, 0}
+	case reflect.Complex64, reflect.Complex128:
+		st = SQLType{Varchar, 64, 0}
+	case reflect.Array, reflect.Slice, reflect.Map:
+		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
+			st = SQLType{Blob, 0, 0}
+		} else {
+			st = SQLType{Text, 0, 0}
+		}
+	case reflect.Bool:
+		st = SQLType{Bool, 0, 0}
+	case reflect.String:
+		st = SQLType{Varchar, 255, 0}
+	case reflect.Struct:
+		if t.ConvertibleTo(TimeType) {
+			st = SQLType{DateTime, 0, 0}
+		} else {
+			// TODO need to handle association struct
+			st = SQLType{Text, 0, 0}
+		}
+	case reflect.Ptr:
+		st = Type2SQLType(t.Elem())
+	default:
+		st = SQLType{Text, 0, 0}
+	}
+	return
+}
+
+// default sql type change to go types
+func SQLType2Type(st SQLType) reflect.Type {
+	name := strings.ToUpper(st.Name)
+	switch name {
+	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
+		return reflect.TypeOf(1)
+	case BigInt, BigSerial:
+		return reflect.TypeOf(int64(1))
+	case Float, Real:
+		return reflect.TypeOf(float32(1))
+	case Double:
+		return reflect.TypeOf(float64(1))
+	case Char, NChar, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
+		return reflect.TypeOf("")
+	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
+		return reflect.TypeOf([]byte{})
+	case Bool:
+		return reflect.TypeOf(true)
+	case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime:
+		return reflect.TypeOf(c_TIME_DEFAULT)
+	case Decimal, Numeric, Money, SmallMoney:
+		return reflect.TypeOf("")
+	default:
+		return reflect.TypeOf("")
+	}
+}

+ 46 - 0
vendor/gitea.com/xorm/xorm/CONTRIBUTING.md

@@ -0,0 +1,46 @@
+## Contributing to xorm
+
+`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very
+much welcome. You can help with patch review, submitting bug reports,
+or adding new functionality. There is no formal style guide, but
+please conform to the style of existing code and general Go formatting
+conventions when submitting patches.
+
+* [fork a repo](https://help.github.com/articles/fork-a-repo)
+* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
+
+### Language
+
+Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible.
+
+### Sign your codes with comments
+```
+// !<you github id>! your comments
+
+e.g.,
+
+// !lunny! this is comments made by lunny
+```
+
+### Patch review
+
+Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or
+proposed functionality.
+
+### Bug reports
+
+We appreciate any bug reports, but especially ones with self-contained
+(doesn't depend on code outside of xorm), minimal (can't be simplified
+further) test cases. It's especially helpful if you can submit a pull
+request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)).
+
+If you implements a new database interface, you maybe need to add a test_<databasename>.sh file.
+For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh)
+
+### New functionality
+
+There are a number of pending patches for new functionality, so
+additional feature patches will take a while to merge. Still, patches
+are generally reviewed based on usefulness and complexity in addition
+to time-in-queue, so if you have a knockout idea, take a shot. Feel
+free to open an issue discussion your proposed patch beforehand.

+ 27 - 0
vendor/gitea.com/xorm/xorm/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2013 - 2015 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.

+ 496 - 0
vendor/gitea.com/xorm/xorm/README.md

@@ -0,0 +1,496 @@
+# xorm
+
+[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md)
+
+Xorm is a simple and powerful ORM for Go.
+
+[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
+[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) 
+[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
+
+## Features
+
+* Struct <-> Table Mapping Support
+
+* Chainable APIs
+
+* Transaction Support
+
+* Both ORM and raw SQL operation Support
+
+* Sync database schema Support
+
+* Query Cache speed up
+
+* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md)
+
+* Simple cascade loading support
+
+* Optimistic Locking support
+
+* SQL Builder support via [xorm.io/builder](https://xorm.io/builder)
+
+* Automatical Read/Write seperatelly
+
+* Postgres schema support
+
+* Context Cache support
+
+## Drivers Support
+
+Drivers for Go's sql package which currently support database/sql includes:
+
+* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+
+* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv)
+
+* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
+
+* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
+
+* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+
+* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
+
+* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
+
+## Installation
+
+	go get github.com/go-xorm/xorm
+
+## Documents
+
+* [Manual](http://xorm.io/docs)
+
+* [GoDoc](http://godoc.org/github.com/go-xorm/xorm)
+
+## Quick Start
+
+* Create Engine
+
+```Go
+engine, err := xorm.NewEngine(driverName, dataSourceName)
+```
+
+* Define a struct and Sync2 table struct to database
+
+```Go
+type User struct {
+    Id int64
+    Name string
+    Salt string
+    Age int
+    Passwd string `xorm:"varchar(200)"`
+    Created time.Time `xorm:"created"`
+    Updated time.Time `xorm:"updated"`
+}
+
+err := engine.Sync2(new(User))
+```
+
+* Create Engine Group
+
+```Go
+dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
+engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
+```
+
+```Go
+masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
+slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
+slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
+engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
+```
+
+Then all place where `engine` you can just use `engineGroup`.
+
+* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`.
+
+```Go
+results, err := engine.Query("select * from user")
+results, err := engine.Where("a = 1").Query()
+
+results, err := engine.QueryString("select * from user")
+results, err := engine.Where("a = 1").QueryString()
+
+results, err := engine.QueryInterface("select * from user")
+results, err := engine.Where("a = 1").QueryInterface()
+```
+
+* `Exec` runs a SQL string, it returns `affected` and `error`
+
+```Go
+affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
+```
+
+* `Insert` one or multiple records to database
+
+```Go
+affected, err := engine.Insert(&user)
+// INSERT INTO struct () values ()
+
+affected, err := engine.Insert(&user1, &user2)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values ()
+
+affected, err := engine.Insert(&users)
+// INSERT INTO struct () values (),(),()
+
+affected, err := engine.Insert(&user1, &users)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values (),(),()
+```
+
+* `Get` query one record from database
+
+```Go
+has, err := engine.Get(&user)
+// SELECT * FROM user LIMIT 1
+
+has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
+// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
+
+var name string
+has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name)
+// SELECT name FROM user WHERE id = ?
+
+var id int64
+has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
+has, err := engine.SQL("select id from user").Get(&id)
+// SELECT id FROM user WHERE name = ?
+
+var valuesMap = make(map[string]string)
+has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
+// SELECT * FROM user WHERE id = ?
+
+var valuesSlice = make([]interface{}, len(cols))
+has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
+// SELECT col1, col2, col3 FROM user WHERE id = ?
+```
+
+* `Exist` check if one record exist on table
+
+```Go
+has, err := testEngine.Exist(new(RecordExist))
+// SELECT * FROM record_exist LIMIT 1
+
+has, err = testEngine.Exist(&RecordExist{
+		Name: "test1",
+	})
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+
+has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+
+has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
+// select * from record_exist where name = ?
+
+has, err = testEngine.Table("record_exist").Exist()
+// SELECT * FROM record_exist LIMIT 1
+
+has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+```
+
+* `Find` query multiple records from database, also you can use join and extends
+
+```Go
+var users []User
+err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
+// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
+
+type Detail struct {
+    Id int64
+    UserId int64 `xorm:"index"`
+}
+
+type UserDetail struct {
+    User `xorm:"extends"`
+    Detail `xorm:"extends"`
+}
+
+var users []UserDetail
+err := engine.Table("user").Select("user.*, detail.*").
+    Join("INNER", "detail", "detail.user_id = user.id").
+    Where("user.name = ?", name).Limit(10, 0).
+    Find(&users)
+// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
+```
+
+* `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows
+
+```Go
+err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user
+
+err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user Limit 0, 100
+// SELECT * FROM user Limit 101, 100
+
+rows, err := engine.Rows(&User{Name:name})
+// SELECT * FROM user
+defer rows.Close()
+bean := new(Struct)
+for rows.Next() {
+    err = rows.Scan(bean)
+}
+```
+
+* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
+
+```Go
+affected, err := engine.ID(1).Update(&user)
+// UPDATE user SET ... Where id = ?
+
+affected, err := engine.Update(&user, &User{Name:name})
+// UPDATE user SET ... Where name = ?
+
+var ids = []int64{1, 2, 3}
+affected, err := engine.In("id", ids).Update(&user)
+// UPDATE user SET ... Where id IN (?, ?, ?)
+
+// force update indicated columns by Cols
+affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+// force NOT update indicated columns by Omit
+affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+affected, err := engine.ID(1).AllCols().Update(&user)
+// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
+```
+
+* `Delete` delete one or more records, Delete MUST have condition
+
+```Go
+affected, err := engine.Where(...).Delete(&user)
+// DELETE FROM user Where ...
+
+affected, err := engine.ID(2).Delete(&user)
+// DELETE FROM user Where id = ?
+```
+
+* `Count` count records
+
+```Go
+counts, err := engine.Count(&user)
+// SELECT count(*) AS total FROM user
+```
+
+* `Sum` sum functions
+
+```Go
+agesFloat64, err := engine.Sum(&user, "age")
+// SELECT sum(age) AS total FROM user
+
+agesInt64, err := engine.SumInt(&user, "age")
+// SELECT sum(age) AS total FROM user
+
+sumFloat64Slice, err := engine.Sums(&user, "age", "score")
+// SELECT sum(age), sum(score) FROM user
+
+sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
+// SELECT sum(age), sum(score) 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 (?, ?, ?)
+```
+
+* Multiple operations in one go routine, no transation here but resue session memory
+
+```Go
+session := engine.NewSession()
+defer session.Close()
+
+user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+if _, err := session.Insert(&user1); err != nil {
+    return err
+}
+
+user2 := Userinfo{Username: "yyy"}
+if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+    return err
+}
+
+if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+    return err
+}
+
+return nil
+```
+
+* Transation should on one go routine. There is transaction and resue session memory
+
+```Go
+session := engine.NewSession()
+defer session.Close()
+
+// add Begin() before any action
+if err := session.Begin(); err != nil {
+    // if returned then will rollback automatically
+    return err
+}
+
+user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+if _, err := session.Insert(&user1); err != nil {
+    return err
+}
+
+user2 := Userinfo{Username: "yyy"}
+if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+    return err
+}
+
+if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+    return err
+}
+
+// add Commit() after all actions
+return session.Commit()
+```
+
+* Or you can use `Transaction` to replace above codes.
+
+```Go
+res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
+    user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+    if _, err := session.Insert(&user1); err != nil {
+        return nil, err
+    }
+
+    user2 := Userinfo{Username: "yyy"}
+    if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+        return nil, err
+    }
+
+    if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+        return nil, err
+    }
+    return nil, nil
+})
+```
+
+* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
+
+```Go
+	sess := engine.NewSession()
+	defer sess.Close()
+
+	var context = xorm.NewMemoryContextCache()
+
+	var c2 ContextGetStruct
+	has, err := sess.ID(1).ContextCache(context).Get(&c2)
+	assert.NoError(t, err)
+	assert.True(t, has)
+	assert.EqualValues(t, 1, c2.Id)
+	assert.EqualValues(t, "1", c2.Name)
+	sql, args := sess.LastSQL()
+	assert.True(t, len(sql) > 0)
+	assert.True(t, len(args) > 0)
+
+	var c3 ContextGetStruct
+	has, err = sess.ID(1).ContextCache(context).Get(&c3)
+	assert.NoError(t, err)
+	assert.True(t, has)
+	assert.EqualValues(t, 1, c3.Id)
+	assert.EqualValues(t, "1", c3.Name)
+	sql, args = sess.LastSQL()
+	assert.True(t, len(sql) == 0)
+	assert.True(t, len(args) == 0)
+```
+
+## Contributing
+
+If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.
+
+## Credits
+
+### Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
+
+### Backers
+
+Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/xorm#backer)]
+
+<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
+
+### Sponsors
+
+Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/xorm#sponsor)]
+
+## Changelog
+
+* **v0.7.0**
+    * Some bugs fixed
+
+* **v0.6.6**
+    * Some bugs fixed
+
+* **v0.6.5**
+    * Postgres schema support
+    * vgo support
+    * Add FindAndCount
+    * Database special params support via NewEngineWithParams
+    * Some bugs fixed
+
+* **v0.6.4**
+    * Automatical Read/Write seperatelly
+    * Query/QueryString/QueryInterface and action with Where/And
+    * Get support non-struct variables
+    * BufferSize on Iterate
+    * fix some other bugs.
+
+[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
+
+## Cases
+
+* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
+
+* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
+
+* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
+
+* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
+
+* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
+
+* [Wego](http://github.com/go-tango/wego)
+
+* [Docker.cn](https://docker.cn/)
+
+* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
+
+* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel)
+
+* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
+
+* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
+
+* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
+
+* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
+
+* [YouGam](http://www.yougam.com/)
+
+* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
+
+* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
+
+* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
+
+## LICENSE
+
+BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)

+ 500 - 0
vendor/gitea.com/xorm/xorm/README_CN.md

@@ -0,0 +1,500 @@
+# xorm
+
+[English](https://github.com/go-xorm/xorm/blob/master/README.md)
+
+xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
+
+[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
+[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
+[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
+
+## 特性
+
+* 支持Struct和数据库表之间的灵活映射,并支持自动同步
+
+* 事务支持
+
+* 同时支持原始SQL语句和ORM操作的混合执行
+
+* 使用连写来简化调用
+
+* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
+
+* 支持级联加载Struct
+
+* Schema支持(仅Postgres)
+
+* 支持缓存
+
+* 支持根据数据库自动生成xorm的结构体
+
+* 支持记录版本(即乐观锁)
+
+* 内置SQL Builder支持
+
+* 上下文缓存支持
+
+## 驱动支持
+
+目前支持的Go数据库驱动和对应的数据库如下:
+
+* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+
+* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
+
+* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
+
+* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
+
+* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+
+* 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) (试验性支持)
+
+## 安装
+
+	go get github.com/go-xorm/xorm
+
+## 文档
+
+* [操作指南](http://xorm.io/docs)
+
+* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm)
+
+* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
+
+# 快速开始
+
+* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同
+
+```Go
+engine, err := xorm.NewEngine(driverName, dataSourceName)
+```
+
+* 定义一个和表同步的结构体,并且自动同步结构体到数据库
+
+```Go
+type User struct {
+    Id int64
+    Name string
+    Salt string
+    Age int
+    Passwd string `xorm:"varchar(200)"`
+    Created time.Time `xorm:"created"`
+    Updated time.Time `xorm:"updated"`
+}
+
+err := engine.Sync2(new(User))
+```
+
+* 创建Engine组
+
+```Go
+dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
+engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
+```
+
+```Go
+masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
+slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
+slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
+engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
+```
+
+所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。
+
+* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`.
+
+```Go
+results, err := engine.Query("select * from user")
+results, err := engine.Where("a = 1").Query()
+
+results, err := engine.QueryString("select * from user")
+results, err := engine.Where("a = 1").QueryString()
+
+results, err := engine.QueryInterface("select * from user")
+results, err := engine.Where("a = 1").QueryInterface()
+```
+
+* `Exec` 执行一个SQL语句
+
+```Go
+affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
+```
+
+* `Insert` 插入一条或者多条记录
+
+```Go
+affected, err := engine.Insert(&user)
+// INSERT INTO struct () values ()
+
+affected, err := engine.Insert(&user1, &user2)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values ()
+
+affected, err := engine.Insert(&users)
+// INSERT INTO struct () values (),(),()
+
+affected, err := engine.Insert(&user1, &users)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values (),(),()
+```
+
+* `Get` 查询单条记录
+
+```Go
+has, err := engine.Get(&user)
+// SELECT * FROM user LIMIT 1
+
+has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
+// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
+
+var name string
+has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name)
+// SELECT name FROM user WHERE id = ?
+
+var id int64
+has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
+has, err := engine.SQL("select id from user").Get(&id)
+// SELECT id FROM user WHERE name = ?
+
+var valuesMap = make(map[string]string)
+has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
+// SELECT * FROM user WHERE id = ?
+
+var valuesSlice = make([]interface{}, len(cols))
+has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
+// SELECT col1, col2, col3 FROM user WHERE id = ?
+```
+
+* `Exist` 检测记录是否存在
+
+```Go
+has, err := testEngine.Exist(new(RecordExist))
+// SELECT * FROM record_exist LIMIT 1
+
+has, err = testEngine.Exist(&RecordExist{
+		Name: "test1",
+	})
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+
+has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+
+has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
+// select * from record_exist where name = ?
+
+has, err = testEngine.Table("record_exist").Exist()
+// SELECT * FROM record_exist LIMIT 1
+
+has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
+// SELECT * FROM record_exist WHERE name = ? LIMIT 1
+```
+
+* `Find` 查询多条记录,当然可以使用Join和extends来组合使用
+
+```Go
+var users []User
+err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
+// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
+
+type Detail struct {
+    Id int64
+    UserId int64 `xorm:"index"`
+}
+
+type UserDetail struct {
+    User `xorm:"extends"`
+    Detail `xorm:"extends"`
+}
+
+var users []UserDetail
+err := engine.Table("user").Select("user.*, detail.*")
+    Join("INNER", "detail", "detail.user_id = user.id").
+    Where("user.name = ?", name).Limit(10, 0).
+    Find(&users)
+// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
+```
+
+* `Iterate` 和 `Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows
+
+```Go
+err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user
+
+err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user Limit 0, 100
+// SELECT * FROM user Limit 101, 100
+
+rows, err := engine.Rows(&User{Name:name})
+// SELECT * FROM user
+defer rows.Close()
+bean := new(Struct)
+for rows.Next() {
+    err = rows.Scan(bean)
+}
+```
+
+* `Update` 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
+
+```Go
+affected, err := engine.ID(1).Update(&user)
+// UPDATE user SET ... Where id = ?
+
+affected, err := engine.Update(&user, &User{Name:name})
+// UPDATE user SET ... Where name = ?
+
+var ids = []int64{1, 2, 3}
+affected, err := engine.In(ids).Update(&user)
+// UPDATE user SET ... Where id IN (?, ?, ?)
+
+// force update indicated columns by Cols
+affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+// force NOT update indicated columns by Omit
+affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+affected, err := engine.ID(1).AllCols().Update(&user)
+// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
+```
+
+* `Delete` 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
+
+```Go
+affected, err := engine.Where(...).Delete(&user)
+// DELETE FROM user Where ...
+
+affected, err := engine.ID(2).Delete(&user)
+// DELETE FROM user Where id = ?
+```
+
+* `Count` 获取记录条数
+
+```Go
+counts, err := engine.Count(&user)
+// SELECT count(*) AS total FROM user
+```
+
+* `Sum` 求和函数
+
+```Go
+agesFloat64, err := engine.Sum(&user, "age")
+// SELECT sum(age) AS total FROM user
+
+agesInt64, err := engine.SumInt(&user, "age")
+// SELECT sum(age) AS total FROM user
+
+sumFloat64Slice, err := engine.Sums(&user, "age", "score")
+// SELECT sum(age), sum(score) FROM user
+
+sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
+// SELECT sum(age), sum(score) 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 (?, ?, ?)
+```
+
+* 在一个Go程中多次操作数据库,但没有事务
+
+```Go
+session := engine.NewSession()
+defer session.Close()
+
+user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+if _, err := session.Insert(&user1); err != nil {
+    return err
+}
+
+user2 := Userinfo{Username: "yyy"}
+if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+    return err
+}
+
+if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+    return err
+}
+
+return nil
+```
+
+* 在一个Go程中有事务
+
+```Go
+session := engine.NewSession()
+defer session.Close()
+
+// add Begin() before any action
+if err := session.Begin(); err != nil {
+    // if returned then will rollback automatically
+    return err
+}
+
+user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+if _, err := session.Insert(&user1); err != nil {
+    return err
+}
+
+user2 := Userinfo{Username: "yyy"}
+if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+    return err
+}
+
+if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+    return err
+}
+
+// add Commit() after all actions
+return session.Commit()
+```
+
+* 事务的简写方法
+
+```Go
+res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
+    user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
+    if _, err := session.Insert(&user1); err != nil {
+        return nil, err
+    }
+
+    user2 := Userinfo{Username: "yyy"}
+    if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
+        return nil, err
+    }
+
+    if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
+        return nil, err
+    }
+    return nil, nil
+})
+```
+
+* 上下文缓存,如果启用,那么针对单个对象的查询将会被缓存到系统中,可以被下一个查询使用。
+
+```Go
+	sess := engine.NewSession()
+	defer sess.Close()
+
+	var context = xorm.NewMemoryContextCache()
+
+	var c2 ContextGetStruct
+	has, err := sess.ID(1).ContextCache(context).Get(&c2)
+	assert.NoError(t, err)
+	assert.True(t, has)
+	assert.EqualValues(t, 1, c2.Id)
+	assert.EqualValues(t, "1", c2.Name)
+	sql, args := sess.LastSQL()
+	assert.True(t, len(sql) > 0)
+	assert.True(t, len(args) > 0)
+
+	var c3 ContextGetStruct
+	has, err = sess.ID(1).ContextCache(context).Get(&c3)
+	assert.NoError(t, err)
+	assert.True(t, has)
+	assert.EqualValues(t, 1, c3.Id)
+	assert.EqualValues(t, "1", c3.Name)
+	sql, args = sess.LastSQL()
+	assert.True(t, len(sql) == 0)
+	assert.True(t, len(args) == 0)
+```
+
+## 贡献
+
+如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群  技术帮助和讨论。
+群一:280360085 (已满)
+群二:795010183
+
+## Credits
+
+### Contributors
+
+感谢所有的贡献者. [[Contribute](CONTRIBUTING.md)].
+<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
+
+### Backers
+
+感谢我们所有的 backers! 🙏 [[成为 backer](https://opencollective.com/xorm#backer)]
+
+<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
+
+### Sponsors
+
+成为 sponsor 来支持 xorm。您的 logo 将会被显示并被链接到您的网站。 [[成为 sponsor](https://opencollective.com/xorm#sponsor)]
+
+# 案例
+
+* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
+
+* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
+
+* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
+
+* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
+
+* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
+
+* [Wego](http://github.com/go-tango/wego)
+
+* [Docker.cn](https://docker.cn/)
+
+* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
+
+* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
+
+* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
+
+* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
+
+* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
+
+* [YouGam](http://www.yougam.com/)
+
+* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
+
+* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
+
+* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
+
+
+## 更新日志
+
+* **v0.7.0**
+    * 修正部分Bug
+
+* **v0.6.6**
+    * 修正部分Bug
+
+* **v0.6.5**
+    * 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres
+    * vgo 支持
+    * 新增 `FindAndCount` 函数
+    * 通过 `NewEngineWithParams` 支持数据库特别参数
+    * 修正部分Bug
+
+* **v0.6.4**
+    * 自动读写分离支持
+    * Query/QueryString/QueryInterface 支持与 Where/And 合用
+    * `Get` 支持获取非结构体变量
+    * `Iterate` 支持 `BufferSize` 
+    * 修正部分Bug
+
+[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
+
+## LICENSE
+
+BSD License
+[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)

+ 284 - 0
vendor/gitea.com/xorm/xorm/cache_lru.go

@@ -0,0 +1,284 @@
+// 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 (
+	"container/list"
+	"fmt"
+	"sync"
+	"time"
+
+	"xorm.io/core"
+)
+
+// LRUCacher implments cache object facilities
+type LRUCacher struct {
+	idList         *list.List
+	sqlList        *list.List
+	idIndex        map[string]map[string]*list.Element
+	sqlIndex       map[string]map[string]*list.Element
+	store          core.CacheStore
+	mutex          sync.Mutex
+	MaxElementSize int
+	Expired        time.Duration
+	GcInterval     time.Duration
+}
+
+// NewLRUCacher creates a cacher
+func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
+	return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
+}
+
+// NewLRUCacher2 creates a cache include different params
+func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
+	cacher := &LRUCacher{store: store, idList: list.New(),
+		sqlList: list.New(), Expired: expired,
+		GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
+		sqlIndex: make(map[string]map[string]*list.Element),
+		idIndex:  make(map[string]map[string]*list.Element),
+	}
+	cacher.RunGC()
+	return cacher
+}
+
+// RunGC run once every m.GcInterval
+func (m *LRUCacher) RunGC() {
+	time.AfterFunc(m.GcInterval, func() {
+		m.RunGC()
+		m.GC()
+	})
+}
+
+// GC check ids lit and sql list to remove all element expired
+func (m *LRUCacher) GC() {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	var removedNum int
+	for e := m.idList.Front(); e != nil; {
+		if removedNum <= core.CacheGcMaxRemoved &&
+			time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
+			removedNum++
+			next := e.Next()
+			node := e.Value.(*idNode)
+			m.delBean(node.tbName, node.id)
+			e = next
+		} else {
+			break
+		}
+	}
+
+	removedNum = 0
+	for e := m.sqlList.Front(); e != nil; {
+		if removedNum <= core.CacheGcMaxRemoved &&
+			time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
+			removedNum++
+			next := e.Next()
+			node := e.Value.(*sqlNode)
+			m.delIds(node.tbName, node.sql)
+			e = next
+		} else {
+			break
+		}
+	}
+}
+
+// GetIds returns all bean's ids according to sql and parameter from cache
+func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	if _, ok := m.sqlIndex[tableName]; !ok {
+		m.sqlIndex[tableName] = make(map[string]*list.Element)
+	}
+	if v, err := m.store.Get(sql); err == nil {
+		if el, ok := m.sqlIndex[tableName][sql]; !ok {
+			el = m.sqlList.PushBack(newSQLNode(tableName, sql))
+			m.sqlIndex[tableName][sql] = el
+		} else {
+			lastTime := el.Value.(*sqlNode).lastVisit
+			// if expired, remove the node and return nil
+			if time.Now().Sub(lastTime) > m.Expired {
+				m.delIds(tableName, sql)
+				return nil
+			}
+			m.sqlList.MoveToBack(el)
+			el.Value.(*sqlNode).lastVisit = time.Now()
+		}
+		return v
+	}
+
+	m.delIds(tableName, sql)
+	return nil
+}
+
+// GetBean returns bean according tableName and id from cache
+func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	if _, ok := m.idIndex[tableName]; !ok {
+		m.idIndex[tableName] = make(map[string]*list.Element)
+	}
+	tid := genID(tableName, id)
+	if v, err := m.store.Get(tid); err == nil {
+		if el, ok := m.idIndex[tableName][id]; ok {
+			lastTime := el.Value.(*idNode).lastVisit
+			// if expired, remove the node and return nil
+			if time.Now().Sub(lastTime) > m.Expired {
+				m.delBean(tableName, id)
+				return nil
+			}
+			m.idList.MoveToBack(el)
+			el.Value.(*idNode).lastVisit = time.Now()
+		} else {
+			el = m.idList.PushBack(newIDNode(tableName, id))
+			m.idIndex[tableName][id] = el
+		}
+		return v
+	}
+
+	// store bean is not exist, then remove memory's index
+	m.delBean(tableName, id)
+	return nil
+}
+
+// clearIds clears all sql-ids mapping on table tableName from cache
+func (m *LRUCacher) clearIds(tableName string) {
+	if tis, ok := m.sqlIndex[tableName]; ok {
+		for sql, v := range tis {
+			m.sqlList.Remove(v)
+			m.store.Del(sql)
+		}
+	}
+	m.sqlIndex[tableName] = make(map[string]*list.Element)
+}
+
+// ClearIds clears all sql-ids mapping on table tableName from cache
+func (m *LRUCacher) ClearIds(tableName string) {
+	m.mutex.Lock()
+	m.clearIds(tableName)
+	m.mutex.Unlock()
+}
+
+func (m *LRUCacher) clearBeans(tableName string) {
+	if tis, ok := m.idIndex[tableName]; ok {
+		for id, v := range tis {
+			m.idList.Remove(v)
+			tid := genID(tableName, id)
+			m.store.Del(tid)
+		}
+	}
+	m.idIndex[tableName] = make(map[string]*list.Element)
+}
+
+// ClearBeans clears all beans in some table
+func (m *LRUCacher) ClearBeans(tableName string) {
+	m.mutex.Lock()
+	m.clearBeans(tableName)
+	m.mutex.Unlock()
+}
+
+// PutIds pus ids into table
+func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
+	m.mutex.Lock()
+	if _, ok := m.sqlIndex[tableName]; !ok {
+		m.sqlIndex[tableName] = make(map[string]*list.Element)
+	}
+	if el, ok := m.sqlIndex[tableName][sql]; !ok {
+		el = m.sqlList.PushBack(newSQLNode(tableName, sql))
+		m.sqlIndex[tableName][sql] = el
+	} else {
+		el.Value.(*sqlNode).lastVisit = time.Now()
+	}
+	m.store.Put(sql, ids)
+	if m.sqlList.Len() > m.MaxElementSize {
+		e := m.sqlList.Front()
+		node := e.Value.(*sqlNode)
+		m.delIds(node.tbName, node.sql)
+	}
+	m.mutex.Unlock()
+}
+
+// PutBean puts beans into table
+func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
+	m.mutex.Lock()
+	var el *list.Element
+	var ok bool
+
+	if el, ok = m.idIndex[tableName][id]; !ok {
+		el = m.idList.PushBack(newIDNode(tableName, id))
+		m.idIndex[tableName][id] = el
+	} else {
+		el.Value.(*idNode).lastVisit = time.Now()
+	}
+
+	m.store.Put(genID(tableName, id), obj)
+	if m.idList.Len() > m.MaxElementSize {
+		e := m.idList.Front()
+		node := e.Value.(*idNode)
+		m.delBean(node.tbName, node.id)
+	}
+	m.mutex.Unlock()
+}
+
+func (m *LRUCacher) delIds(tableName, sql string) {
+	if _, ok := m.sqlIndex[tableName]; ok {
+		if el, ok := m.sqlIndex[tableName][sql]; ok {
+			delete(m.sqlIndex[tableName], sql)
+			m.sqlList.Remove(el)
+		}
+	}
+	m.store.Del(sql)
+}
+
+// DelIds deletes ids
+func (m *LRUCacher) DelIds(tableName, sql string) {
+	m.mutex.Lock()
+	m.delIds(tableName, sql)
+	m.mutex.Unlock()
+}
+
+func (m *LRUCacher) delBean(tableName string, id string) {
+	tid := genID(tableName, id)
+	if el, ok := m.idIndex[tableName][id]; ok {
+		delete(m.idIndex[tableName], id)
+		m.idList.Remove(el)
+		m.clearIds(tableName)
+	}
+	m.store.Del(tid)
+}
+
+// DelBean deletes beans in some table
+func (m *LRUCacher) DelBean(tableName string, id string) {
+	m.mutex.Lock()
+	m.delBean(tableName, id)
+	m.mutex.Unlock()
+}
+
+type idNode struct {
+	tbName    string
+	id        string
+	lastVisit time.Time
+}
+
+type sqlNode struct {
+	tbName    string
+	sql       string
+	lastVisit time.Time
+}
+
+func genSQLKey(sql string, args interface{}) string {
+	return fmt.Sprintf("%v-%v", sql, args)
+}
+
+func genID(prefix string, id string) string {
+	return fmt.Sprintf("%v-%v", prefix, id)
+}
+
+func newIDNode(tbName string, id string) *idNode {
+	return &idNode{tbName, id, time.Now()}
+}
+
+func newSQLNode(tbName, sql string) *sqlNode {
+	return &sqlNode{tbName, sql, time.Now()}
+}

+ 51 - 0
vendor/gitea.com/xorm/xorm/cache_memory_store.go

@@ -0,0 +1,51 @@
+// 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 (
+	"sync"
+
+	"xorm.io/core"
+)
+
+var _ core.CacheStore = NewMemoryStore()
+
+// MemoryStore represents in-memory store
+type MemoryStore struct {
+	store map[interface{}]interface{}
+	mutex sync.RWMutex
+}
+
+// NewMemoryStore creates a new store in memory
+func NewMemoryStore() *MemoryStore {
+	return &MemoryStore{store: make(map[interface{}]interface{})}
+}
+
+// Put puts object into store
+func (s *MemoryStore) Put(key string, value interface{}) error {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	s.store[key] = value
+	return nil
+}
+
+// Get gets object from store
+func (s *MemoryStore) Get(key string) (interface{}, error) {
+	s.mutex.RLock()
+	defer s.mutex.RUnlock()
+	if v, ok := s.store[key]; ok {
+		return v, nil
+	}
+
+	return nil, ErrNotExist
+}
+
+// Del deletes object
+func (s *MemoryStore) Del(key string) error {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	delete(s.store, key)
+	return nil
+}

+ 30 - 0
vendor/gitea.com/xorm/xorm/context_cache.go

@@ -0,0 +1,30 @@
+// Copyright 2018 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+// ContextCache is the interface that operates the cache data.
+type ContextCache interface {
+	// Put puts value into cache with key.
+	Put(key string, val interface{})
+	// Get gets cached value by given key.
+	Get(key string) interface{}
+}
+
+type memoryContextCache map[string]interface{}
+
+// NewMemoryContextCache return memoryContextCache
+func NewMemoryContextCache() memoryContextCache {
+	return make(map[string]interface{})
+}
+
+// Put puts value into cache with key.
+func (m memoryContextCache) Put(key string, val interface{}) {
+	m[key] = val
+}
+
+// Get gets cached value by given key.
+func (m memoryContextCache) Get(key string) interface{} {
+	return m[key]
+}

+ 348 - 0
vendor/gitea.com/xorm/xorm/convert.go

@@ -0,0 +1,348 @@
+// 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
+		}
+
+		dv.Set(reflect.New(dv.Type().Elem()))
+		return convertAssign(dv.Interface(), src)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		s := asString(src)
+		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetInt(i64)
+		return nil
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		s := asString(src)
+		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetUint(u64)
+		return nil
+	case reflect.Float32, reflect.Float64:
+		s := asString(src)
+		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
+		if err != nil {
+			err = strconvErr(err)
+			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+		}
+		dv.SetFloat(f64)
+		return nil
+	case reflect.String:
+		dv.SetString(asString(src))
+		return nil
+	}
+
+	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
+}
+
+func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
+	switch tp.Kind() {
+	case reflect.Int64:
+		return vv.Int(), nil
+	case reflect.Int:
+		return int(vv.Int()), nil
+	case reflect.Int32:
+		return int32(vv.Int()), nil
+	case reflect.Int16:
+		return int16(vv.Int()), nil
+	case reflect.Int8:
+		return int8(vv.Int()), nil
+	case reflect.Uint64:
+		return vv.Uint(), nil
+	case reflect.Uint:
+		return uint(vv.Uint()), nil
+	case reflect.Uint32:
+		return uint32(vv.Uint()), nil
+	case reflect.Uint16:
+		return uint16(vv.Uint()), nil
+	case reflect.Uint8:
+		return uint8(vv.Uint()), nil
+	case reflect.String:
+		return vv.String(), nil
+	case reflect.Slice:
+		if tp.Elem().Kind() == reflect.Uint8 {
+			v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
+			if err != nil {
+				return nil, err
+			}
+			return v, nil
+		}
+
+	}
+	return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
+}
+
+func convertFloat(v interface{}) (float64, error) {
+	switch v.(type) {
+	case float32:
+		return float64(v.(float32)), nil
+	case float64:
+		return v.(float64), nil
+	case string:
+		i, err := strconv.ParseFloat(v.(string), 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	case []byte:
+		i, err := strconv.ParseFloat(string(v.([]byte)), 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	}
+	return 0, fmt.Errorf("unsupported type: %v", v)
+}
+
+func convertInt(v interface{}) (int64, error) {
+	switch v.(type) {
+	case int:
+		return int64(v.(int)), nil
+	case int8:
+		return int64(v.(int8)), nil
+	case int16:
+		return int64(v.(int16)), nil
+	case int32:
+		return int64(v.(int32)), nil
+	case int64:
+		return v.(int64), nil
+	case []byte:
+		i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	case string:
+		i, err := strconv.ParseInt(v.(string), 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return i, nil
+	}
+	return 0, fmt.Errorf("unsupported type: %v", v)
+}
+
+func asBool(bs []byte) (bool, error) {
+	if len(bs) == 0 {
+		return false, nil
+	}
+	if bs[0] == 0x00 {
+		return false, nil
+	} else if bs[0] == 0x01 {
+		return true, nil
+	}
+	return strconv.ParseBool(string(bs))
+}

+ 572 - 0
vendor/gitea.com/xorm/xorm/dialect_mssql.go

@@ -0,0 +1,572 @@
+// 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"
+	"strconv"
+	"strings"
+
+	"xorm.io/core"
+)
+
+var (
+	mssqlReservedWords = map[string]bool{
+		"ADD":                    true,
+		"EXTERNAL":               true,
+		"PROCEDURE":              true,
+		"ALL":                    true,
+		"FETCH":                  true,
+		"PUBLIC":                 true,
+		"ALTER":                  true,
+		"FILE":                   true,
+		"RAISERROR":              true,
+		"AND":                    true,
+		"FILLFACTOR":             true,
+		"READ":                   true,
+		"ANY":                    true,
+		"FOR":                    true,
+		"READTEXT":               true,
+		"AS":                     true,
+		"FOREIGN":                true,
+		"RECONFIGURE":            true,
+		"ASC":                    true,
+		"FREETEXT":               true,
+		"REFERENCES":             true,
+		"AUTHORIZATION":          true,
+		"FREETEXTTABLE":          true,
+		"REPLICATION":            true,
+		"BACKUP":                 true,
+		"FROM":                   true,
+		"RESTORE":                true,
+		"BEGIN":                  true,
+		"FULL":                   true,
+		"RESTRICT":               true,
+		"BETWEEN":                true,
+		"FUNCTION":               true,
+		"RETURN":                 true,
+		"BREAK":                  true,
+		"GOTO":                   true,
+		"REVERT":                 true,
+		"BROWSE":                 true,
+		"GRANT":                  true,
+		"REVOKE":                 true,
+		"BULK":                   true,
+		"GROUP":                  true,
+		"RIGHT":                  true,
+		"BY":                     true,
+		"HAVING":                 true,
+		"ROLLBACK":               true,
+		"CASCADE":                true,
+		"HOLDLOCK":               true,
+		"ROWCOUNT":               true,
+		"CASE":                   true,
+		"IDENTITY":               true,
+		"ROWGUIDCOL":             true,
+		"CHECK":                  true,
+		"IDENTITY_INSERT":        true,
+		"RULE":                   true,
+		"CHECKPOINT":             true,
+		"IDENTITYCOL":            true,
+		"SAVE":                   true,
+		"CLOSE":                  true,
+		"IF":                     true,
+		"SCHEMA":                 true,
+		"CLUSTERED":              true,
+		"IN":                     true,
+		"SECURITYAUDIT":          true,
+		"COALESCE":               true,
+		"INDEX":                  true,
+		"SELECT":                 true,
+		"COLLATE":                true,
+		"INNER":                  true,
+		"SEMANTICKEYPHRASETABLE": true,
+		"COLUMN":                 true,
+		"INSERT":                 true,
+		"SEMANTICSIMILARITYDETAILSTABLE": true,
+		"COMMIT":                  true,
+		"INTERSECT":               true,
+		"SEMANTICSIMILARITYTABLE": true,
+		"COMPUTE":                 true,
+		"INTO":                    true,
+		"SESSION_USER":            true,
+		"CONSTRAINT":              true,
+		"IS":                      true,
+		"SET":                     true,
+		"CONTAINS":                true,
+		"JOIN":                    true,
+		"SETUSER":                 true,
+		"CONTAINSTABLE":           true,
+		"KEY":                     true,
+		"SHUTDOWN":                true,
+		"CONTINUE":                true,
+		"KILL":                    true,
+		"SOME":                    true,
+		"CONVERT":                 true,
+		"LEFT":                    true,
+		"STATISTICS":              true,
+		"CREATE":                  true,
+		"LIKE":                    true,
+		"SYSTEM_USER":             true,
+		"CROSS":                   true,
+		"LINENO":                  true,
+		"TABLE":                   true,
+		"CURRENT":                 true,
+		"LOAD":                    true,
+		"TABLESAMPLE":             true,
+		"CURRENT_DATE":            true,
+		"MERGE":                   true,
+		"TEXTSIZE":                true,
+		"CURRENT_TIME":            true,
+		"NATIONAL":                true,
+		"THEN":                    true,
+		"CURRENT_TIMESTAMP":       true,
+		"NOCHECK":                 true,
+		"TO":                      true,
+		"CURRENT_USER":            true,
+		"NONCLUSTERED":            true,
+		"TOP":                     true,
+		"CURSOR":                  true,
+		"NOT":                     true,
+		"TRAN":                    true,
+		"DATABASE":                true,
+		"NULL":                    true,
+		"TRANSACTION":             true,
+		"DBCC":                    true,
+		"NULLIF":                  true,
+		"TRIGGER":                 true,
+		"DEALLOCATE":              true,
+		"OF":                      true,
+		"TRUNCATE":                true,
+		"DECLARE":                 true,
+		"OFF":                     true,
+		"TRY_CONVERT":             true,
+		"DEFAULT":                 true,
+		"OFFSETS":                 true,
+		"TSEQUAL":                 true,
+		"DELETE":                  true,
+		"ON":                      true,
+		"UNION":                   true,
+		"DENY":                    true,
+		"OPEN":                    true,
+		"UNIQUE":                  true,
+		"DESC":                    true,
+		"OPENDATASOURCE":          true,
+		"UNPIVOT":                 true,
+		"DISK":                    true,
+		"OPENQUERY":               true,
+		"UPDATE":                  true,
+		"DISTINCT":                true,
+		"OPENROWSET":              true,
+		"UPDATETEXT":              true,
+		"DISTRIBUTED":             true,
+		"OPENXML":                 true,
+		"USE":                     true,
+		"DOUBLE":                  true,
+		"OPTION":                  true,
+		"USER":                    true,
+		"DROP":                    true,
+		"OR":                      true,
+		"VALUES":                  true,
+		"DUMP":                    true,
+		"ORDER":                   true,
+		"VARYING":                 true,
+		"ELSE":                    true,
+		"OUTER":                   true,
+		"VIEW":                    true,
+		"END":                     true,
+		"OVER":                    true,
+		"WAITFOR":                 true,
+		"ERRLVL":                  true,
+		"PERCENT":                 true,
+		"WHEN":                    true,
+		"ESCAPE":                  true,
+		"PIVOT":                   true,
+		"WHERE":                   true,
+		"EXCEPT":                  true,
+		"PLAN":                    true,
+		"WHILE":                   true,
+		"EXEC":                    true,
+		"PRECISION":               true,
+		"WITH":                    true,
+		"EXECUTE":                 true,
+		"PRIMARY":                 true,
+		"WITHIN":                  true,
+		"EXISTS":                  true,
+		"PRINT":                   true,
+		"WRITETEXT":               true,
+		"EXIT":                    true,
+		"PROC":                    true,
+	}
+)
+
+type mssql struct {
+	core.Base
+}
+
+func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *mssql) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		res = core.Bit
+		if strings.EqualFold(c.Default, "true") {
+			c.Default = "1"
+		} else if strings.EqualFold(c.Default, "false") {
+			c.Default = "0"
+		}
+	case core.Serial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.Int
+	case core.BigSerial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.BigInt
+	case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
+		res = core.VarBinary
+		if c.Length == 0 {
+			c.Length = 50
+		}
+	case core.TimeStamp:
+		res = core.DateTime
+	case core.TimeStampz:
+		res = "DATETIMEOFFSET"
+		c.Length = 7
+	case core.MediumInt:
+		res = core.Int
+	case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json:
+		res = core.Varchar + "(MAX)"
+	case core.Double:
+		res = core.Real
+	case core.Uuid:
+		res = core.Varchar
+		c.Length = 40
+	case core.TinyInt:
+		res = core.TinyInt
+		c.Length = 0
+	default:
+		res = t
+	}
+
+	if res == core.Int {
+		return core.Int
+	}
+
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *mssql) SupportInsertMany() bool {
+	return true
+}
+
+func (db *mssql) IsReserved(name string) bool {
+	_, ok := mssqlReservedWords[name]
+	return ok
+}
+
+func (db *mssql) Quote(name string) string {
+	return "\"" + name + "\""
+}
+
+func (db *mssql) QuoteStr() string {
+	return "\""
+}
+
+func (db *mssql) SupportEngine() bool {
+	return false
+}
+
+func (db *mssql) AutoIncrStr() string {
+	return "IDENTITY"
+}
+
+func (db *mssql) DropTableSql(tableName string) string {
+	return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
+		"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
+		"DROP TABLE \"%s\"", tableName, tableName)
+}
+
+func (db *mssql) SupportCharset() bool {
+	return false
+}
+
+func (db *mssql) IndexOnTable() bool {
+	return true
+}
+
+func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{idxName}
+	sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
+	return sql, args
+}
+
+/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{tableName, colName}
+	sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
+	return sql, args
+}*/
+
+func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
+	query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
+
+	return db.HasRecords(query, tableName, colName)
+}
+
+func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{}
+	sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
+	return sql, args
+}
+
+func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{}
+	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
+	      replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
+		  ISNULL(i.is_primary_key, 0)
+          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
+		  LEFT OUTER JOIN 
+    sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
+		  LEFT OUTER JOIN 
+    sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
+          where a.object_id=object_id('` + tableName + `')`
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		var name, ctype, vdefault string
+		var maxLen, precision, scale int
+		var nullable, isPK bool
+		err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		col := new(core.Column)
+		col.Indexes = make(map[string]int)
+		col.Name = strings.Trim(name, "` ")
+		col.Nullable = nullable
+		col.Default = vdefault
+		col.IsPrimaryKey = isPK
+		ct := strings.ToUpper(ctype)
+		if ct == "DECIMAL" {
+			col.Length = precision
+			col.Length2 = scale
+		} else {
+			col.Length = maxLen
+		}
+		switch ct {
+		case "DATETIMEOFFSET":
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
+		case "NVARCHAR":
+			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
+		case "IMAGE":
+			col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
+		default:
+			if _, ok := core.SqlTypes[ct]; ok {
+				col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
+			} else {
+				return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name)
+			}
+		}
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *mssql) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := `select name from sysobjects where xtype ='U'`
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name string
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, err
+		}
+		table.Name = strings.Trim(name, "` ")
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := `SELECT
+IXS.NAME                    AS  [INDEX_NAME],
+C.NAME                      AS  [COLUMN_NAME],
+IXS.is_unique AS [IS_UNIQUE]
+FROM SYS.INDEXES IXS
+INNER JOIN SYS.INDEX_COLUMNS   IXCS
+ON IXS.OBJECT_ID=IXCS.OBJECT_ID  AND IXS.INDEX_ID = IXCS.INDEX_ID
+INNER   JOIN SYS.COLUMNS C  ON IXS.OBJECT_ID=C.OBJECT_ID
+AND IXCS.COLUMN_ID=C.COLUMN_ID
+WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
+`
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, isUnique string
+
+		err = rows.Scan(&indexName, &colName, &isUnique)
+		if err != nil {
+			return nil, err
+		}
+
+		i, err := strconv.ParseBool(isUnique)
+		if err != nil {
+			return nil, err
+		}
+
+		if i {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+
+		colName = strings.Trim(colName, "` ")
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			indexName = indexName[5+len(tableName):]
+			isRegular = true
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.Type = indexType
+			index.Name = indexName
+			index.IsRegular = isRegular
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+	var sql string
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
+
+	sql += db.QuoteStr() + tableName + db.QuoteStr() + " ("
+
+	pkList := table.PrimaryKeys
+
+	for _, colName := range table.ColumnsSeq() {
+		col := table.GetColumn(colName)
+		if col.IsPrimaryKey && len(pkList) == 1 {
+			sql += col.String(db)
+		} else {
+			sql += col.StringNoPk(db)
+		}
+		sql = strings.TrimSpace(sql)
+		sql += ", "
+	}
+
+	if len(pkList) > 1 {
+		sql += "PRIMARY KEY ( "
+		sql += strings.Join(pkList, ",")
+		sql += " ), "
+	}
+
+	sql = sql[:len(sql)-2] + ")"
+	sql += ";"
+	return sql
+}
+
+func (db *mssql) ForUpdateSql(query string) string {
+	return query
+}
+
+func (db *mssql) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
+}
+
+type odbcDriver struct {
+}
+
+func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	var dbName string
+
+	if strings.HasPrefix(dataSourceName, "sqlserver://") {
+		u, err := url.Parse(dataSourceName)
+		if err != nil {
+			return nil, err
+		}
+		dbName = u.Query().Get("database")
+	} else {
+		kv := strings.Split(dataSourceName, ";")
+		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
+}

+ 662 - 0
vendor/gitea.com/xorm/xorm/dialect_mysql.go

@@ -0,0 +1,662 @@
+// 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 (
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+
+	"xorm.io/core"
+)
+
+var (
+	mysqlReservedWords = map[string]bool{
+		"ADD":               true,
+		"ALL":               true,
+		"ALTER":             true,
+		"ANALYZE":           true,
+		"AND":               true,
+		"AS":                true,
+		"ASC":               true,
+		"ASENSITIVE":        true,
+		"BEFORE":            true,
+		"BETWEEN":           true,
+		"BIGINT":            true,
+		"BINARY":            true,
+		"BLOB":              true,
+		"BOTH":              true,
+		"BY":                true,
+		"CALL":              true,
+		"CASCADE":           true,
+		"CASE":              true,
+		"CHANGE":            true,
+		"CHAR":              true,
+		"CHARACTER":         true,
+		"CHECK":             true,
+		"COLLATE":           true,
+		"COLUMN":            true,
+		"CONDITION":         true,
+		"CONNECTION":        true,
+		"CONSTRAINT":        true,
+		"CONTINUE":          true,
+		"CONVERT":           true,
+		"CREATE":            true,
+		"CROSS":             true,
+		"CURRENT_DATE":      true,
+		"CURRENT_TIME":      true,
+		"CURRENT_TIMESTAMP": true,
+		"CURRENT_USER":      true,
+		"CURSOR":            true,
+		"DATABASE":          true,
+		"DATABASES":         true,
+		"DAY_HOUR":          true,
+		"DAY_MICROSECOND":   true,
+		"DAY_MINUTE":        true,
+		"DAY_SECOND":        true,
+		"DEC":               true,
+		"DECIMAL":           true,
+		"DECLARE":           true,
+		"DEFAULT":           true,
+		"DELAYED":           true,
+		"DELETE":            true,
+		"DESC":              true,
+		"DESCRIBE":          true,
+		"DETERMINISTIC":     true,
+		"DISTINCT":          true,
+		"DISTINCTROW":       true,
+		"DIV":               true,
+		"DOUBLE":            true,
+		"DROP":              true,
+		"DUAL":              true,
+		"EACH":              true,
+		"ELSE":              true,
+		"ELSEIF":            true,
+		"ENCLOSED":          true,
+		"ESCAPED":           true,
+		"EXISTS":            true,
+		"EXIT":              true,
+		"EXPLAIN":           true,
+		"FALSE":             true,
+		"FETCH":             true,
+		"FLOAT":             true,
+		"FLOAT4":            true,
+		"FLOAT8":            true,
+		"FOR":               true,
+		"FORCE":             true,
+		"FOREIGN":           true,
+		"FROM":              true,
+		"FULLTEXT":          true,
+		"GOTO":              true,
+		"GRANT":             true,
+		"GROUP":             true,
+		"HAVING":            true,
+		"HIGH_PRIORITY":     true,
+		"HOUR_MICROSECOND":  true,
+		"HOUR_MINUTE":       true,
+		"HOUR_SECOND":       true,
+		"IF":                true,
+		"IGNORE":            true,
+		"IN":                true, "INDEX": true,
+		"INFILE": true, "INNER": true, "INOUT": true,
+		"INSENSITIVE": true, "INSERT": true, "INT": true,
+		"INT1": true, "INT2": true, "INT3": true,
+		"INT4": true, "INT8": true, "INTEGER": true,
+		"INTERVAL": true, "INTO": true, "IS": true,
+		"ITERATE": true, "JOIN": true, "KEY": true,
+		"KEYS": true, "KILL": true, "LABEL": true,
+		"LEADING": true, "LEAVE": true, "LEFT": true,
+		"LIKE": true, "LIMIT": true, "LINEAR": true,
+		"LINES": true, "LOAD": true, "LOCALTIME": true,
+		"LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
+		"LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
+		"LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
+		"MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
+		"MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
+		"MODIFIES": true, "NATURAL": true, "NOT": true,
+		"NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
+		"ON	OPTIMIZE": true, "OPTION": true,
+		"OPTIONALLY": true, "OR": true, "ORDER": true,
+		"OUT": true, "OUTER": true, "OUTFILE": true,
+		"PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
+		"PURGE": true, "RAID0": true, "RANGE": true,
+		"READ": true, "READS": true, "REAL": true,
+		"REFERENCES": true, "REGEXP": true, "RELEASE": true,
+		"RENAME": true, "REPEAT": true, "REPLACE": true,
+		"REQUIRE": true, "RESTRICT": true, "RETURN": true,
+		"REVOKE": true, "RIGHT": true, "RLIKE": true,
+		"SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
+		"SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
+		"SET": true, "SHOW": true, "SMALLINT": true,
+		"SPATIAL": true, "SPECIFIC": true, "SQL": true,
+		"SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
+		"SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
+		"SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
+		"TABLE": true, "TERMINATED": true, "THEN": true,
+		"TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
+		"TO": true, "TRAILING": true, "TRIGGER": true,
+		"TRUE": true, "UNDO": true, "UNION": true,
+		"UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
+		"UPDATE": true, "USAGE": true, "USE": true,
+		"USING": true, "UTC_DATE": true, "UTC_TIME": true,
+		"UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
+		"VARCHAR":      true,
+		"VARCHARACTER": true,
+		"VARYING":      true,
+		"WHEN":         true,
+		"WHERE":        true,
+		"WHILE":        true,
+		"WITH":         true,
+		"WRITE":        true,
+		"X509":         true,
+		"XOR":          true,
+		"YEAR_MONTH":   true,
+		"ZEROFILL":     true,
+	}
+)
+
+type mysql struct {
+	core.Base
+	net               string
+	addr              string
+	params            map[string]string
+	loc               *time.Location
+	timeout           time.Duration
+	tls               *tls.Config
+	allowAllFiles     bool
+	allowOldPasswords bool
+	clientFoundRows   bool
+	rowFormat         string
+}
+
+func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *mysql) SetParams(params map[string]string) {
+	rowFormat, ok := params["rowFormat"]
+	if ok {
+		var t = strings.ToUpper(rowFormat)
+		switch t {
+		case "COMPACT":
+			fallthrough
+		case "REDUNDANT":
+			fallthrough
+		case "DYNAMIC":
+			fallthrough
+		case "COMPRESSED":
+			db.rowFormat = t
+			break
+		default:
+			break
+		}
+	}
+}
+
+func (db *mysql) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		res = core.TinyInt
+		c.Length = 1
+	case core.Serial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.Int
+	case core.BigSerial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.BigInt
+	case core.Bytea:
+		res = core.Blob
+	case core.TimeStampz:
+		res = core.Char
+		c.Length = 64
+	case core.Enum: //mysql enum
+		res = core.Enum
+		res += "("
+		opts := ""
+		for v := range c.EnumOptions {
+			opts += fmt.Sprintf(",'%v'", v)
+		}
+		res += strings.TrimLeft(opts, ",")
+		res += ")"
+	case core.Set: //mysql set
+		res = core.Set
+		res += "("
+		opts := ""
+		for v := range c.SetOptions {
+			opts += fmt.Sprintf(",'%v'", v)
+		}
+		res += strings.TrimLeft(opts, ",")
+		res += ")"
+	case core.NVarchar:
+		res = core.Varchar
+	case core.Uuid:
+		res = core.Varchar
+		c.Length = 40
+	case core.Json:
+		res = core.Text
+	default:
+		res = t
+	}
+
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
+	if res == core.BigInt && !hasLen1 && !hasLen2 {
+		c.Length = 20
+		hasLen1 = true
+	}
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *mysql) SupportInsertMany() bool {
+	return true
+}
+
+func (db *mysql) IsReserved(name string) bool {
+	_, ok := mysqlReservedWords[name]
+	return ok
+}
+
+func (db *mysql) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *mysql) QuoteStr() string {
+	return "`"
+}
+
+func (db *mysql) SupportEngine() bool {
+	return true
+}
+
+func (db *mysql) AutoIncrStr() string {
+	return "AUTO_INCREMENT"
+}
+
+func (db *mysql) SupportCharset() bool {
+	return true
+}
+
+func (db *mysql) IndexOnTable() bool {
+	return true
+}
+
+func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName, idxName}
+	sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
+	sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
+	return sql, args
+}
+
+/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName, colName}
+	sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
+	return sql, args
+}*/
+
+func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName}
+	sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
+	return sql, args
+}
+
+func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{db.DbName, tableName}
+	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
+		" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]int)
+
+		var columnName, isNullable, colType, colKey, extra, comment string
+		var colDefault *string
+		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
+		if err != nil {
+			return nil, nil, err
+		}
+		col.Name = strings.Trim(columnName, "` ")
+		col.Comment = comment
+		if "YES" == isNullable {
+			col.Nullable = true
+		}
+
+		if colDefault != nil {
+			col.Default = *colDefault
+			if col.Default == "" {
+				col.DefaultIsEmpty = true
+			}
+		}
+
+		cts := strings.Split(colType, "(")
+		colName := cts[0]
+		colType = strings.ToUpper(colName)
+		var len1, len2 int
+		if len(cts) == 2 {
+			idx := strings.Index(cts[1], ")")
+			if colType == core.Enum && cts[1][0] == '\'' { //enum
+				options := strings.Split(cts[1][0:idx], ",")
+				col.EnumOptions = make(map[string]int)
+				for k, v := range options {
+					v = strings.TrimSpace(v)
+					v = strings.Trim(v, "'")
+					col.EnumOptions[v] = k
+				}
+			} else if colType == core.Set && cts[1][0] == '\'' {
+				options := strings.Split(cts[1][0:idx], ",")
+				col.SetOptions = make(map[string]int)
+				for k, v := range options {
+					v = strings.TrimSpace(v)
+					v = strings.Trim(v, "'")
+					col.SetOptions[v] = k
+				}
+			} else {
+				lens := strings.Split(cts[1][0:idx], ",")
+				len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
+				if err != nil {
+					return nil, nil, err
+				}
+				if len(lens) == 2 {
+					len2, err = strconv.Atoi(lens[1])
+					if err != nil {
+						return nil, nil, err
+					}
+				}
+			}
+		}
+		if colType == "FLOAT UNSIGNED" {
+			colType = "FLOAT"
+		}
+		if colType == "DOUBLE UNSIGNED" {
+			colType = "DOUBLE"
+		}
+		col.Length = len1
+		col.Length2 = len2
+		if _, ok := core.SqlTypes[colType]; ok {
+			col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
+		} else {
+			return nil, nil, fmt.Errorf("Unknown colType %v", colType)
+		}
+
+		if colKey == "PRI" {
+			col.IsPrimaryKey = true
+		}
+		if colKey == "UNI" {
+			//col.is
+		}
+
+		if extra == "auto_increment" {
+			col.IsAutoIncrement = true
+		}
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *mysql) GetTables() ([]*core.Table, error) {
+	args := []interface{}{db.DbName}
+	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
+		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name, engine, tableRows, comment string
+		var autoIncr *string
+		err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
+		if err != nil {
+			return nil, err
+		}
+
+		table.Name = name
+		table.Comment = comment
+		table.StoreEngine = engine
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{db.DbName, tableName}
+	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, nonUnique string
+		err = rows.Scan(&indexName, &nonUnique, &colName)
+		if err != nil {
+			return nil, err
+		}
+
+		if indexName == "PRIMARY" {
+			continue
+		}
+
+		if "YES" == nonUnique || nonUnique == "1" {
+			indexType = core.IndexType
+		} else {
+			indexType = core.UniqueType
+		}
+
+		colName = strings.Trim(colName, "` ")
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			indexName = indexName[5+len(tableName):]
+			isRegular = true
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.IsRegular = isRegular
+			index.Type = indexType
+			index.Name = indexName
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+	var sql string
+	sql = "CREATE TABLE IF NOT EXISTS "
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql += db.Quote(tableName)
+	sql += " ("
+
+	if len(table.ColumnsSeq()) > 0 {
+		pkList := table.PrimaryKeys
+
+		for _, colName := range table.ColumnsSeq() {
+			col := table.GetColumn(colName)
+			if col.IsPrimaryKey && len(pkList) == 1 {
+				sql += col.String(db)
+			} else {
+				sql += col.StringNoPk(db)
+			}
+			sql = strings.TrimSpace(sql)
+			if len(col.Comment) > 0 {
+				sql += " COMMENT '" + col.Comment + "'"
+			}
+			sql += ", "
+		}
+
+		if len(pkList) > 1 {
+			sql += "PRIMARY KEY ( "
+			sql += db.Quote(strings.Join(pkList, db.Quote(",")))
+			sql += " ), "
+		}
+
+		sql = sql[:len(sql)-2]
+	}
+	sql += ")"
+
+	if storeEngine != "" {
+		sql += " ENGINE=" + storeEngine
+	}
+
+	if len(charset) == 0 {
+		charset = db.URI().Charset
+	} 
+	if len(charset) != 0 {
+		sql += " DEFAULT CHARSET " + charset
+	}
+	
+	
+
+	if db.rowFormat != "" {
+		sql += " ROW_FORMAT=" + db.rowFormat
+	}
+	return sql
+}
+
+func (db *mysql) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}}
+}
+
+type mymysqlDriver struct {
+}
+
+func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.MYSQL}
+
+	pd := strings.SplitN(dataSourceName, "*", 2)
+	if len(pd) == 2 {
+		// Parse protocol part of URI
+		p := strings.SplitN(pd[0], ":", 2)
+		if len(p) != 2 {
+			return nil, errors.New("Wrong protocol part of URI")
+		}
+		db.Proto = p[0]
+		options := strings.Split(p[1], ",")
+		db.Raddr = options[0]
+		for _, o := range options[1:] {
+			kv := strings.SplitN(o, "=", 2)
+			var k, v string
+			if len(kv) == 2 {
+				k, v = kv[0], kv[1]
+			} else {
+				k, v = o, "true"
+			}
+			switch k {
+			case "laddr":
+				db.Laddr = v
+			case "timeout":
+				to, err := time.ParseDuration(v)
+				if err != nil {
+					return nil, err
+				}
+				db.Timeout = to
+			default:
+				return nil, errors.New("Unknown option: " + k)
+			}
+		}
+		// Remove protocol part
+		pd = pd[1:]
+	}
+	// Parse database part of URI
+	dup := strings.SplitN(pd[0], "/", 3)
+	if len(dup) != 3 {
+		return nil, errors.New("Wrong database part of URI")
+	}
+	db.DbName = dup[0]
+	db.User = dup[1]
+	db.Passwd = dup[2]
+
+	return db, nil
+}
+
+type mysqlDriver struct {
+}
+
+func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	dsnPattern := regexp.MustCompile(
+		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
+			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
+			`\/(?P<dbname>.*?)` + // /dbname
+			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	//tlsConfigRegister := make(map[string]*tls.Config)
+	names := dsnPattern.SubexpNames()
+
+	uri := &core.Uri{DbType: core.MYSQL}
+
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			uri.DbName = match
+		case "params":
+			if len(match) > 0 {
+				kvs := strings.Split(match, "&")
+				for _, kv := range kvs {
+					splits := strings.Split(kv, "=")
+					if len(splits) == 2 {
+						switch splits[0] {
+						case "charset":
+							uri.Charset = splits[1]
+						}
+					}
+				}
+			}
+
+		}
+	}
+	return uri, nil
+}

+ 906 - 0
vendor/gitea.com/xorm/xorm/dialect_oracle.go

@@ -0,0 +1,906 @@
+// 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"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"xorm.io/core"
+)
+
+var (
+	oracleReservedWords = map[string]bool{
+		"ACCESS":                    true,
+		"ACCOUNT":                   true,
+		"ACTIVATE":                  true,
+		"ADD":                       true,
+		"ADMIN":                     true,
+		"ADVISE":                    true,
+		"AFTER":                     true,
+		"ALL":                       true,
+		"ALL_ROWS":                  true,
+		"ALLOCATE":                  true,
+		"ALTER":                     true,
+		"ANALYZE":                   true,
+		"AND":                       true,
+		"ANY":                       true,
+		"ARCHIVE":                   true,
+		"ARCHIVELOG":                true,
+		"ARRAY":                     true,
+		"AS":                        true,
+		"ASC":                       true,
+		"AT":                        true,
+		"AUDIT":                     true,
+		"AUTHENTICATED":             true,
+		"AUTHORIZATION":             true,
+		"AUTOEXTEND":                true,
+		"AUTOMATIC":                 true,
+		"BACKUP":                    true,
+		"BECOME":                    true,
+		"BEFORE":                    true,
+		"BEGIN":                     true,
+		"BETWEEN":                   true,
+		"BFILE":                     true,
+		"BITMAP":                    true,
+		"BLOB":                      true,
+		"BLOCK":                     true,
+		"BODY":                      true,
+		"BY":                        true,
+		"CACHE":                     true,
+		"CACHE_INSTANCES":           true,
+		"CANCEL":                    true,
+		"CASCADE":                   true,
+		"CAST":                      true,
+		"CFILE":                     true,
+		"CHAINED":                   true,
+		"CHANGE":                    true,
+		"CHAR":                      true,
+		"CHAR_CS":                   true,
+		"CHARACTER":                 true,
+		"CHECK":                     true,
+		"CHECKPOINT":                true,
+		"CHOOSE":                    true,
+		"CHUNK":                     true,
+		"CLEAR":                     true,
+		"CLOB":                      true,
+		"CLONE":                     true,
+		"CLOSE":                     true,
+		"CLOSE_CACHED_OPEN_CURSORS": true,
+		"CLUSTER":                   true,
+		"COALESCE":                  true,
+		"COLUMN":                    true,
+		"COLUMNS":                   true,
+		"COMMENT":                   true,
+		"COMMIT":                    true,
+		"COMMITTED":                 true,
+		"COMPATIBILITY":             true,
+		"COMPILE":                   true,
+		"COMPLETE":                  true,
+		"COMPOSITE_LIMIT":           true,
+		"COMPRESS":                  true,
+		"COMPUTE":                   true,
+		"CONNECT":                   true,
+		"CONNECT_TIME":              true,
+		"CONSTRAINT":                true,
+		"CONSTRAINTS":               true,
+		"CONTENTS":                  true,
+		"CONTINUE":                  true,
+		"CONTROLFILE":               true,
+		"CONVERT":                   true,
+		"COST":                      true,
+		"CPU_PER_CALL":              true,
+		"CPU_PER_SESSION":           true,
+		"CREATE":                    true,
+		"CURRENT":                   true,
+		"CURRENT_SCHEMA":            true,
+		"CURREN_USER":               true,
+		"CURSOR":                    true,
+		"CYCLE":                     true,
+		"DANGLING":                  true,
+		"DATABASE":                  true,
+		"DATAFILE":                  true,
+		"DATAFILES":                 true,
+		"DATAOBJNO":                 true,
+		"DATE":                      true,
+		"DBA":                       true,
+		"DBHIGH":                    true,
+		"DBLOW":                     true,
+		"DBMAC":                     true,
+		"DEALLOCATE":                true,
+		"DEBUG":                     true,
+		"DEC":                       true,
+		"DECIMAL":                   true,
+		"DECLARE":                   true,
+		"DEFAULT":                   true,
+		"DEFERRABLE":                true,
+		"DEFERRED":                  true,
+		"DEGREE":                    true,
+		"DELETE":                    true,
+		"DEREF":                     true,
+		"DESC":                      true,
+		"DIRECTORY":                 true,
+		"DISABLE":                   true,
+		"DISCONNECT":                true,
+		"DISMOUNT":                  true,
+		"DISTINCT":                  true,
+		"DISTRIBUTED":               true,
+		"DML":                       true,
+		"DOUBLE":                    true,
+		"DROP":                      true,
+		"DUMP":                      true,
+		"EACH":                      true,
+		"ELSE":                      true,
+		"ENABLE":                    true,
+		"END":                       true,
+		"ENFORCE":                   true,
+		"ENTRY":                     true,
+		"ESCAPE":                    true,
+		"EXCEPT":                    true,
+		"EXCEPTIONS":                true,
+		"EXCHANGE":                  true,
+		"EXCLUDING":                 true,
+		"EXCLUSIVE":                 true,
+		"EXECUTE":                   true,
+		"EXISTS":                    true,
+		"EXPIRE":                    true,
+		"EXPLAIN":                   true,
+		"EXTENT":                    true,
+		"EXTENTS":                   true,
+		"EXTERNALLY":                true,
+		"FAILED_LOGIN_ATTEMPTS":     true,
+		"FALSE":                     true,
+		"FAST":                      true,
+		"FILE":                      true,
+		"FIRST_ROWS":                true,
+		"FLAGGER":                   true,
+		"FLOAT":                     true,
+		"FLOB":                      true,
+		"FLUSH":                     true,
+		"FOR":                       true,
+		"FORCE":                     true,
+		"FOREIGN":                   true,
+		"FREELIST":                  true,
+		"FREELISTS":                 true,
+		"FROM":                      true,
+		"FULL":                      true,
+		"FUNCTION":                  true,
+		"GLOBAL":                    true,
+		"GLOBALLY":                  true,
+		"GLOBAL_NAME":               true,
+		"GRANT":                     true,
+		"GROUP":                     true,
+		"GROUPS":                    true,
+		"HASH":                      true,
+		"HASHKEYS":                  true,
+		"HAVING":                    true,
+		"HEADER":                    true,
+		"HEAP":                      true,
+		"IDENTIFIED":                true,
+		"IDGENERATORS":              true,
+		"IDLE_TIME":                 true,
+		"IF":                        true,
+		"IMMEDIATE":                 true,
+		"IN":                        true,
+		"INCLUDING":                 true,
+		"INCREMENT":                 true,
+		"INDEX":                     true,
+		"INDEXED":                   true,
+		"INDEXES":                   true,
+		"INDICATOR":                 true,
+		"IND_PARTITION":             true,
+		"INITIAL":                   true,
+		"INITIALLY":                 true,
+		"INITRANS":                  true,
+		"INSERT":                    true,
+		"INSTANCE":                  true,
+		"INSTANCES":                 true,
+		"INSTEAD":                   true,
+		"INT":                       true,
+		"INTEGER":                   true,
+		"INTERMEDIATE":              true,
+		"INTERSECT":                 true,
+		"INTO":                      true,
+		"IS":                        true,
+		"ISOLATION":                 true,
+		"ISOLATION_LEVEL":           true,
+		"KEEP":                      true,
+		"KEY":                       true,
+		"KILL":                      true,
+		"LABEL":                     true,
+		"LAYER":                     true,
+		"LESS":                      true,
+		"LEVEL":                     true,
+		"LIBRARY":                   true,
+		"LIKE":                      true,
+		"LIMIT":                     true,
+		"LINK":                      true,
+		"LIST":                      true,
+		"LOB":                       true,
+		"LOCAL":                     true,
+		"LOCK":                      true,
+		"LOCKED":                    true,
+		"LOG":                       true,
+		"LOGFILE":                   true,
+		"LOGGING":                   true,
+		"LOGICAL_READS_PER_CALL":    true,
+		"LOGICAL_READS_PER_SESSION": true,
+		"LONG":                     true,
+		"MANAGE":                   true,
+		"MASTER":                   true,
+		"MAX":                      true,
+		"MAXARCHLOGS":              true,
+		"MAXDATAFILES":             true,
+		"MAXEXTENTS":               true,
+		"MAXINSTANCES":             true,
+		"MAXLOGFILES":              true,
+		"MAXLOGHISTORY":            true,
+		"MAXLOGMEMBERS":            true,
+		"MAXSIZE":                  true,
+		"MAXTRANS":                 true,
+		"MAXVALUE":                 true,
+		"MIN":                      true,
+		"MEMBER":                   true,
+		"MINIMUM":                  true,
+		"MINEXTENTS":               true,
+		"MINUS":                    true,
+		"MINVALUE":                 true,
+		"MLSLABEL":                 true,
+		"MLS_LABEL_FORMAT":         true,
+		"MODE":                     true,
+		"MODIFY":                   true,
+		"MOUNT":                    true,
+		"MOVE":                     true,
+		"MTS_DISPATCHERS":          true,
+		"MULTISET":                 true,
+		"NATIONAL":                 true,
+		"NCHAR":                    true,
+		"NCHAR_CS":                 true,
+		"NCLOB":                    true,
+		"NEEDED":                   true,
+		"NESTED":                   true,
+		"NETWORK":                  true,
+		"NEW":                      true,
+		"NEXT":                     true,
+		"NOARCHIVELOG":             true,
+		"NOAUDIT":                  true,
+		"NOCACHE":                  true,
+		"NOCOMPRESS":               true,
+		"NOCYCLE":                  true,
+		"NOFORCE":                  true,
+		"NOLOGGING":                true,
+		"NOMAXVALUE":               true,
+		"NOMINVALUE":               true,
+		"NONE":                     true,
+		"NOORDER":                  true,
+		"NOOVERRIDE":               true,
+		"NOPARALLEL":               true,
+		"NOREVERSE":                true,
+		"NORMAL":                   true,
+		"NOSORT":                   true,
+		"NOT":                      true,
+		"NOTHING":                  true,
+		"NOWAIT":                   true,
+		"NULL":                     true,
+		"NUMBER":                   true,
+		"NUMERIC":                  true,
+		"NVARCHAR2":                true,
+		"OBJECT":                   true,
+		"OBJNO":                    true,
+		"OBJNO_REUSE":              true,
+		"OF":                       true,
+		"OFF":                      true,
+		"OFFLINE":                  true,
+		"OID":                      true,
+		"OIDINDEX":                 true,
+		"OLD":                      true,
+		"ON":                       true,
+		"ONLINE":                   true,
+		"ONLY":                     true,
+		"OPCODE":                   true,
+		"OPEN":                     true,
+		"OPTIMAL":                  true,
+		"OPTIMIZER_GOAL":           true,
+		"OPTION":                   true,
+		"OR":                       true,
+		"ORDER":                    true,
+		"ORGANIZATION":             true,
+		"OSLABEL":                  true,
+		"OVERFLOW":                 true,
+		"OWN":                      true,
+		"PACKAGE":                  true,
+		"PARALLEL":                 true,
+		"PARTITION":                true,
+		"PASSWORD":                 true,
+		"PASSWORD_GRACE_TIME":      true,
+		"PASSWORD_LIFE_TIME":       true,
+		"PASSWORD_LOCK_TIME":       true,
+		"PASSWORD_REUSE_MAX":       true,
+		"PASSWORD_REUSE_TIME":      true,
+		"PASSWORD_VERIFY_FUNCTION": true,
+		"PCTFREE":                  true,
+		"PCTINCREASE":              true,
+		"PCTTHRESHOLD":             true,
+		"PCTUSED":                  true,
+		"PCTVERSION":               true,
+		"PERCENT":                  true,
+		"PERMANENT":                true,
+		"PLAN":                     true,
+		"PLSQL_DEBUG":              true,
+		"POST_TRANSACTION":         true,
+		"PRECISION":                true,
+		"PRESERVE":                 true,
+		"PRIMARY":                  true,
+		"PRIOR":                    true,
+		"PRIVATE":                  true,
+		"PRIVATE_SGA":              true,
+		"PRIVILEGE":                true,
+		"PRIVILEGES":               true,
+		"PROCEDURE":                true,
+		"PROFILE":                  true,
+		"PUBLIC":                   true,
+		"PURGE":                    true,
+		"QUEUE":                    true,
+		"QUOTA":                    true,
+		"RANGE":                    true,
+		"RAW":                      true,
+		"RBA":                      true,
+		"READ":                     true,
+		"READUP":                   true,
+		"REAL":                     true,
+		"REBUILD":                  true,
+		"RECOVER":                  true,
+		"RECOVERABLE":              true,
+		"RECOVERY":                 true,
+		"REF":                      true,
+		"REFERENCES":               true,
+		"REFERENCING":              true,
+		"REFRESH":                  true,
+		"RENAME":                   true,
+		"REPLACE":                  true,
+		"RESET":                    true,
+		"RESETLOGS":                true,
+		"RESIZE":                   true,
+		"RESOURCE":                 true,
+		"RESTRICTED":               true,
+		"RETURN":                   true,
+		"RETURNING":                true,
+		"REUSE":                    true,
+		"REVERSE":                  true,
+		"REVOKE":                   true,
+		"ROLE":                     true,
+		"ROLES":                    true,
+		"ROLLBACK":                 true,
+		"ROW":                      true,
+		"ROWID":                    true,
+		"ROWNUM":                   true,
+		"ROWS":                     true,
+		"RULE":                     true,
+		"SAMPLE":                   true,
+		"SAVEPOINT":                true,
+		"SB4":                      true,
+		"SCAN_INSTANCES":           true,
+		"SCHEMA":                   true,
+		"SCN":                      true,
+		"SCOPE":                    true,
+		"SD_ALL":                   true,
+		"SD_INHIBIT":               true,
+		"SD_SHOW":                  true,
+		"SEGMENT":                  true,
+		"SEG_BLOCK":                true,
+		"SEG_FILE":                 true,
+		"SELECT":                   true,
+		"SEQUENCE":                 true,
+		"SERIALIZABLE":             true,
+		"SESSION":                  true,
+		"SESSION_CACHED_CURSORS":   true,
+		"SESSIONS_PER_USER":        true,
+		"SET":                      true,
+		"SHARE":                    true,
+		"SHARED":                   true,
+		"SHARED_POOL":              true,
+		"SHRINK":                   true,
+		"SIZE":                     true,
+		"SKIP":                     true,
+		"SKIP_UNUSABLE_INDEXES":    true,
+		"SMALLINT":                 true,
+		"SNAPSHOT":                 true,
+		"SOME":                     true,
+		"SORT":                     true,
+		"SPECIFICATION":            true,
+		"SPLIT":                    true,
+		"SQL_TRACE":                true,
+		"STANDBY":                  true,
+		"START":                    true,
+		"STATEMENT_ID":             true,
+		"STATISTICS":               true,
+		"STOP":                     true,
+		"STORAGE":                  true,
+		"STORE":                    true,
+		"STRUCTURE":                true,
+		"SUCCESSFUL":               true,
+		"SWITCH":                   true,
+		"SYS_OP_ENFORCE_NOT_NULL$": true,
+		"SYS_OP_NTCIMG$":           true,
+		"SYNONYM":                  true,
+		"SYSDATE":                  true,
+		"SYSDBA":                   true,
+		"SYSOPER":                  true,
+		"SYSTEM":                   true,
+		"TABLE":                    true,
+		"TABLES":                   true,
+		"TABLESPACE":               true,
+		"TABLESPACE_NO":            true,
+		"TABNO":                    true,
+		"TEMPORARY":                true,
+		"THAN":                     true,
+		"THE":                      true,
+		"THEN":                     true,
+		"THREAD":                   true,
+		"TIMESTAMP":                true,
+		"TIME":                     true,
+		"TO":                       true,
+		"TOPLEVEL":                 true,
+		"TRACE":                    true,
+		"TRACING":                  true,
+		"TRANSACTION":              true,
+		"TRANSITIONAL":             true,
+		"TRIGGER":                  true,
+		"TRIGGERS":                 true,
+		"TRUE":                     true,
+		"TRUNCATE":                 true,
+		"TX":                       true,
+		"TYPE":                     true,
+		"UB2":                      true,
+		"UBA":                      true,
+		"UID":                      true,
+		"UNARCHIVED":               true,
+		"UNDO":                     true,
+		"UNION":                    true,
+		"UNIQUE":                   true,
+		"UNLIMITED":                true,
+		"UNLOCK":                   true,
+		"UNRECOVERABLE":            true,
+		"UNTIL":                    true,
+		"UNUSABLE":                 true,
+		"UNUSED":                   true,
+		"UPDATABLE":                true,
+		"UPDATE":                   true,
+		"USAGE":                    true,
+		"USE":                      true,
+		"USER":                     true,
+		"USING":                    true,
+		"VALIDATE":                 true,
+		"VALIDATION":               true,
+		"VALUE":                    true,
+		"VALUES":                   true,
+		"VARCHAR":                  true,
+		"VARCHAR2":                 true,
+		"VARYING":                  true,
+		"VIEW":                     true,
+		"WHEN":                     true,
+		"WHENEVER":                 true,
+		"WHERE":                    true,
+		"WITH":                     true,
+		"WITHOUT":                  true,
+		"WORK":                     true,
+		"WRITE":                    true,
+		"WRITEDOWN":                true,
+		"WRITEUP":                  true,
+		"XID":                      true,
+		"YEAR":                     true,
+		"ZONE":                     true,
+	}
+)
+
+type oracle struct {
+	core.Base
+}
+
+func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *oracle) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
+		res = "NUMBER"
+	case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
+		return core.Blob
+	case core.Time, core.DateTime, core.TimeStamp:
+		res = core.TimeStamp
+	case core.TimeStampz:
+		res = "TIMESTAMP WITH TIME ZONE"
+	case core.Float, core.Double, core.Numeric, core.Decimal:
+		res = "NUMBER"
+	case core.Text, core.MediumText, core.LongText, core.Json:
+		res = "CLOB"
+	case core.Char, core.Varchar, core.TinyText:
+		res = "VARCHAR2"
+	default:
+		res = t
+	}
+
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *oracle) AutoIncrStr() string {
+	return "AUTO_INCREMENT"
+}
+
+func (db *oracle) SupportInsertMany() bool {
+	return true
+}
+
+func (db *oracle) IsReserved(name string) bool {
+	_, ok := oracleReservedWords[name]
+	return ok
+}
+
+func (db *oracle) Quote(name string) string {
+	return "\"" + name + "\""
+}
+
+func (db *oracle) QuoteStr() string {
+	return "\""
+}
+
+func (db *oracle) SupportEngine() bool {
+	return false
+}
+
+func (db *oracle) SupportCharset() bool {
+	return false
+}
+
+func (db *oracle) SupportDropIfExists() bool {
+	return false
+}
+
+func (db *oracle) IndexOnTable() bool {
+	return false
+}
+
+func (db *oracle) DropTableSql(tableName string) string {
+	return fmt.Sprintf("DROP TABLE `%s`", tableName)
+}
+
+func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+	var sql string
+	sql = "CREATE TABLE "
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql += db.Quote(tableName) + " ("
+
+	pkList := table.PrimaryKeys
+
+	for _, colName := range table.ColumnsSeq() {
+		col := table.GetColumn(colName)
+		/*if col.IsPrimaryKey && len(pkList) == 1 {
+			sql += col.String(b.dialect)
+		} else {*/
+		sql += col.StringNoPk(db)
+		//}
+		sql = strings.TrimSpace(sql)
+		sql += ", "
+	}
+
+	if len(pkList) > 0 {
+		sql += "PRIMARY KEY ( "
+		sql += db.Quote(strings.Join(pkList, db.Quote(",")))
+		sql += " ), "
+	}
+
+	sql = sql[:len(sql)-2] + ")"
+	if db.SupportEngine() && storeEngine != "" {
+		sql += " ENGINE=" + storeEngine
+	}
+	if db.SupportCharset() {
+		if len(charset) == 0 {
+			charset = db.URI().Charset
+		}
+		if len(charset) > 0 {
+			sql += " DEFAULT CHARSET " + charset
+		}
+	}
+	return sql
+}
+
+func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{tableName, idxName}
+	return `SELECT INDEX_NAME FROM USER_INDEXES ` +
+		`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
+}
+
+func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return `SELECT table_name FROM user_tables WHERE table_name = :1`, args
+}
+
+func (db *oracle) MustDropTable(tableName string) error {
+	sql, args := db.TableCheckSql(tableName)
+	db.LogSQL(sql, args)
+
+	rows, err := db.DB().Query(sql, args...)
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	if !rows.Next() {
+		return nil
+	}
+
+	sql = "Drop Table \"" + tableName + "\""
+	db.LogSQL(sql, args)
+
+	_, err = db.DB().Exec(sql)
+	return err
+}
+
+/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
+	return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
+		" AND column_name = ?", args
+}*/
+
+func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{tableName, colName}
+	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
+		" AND column_name = :2"
+	db.LogSQL(query, args)
+
+	rows, err := db.DB().Query(query, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
+		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]int)
+
+		var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
+		var dataLen int
+
+		err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision,
+			&dataScale, &nullable)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		col.Name = strings.Trim(*colName, `" `)
+		if colDefault != nil {
+			col.Default = *colDefault
+			col.DefaultIsEmpty = false
+		}
+
+		if *nullable == "Y" {
+			col.Nullable = true
+		} else {
+			col.Nullable = false
+		}
+
+		var ignore bool
+
+		var dt string
+		var len1, len2 int
+		dts := strings.Split(*dataType, "(")
+		dt = dts[0]
+		if len(dts) > 1 {
+			lens := strings.Split(dts[1][:len(dts[1])-1], ",")
+			if len(lens) > 1 {
+				len1, _ = strconv.Atoi(lens[0])
+				len2, _ = strconv.Atoi(lens[1])
+			} else {
+				len1, _ = strconv.Atoi(lens[0])
+			}
+		}
+
+		switch dt {
+		case "VARCHAR2":
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
+		case "NVARCHAR2":
+			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2}
+		case "TIMESTAMP WITH TIME ZONE":
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
+		case "NUMBER":
+			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2}
+		case "LONG", "LONG RAW":
+			col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0}
+		case "RAW":
+			col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
+		case "ROWID":
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
+		case "AQ$_SUBSCRIBERS":
+			ignore = true
+		default:
+			col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
+		}
+
+		if ignore {
+			continue
+		}
+
+		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
+			return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
+		}
+
+		col.Length = dataLen
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if !col.DefaultIsEmpty {
+				col.Default = "'" + col.Default + "'"
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+
+	return colSeq, cols, nil
+}
+
+func (db *oracle) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT table_name FROM user_tables"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		err = rows.Scan(&table.Name)
+		if err != nil {
+			return nil, err
+		}
+
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
+		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, uniqueness string
+
+		err = rows.Scan(&colName, &uniqueness, &indexName)
+		if err != nil {
+			return nil, err
+		}
+
+		indexName = strings.Trim(indexName, `" `)
+
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			indexName = indexName[5+len(tableName):]
+			isRegular = true
+		}
+
+		if uniqueness == "UNIQUE" {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.Type = indexType
+			index.Name = indexName
+			index.IsRegular = isRegular
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *oracle) Filters() []core.Filter {
+	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
+}

+ 1253 - 0
vendor/gitea.com/xorm/xorm/dialect_postgres.go

@@ -0,0 +1,1253 @@
+// 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"
+	"strconv"
+	"strings"
+
+	"xorm.io/core"
+)
+
+// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
+var (
+	postgresReservedWords = map[string]bool{
+		"A":                     true,
+		"ABORT":                 true,
+		"ABS":                   true,
+		"ABSENT":                true,
+		"ABSOLUTE":              true,
+		"ACCESS":                true,
+		"ACCORDING":             true,
+		"ACTION":                true,
+		"ADA":                   true,
+		"ADD":                   true,
+		"ADMIN":                 true,
+		"AFTER":                 true,
+		"AGGREGATE":             true,
+		"ALL":                   true,
+		"ALLOCATE":              true,
+		"ALSO":                  true,
+		"ALTER":                 true,
+		"ALWAYS":                true,
+		"ANALYSE":               true,
+		"ANALYZE":               true,
+		"AND":                   true,
+		"ANY":                   true,
+		"ARE":                   true,
+		"ARRAY":                 true,
+		"ARRAY_AGG":             true,
+		"ARRAY_MAX_CARDINALITY": true,
+		"AS":                               true,
+		"ASC":                              true,
+		"ASENSITIVE":                       true,
+		"ASSERTION":                        true,
+		"ASSIGNMENT":                       true,
+		"ASYMMETRIC":                       true,
+		"AT":                               true,
+		"ATOMIC":                           true,
+		"ATTRIBUTE":                        true,
+		"ATTRIBUTES":                       true,
+		"AUTHORIZATION":                    true,
+		"AVG":                              true,
+		"BACKWARD":                         true,
+		"BASE64":                           true,
+		"BEFORE":                           true,
+		"BEGIN":                            true,
+		"BEGIN_FRAME":                      true,
+		"BEGIN_PARTITION":                  true,
+		"BERNOULLI":                        true,
+		"BETWEEN":                          true,
+		"BIGINT":                           true,
+		"BINARY":                           true,
+		"BIT":                              true,
+		"BIT_LENGTH":                       true,
+		"BLOB":                             true,
+		"BLOCKED":                          true,
+		"BOM":                              true,
+		"BOOLEAN":                          true,
+		"BOTH":                             true,
+		"BREADTH":                          true,
+		"BY":                               true,
+		"C":                                true,
+		"CACHE":                            true,
+		"CALL":                             true,
+		"CALLED":                           true,
+		"CARDINALITY":                      true,
+		"CASCADE":                          true,
+		"CASCADED":                         true,
+		"CASE":                             true,
+		"CAST":                             true,
+		"CATALOG":                          true,
+		"CATALOG_NAME":                     true,
+		"CEIL":                             true,
+		"CEILING":                          true,
+		"CHAIN":                            true,
+		"CHAR":                             true,
+		"CHARACTER":                        true,
+		"CHARACTERISTICS":                  true,
+		"CHARACTERS":                       true,
+		"CHARACTER_LENGTH":                 true,
+		"CHARACTER_SET_CATALOG":            true,
+		"CHARACTER_SET_NAME":               true,
+		"CHARACTER_SET_SCHEMA":             true,
+		"CHAR_LENGTH":                      true,
+		"CHECK":                            true,
+		"CHECKPOINT":                       true,
+		"CLASS":                            true,
+		"CLASS_ORIGIN":                     true,
+		"CLOB":                             true,
+		"CLOSE":                            true,
+		"CLUSTER":                          true,
+		"COALESCE":                         true,
+		"COBOL":                            true,
+		"COLLATE":                          true,
+		"COLLATION":                        true,
+		"COLLATION_CATALOG":                true,
+		"COLLATION_NAME":                   true,
+		"COLLATION_SCHEMA":                 true,
+		"COLLECT":                          true,
+		"COLUMN":                           true,
+		"COLUMNS":                          true,
+		"COLUMN_NAME":                      true,
+		"COMMAND_FUNCTION":                 true,
+		"COMMAND_FUNCTION_CODE":            true,
+		"COMMENT":                          true,
+		"COMMENTS":                         true,
+		"COMMIT":                           true,
+		"COMMITTED":                        true,
+		"CONCURRENTLY":                     true,
+		"CONDITION":                        true,
+		"CONDITION_NUMBER":                 true,
+		"CONFIGURATION":                    true,
+		"CONNECT":                          true,
+		"CONNECTION":                       true,
+		"CONNECTION_NAME":                  true,
+		"CONSTRAINT":                       true,
+		"CONSTRAINTS":                      true,
+		"CONSTRAINT_CATALOG":               true,
+		"CONSTRAINT_NAME":                  true,
+		"CONSTRAINT_SCHEMA":                true,
+		"CONSTRUCTOR":                      true,
+		"CONTAINS":                         true,
+		"CONTENT":                          true,
+		"CONTINUE":                         true,
+		"CONTROL":                          true,
+		"CONVERSION":                       true,
+		"CONVERT":                          true,
+		"COPY":                             true,
+		"CORR":                             true,
+		"CORRESPONDING":                    true,
+		"COST":                             true,
+		"COUNT":                            true,
+		"COVAR_POP":                        true,
+		"COVAR_SAMP":                       true,
+		"CREATE":                           true,
+		"CROSS":                            true,
+		"CSV":                              true,
+		"CUBE":                             true,
+		"CUME_DIST":                        true,
+		"CURRENT":                          true,
+		"CURRENT_CATALOG":                  true,
+		"CURRENT_DATE":                     true,
+		"CURRENT_DEFAULT_TRANSFORM_GROUP":  true,
+		"CURRENT_PATH":                     true,
+		"CURRENT_ROLE":                     true,
+		"CURRENT_ROW":                      true,
+		"CURRENT_SCHEMA":                   true,
+		"CURRENT_TIME":                     true,
+		"CURRENT_TIMESTAMP":                true,
+		"CURRENT_TRANSFORM_GROUP_FOR_TYPE": true,
+		"CURRENT_USER":                     true,
+		"CURSOR":                           true,
+		"CURSOR_NAME":                      true,
+		"CYCLE":                            true,
+		"DATA":                             true,
+		"DATABASE":                         true,
+		"DATALINK":                         true,
+		"DATE":                             true,
+		"DATETIME_INTERVAL_CODE":      true,
+		"DATETIME_INTERVAL_PRECISION": true,
+		"DAY":                        true,
+		"DB":                         true,
+		"DEALLOCATE":                 true,
+		"DEC":                        true,
+		"DECIMAL":                    true,
+		"DECLARE":                    true,
+		"DEFAULT":                    true,
+		"DEFAULTS":                   true,
+		"DEFERRABLE":                 true,
+		"DEFERRED":                   true,
+		"DEFINED":                    true,
+		"DEFINER":                    true,
+		"DEGREE":                     true,
+		"DELETE":                     true,
+		"DELIMITER":                  true,
+		"DELIMITERS":                 true,
+		"DENSE_RANK":                 true,
+		"DEPTH":                      true,
+		"DEREF":                      true,
+		"DERIVED":                    true,
+		"DESC":                       true,
+		"DESCRIBE":                   true,
+		"DESCRIPTOR":                 true,
+		"DETERMINISTIC":              true,
+		"DIAGNOSTICS":                true,
+		"DICTIONARY":                 true,
+		"DISABLE":                    true,
+		"DISCARD":                    true,
+		"DISCONNECT":                 true,
+		"DISPATCH":                   true,
+		"DISTINCT":                   true,
+		"DLNEWCOPY":                  true,
+		"DLPREVIOUSCOPY":             true,
+		"DLURLCOMPLETE":              true,
+		"DLURLCOMPLETEONLY":          true,
+		"DLURLCOMPLETEWRITE":         true,
+		"DLURLPATH":                  true,
+		"DLURLPATHONLY":              true,
+		"DLURLPATHWRITE":             true,
+		"DLURLSCHEME":                true,
+		"DLURLSERVER":                true,
+		"DLVALUE":                    true,
+		"DO":                         true,
+		"DOCUMENT":                   true,
+		"DOMAIN":                     true,
+		"DOUBLE":                     true,
+		"DROP":                       true,
+		"DYNAMIC":                    true,
+		"DYNAMIC_FUNCTION":           true,
+		"DYNAMIC_FUNCTION_CODE":      true,
+		"EACH":                       true,
+		"ELEMENT":                    true,
+		"ELSE":                       true,
+		"EMPTY":                      true,
+		"ENABLE":                     true,
+		"ENCODING":                   true,
+		"ENCRYPTED":                  true,
+		"END":                        true,
+		"END-EXEC":                   true,
+		"END_FRAME":                  true,
+		"END_PARTITION":              true,
+		"ENFORCED":                   true,
+		"ENUM":                       true,
+		"EQUALS":                     true,
+		"ESCAPE":                     true,
+		"EVENT":                      true,
+		"EVERY":                      true,
+		"EXCEPT":                     true,
+		"EXCEPTION":                  true,
+		"EXCLUDE":                    true,
+		"EXCLUDING":                  true,
+		"EXCLUSIVE":                  true,
+		"EXEC":                       true,
+		"EXECUTE":                    true,
+		"EXISTS":                     true,
+		"EXP":                        true,
+		"EXPLAIN":                    true,
+		"EXPRESSION":                 true,
+		"EXTENSION":                  true,
+		"EXTERNAL":                   true,
+		"EXTRACT":                    true,
+		"FALSE":                      true,
+		"FAMILY":                     true,
+		"FETCH":                      true,
+		"FILE":                       true,
+		"FILTER":                     true,
+		"FINAL":                      true,
+		"FIRST":                      true,
+		"FIRST_VALUE":                true,
+		"FLAG":                       true,
+		"FLOAT":                      true,
+		"FLOOR":                      true,
+		"FOLLOWING":                  true,
+		"FOR":                        true,
+		"FORCE":                      true,
+		"FOREIGN":                    true,
+		"FORTRAN":                    true,
+		"FORWARD":                    true,
+		"FOUND":                      true,
+		"FRAME_ROW":                  true,
+		"FREE":                       true,
+		"FREEZE":                     true,
+		"FROM":                       true,
+		"FS":                         true,
+		"FULL":                       true,
+		"FUNCTION":                   true,
+		"FUNCTIONS":                  true,
+		"FUSION":                     true,
+		"G":                          true,
+		"GENERAL":                    true,
+		"GENERATED":                  true,
+		"GET":                        true,
+		"GLOBAL":                     true,
+		"GO":                         true,
+		"GOTO":                       true,
+		"GRANT":                      true,
+		"GRANTED":                    true,
+		"GREATEST":                   true,
+		"GROUP":                      true,
+		"GROUPING":                   true,
+		"GROUPS":                     true,
+		"HANDLER":                    true,
+		"HAVING":                     true,
+		"HEADER":                     true,
+		"HEX":                        true,
+		"HIERARCHY":                  true,
+		"HOLD":                       true,
+		"HOUR":                       true,
+		"ID":                         true,
+		"IDENTITY":                   true,
+		"IF":                         true,
+		"IGNORE":                     true,
+		"ILIKE":                      true,
+		"IMMEDIATE":                  true,
+		"IMMEDIATELY":                true,
+		"IMMUTABLE":                  true,
+		"IMPLEMENTATION":             true,
+		"IMPLICIT":                   true,
+		"IMPORT":                     true,
+		"IN":                         true,
+		"INCLUDING":                  true,
+		"INCREMENT":                  true,
+		"INDENT":                     true,
+		"INDEX":                      true,
+		"INDEXES":                    true,
+		"INDICATOR":                  true,
+		"INHERIT":                    true,
+		"INHERITS":                   true,
+		"INITIALLY":                  true,
+		"INLINE":                     true,
+		"INNER":                      true,
+		"INOUT":                      true,
+		"INPUT":                      true,
+		"INSENSITIVE":                true,
+		"INSERT":                     true,
+		"INSTANCE":                   true,
+		"INSTANTIABLE":               true,
+		"INSTEAD":                    true,
+		"INT":                        true,
+		"INTEGER":                    true,
+		"INTEGRITY":                  true,
+		"INTERSECT":                  true,
+		"INTERSECTION":               true,
+		"INTERVAL":                   true,
+		"INTO":                       true,
+		"INVOKER":                    true,
+		"IS":                         true,
+		"ISNULL":                     true,
+		"ISOLATION":                  true,
+		"JOIN":                       true,
+		"K":                          true,
+		"KEY":                        true,
+		"KEY_MEMBER":                 true,
+		"KEY_TYPE":                   true,
+		"LABEL":                      true,
+		"LAG":                        true,
+		"LANGUAGE":                   true,
+		"LARGE":                      true,
+		"LAST":                       true,
+		"LAST_VALUE":                 true,
+		"LATERAL":                    true,
+		"LC_COLLATE":                 true,
+		"LC_CTYPE":                   true,
+		"LEAD":                       true,
+		"LEADING":                    true,
+		"LEAKPROOF":                  true,
+		"LEAST":                      true,
+		"LEFT":                       true,
+		"LENGTH":                     true,
+		"LEVEL":                      true,
+		"LIBRARY":                    true,
+		"LIKE":                       true,
+		"LIKE_REGEX":                 true,
+		"LIMIT":                      true,
+		"LINK":                       true,
+		"LISTEN":                     true,
+		"LN":                         true,
+		"LOAD":                       true,
+		"LOCAL":                      true,
+		"LOCALTIME":                  true,
+		"LOCALTIMESTAMP":             true,
+		"LOCATION":                   true,
+		"LOCATOR":                    true,
+		"LOCK":                       true,
+		"LOWER":                      true,
+		"M":                          true,
+		"MAP":                        true,
+		"MAPPING":                    true,
+		"MATCH":                      true,
+		"MATCHED":                    true,
+		"MATERIALIZED":               true,
+		"MAX":                        true,
+		"MAXVALUE":                   true,
+		"MAX_CARDINALITY":            true,
+		"MEMBER":                     true,
+		"MERGE":                      true,
+		"MESSAGE_LENGTH":             true,
+		"MESSAGE_OCTET_LENGTH":       true,
+		"MESSAGE_TEXT":               true,
+		"METHOD":                     true,
+		"MIN":                        true,
+		"MINUTE":                     true,
+		"MINVALUE":                   true,
+		"MOD":                        true,
+		"MODE":                       true,
+		"MODIFIES":                   true,
+		"MODULE":                     true,
+		"MONTH":                      true,
+		"MORE":                       true,
+		"MOVE":                       true,
+		"MULTISET":                   true,
+		"MUMPS":                      true,
+		"NAME":                       true,
+		"NAMES":                      true,
+		"NAMESPACE":                  true,
+		"NATIONAL":                   true,
+		"NATURAL":                    true,
+		"NCHAR":                      true,
+		"NCLOB":                      true,
+		"NESTING":                    true,
+		"NEW":                        true,
+		"NEXT":                       true,
+		"NFC":                        true,
+		"NFD":                        true,
+		"NFKC":                       true,
+		"NFKD":                       true,
+		"NIL":                        true,
+		"NO":                         true,
+		"NONE":                       true,
+		"NORMALIZE":                  true,
+		"NORMALIZED":                 true,
+		"NOT":                        true,
+		"NOTHING":                    true,
+		"NOTIFY":                     true,
+		"NOTNULL":                    true,
+		"NOWAIT":                     true,
+		"NTH_VALUE":                  true,
+		"NTILE":                      true,
+		"NULL":                       true,
+		"NULLABLE":                   true,
+		"NULLIF":                     true,
+		"NULLS":                      true,
+		"NUMBER":                     true,
+		"NUMERIC":                    true,
+		"OBJECT":                     true,
+		"OCCURRENCES_REGEX":          true,
+		"OCTETS":                     true,
+		"OCTET_LENGTH":               true,
+		"OF":                         true,
+		"OFF":                        true,
+		"OFFSET":                     true,
+		"OIDS":                       true,
+		"OLD":                        true,
+		"ON":                         true,
+		"ONLY":                       true,
+		"OPEN":                       true,
+		"OPERATOR":                   true,
+		"OPTION":                     true,
+		"OPTIONS":                    true,
+		"OR":                         true,
+		"ORDER":                      true,
+		"ORDERING":                   true,
+		"ORDINALITY":                 true,
+		"OTHERS":                     true,
+		"OUT":                        true,
+		"OUTER":                      true,
+		"OUTPUT":                     true,
+		"OVER":                       true,
+		"OVERLAPS":                   true,
+		"OVERLAY":                    true,
+		"OVERRIDING":                 true,
+		"OWNED":                      true,
+		"OWNER":                      true,
+		"P":                          true,
+		"PAD":                        true,
+		"PARAMETER":                  true,
+		"PARAMETER_MODE":             true,
+		"PARAMETER_NAME":             true,
+		"PARAMETER_ORDINAL_POSITION": true,
+		"PARAMETER_SPECIFIC_CATALOG": true,
+		"PARAMETER_SPECIFIC_NAME":    true,
+		"PARAMETER_SPECIFIC_SCHEMA":  true,
+		"PARSER":                     true,
+		"PARTIAL":                    true,
+		"PARTITION":                  true,
+		"PASCAL":                     true,
+		"PASSING":                    true,
+		"PASSTHROUGH":                true,
+		"PASSWORD":                   true,
+		"PATH":                       true,
+		"PERCENT":                    true,
+		"PERCENTILE_CONT":            true,
+		"PERCENTILE_DISC":            true,
+		"PERCENT_RANK":               true,
+		"PERIOD":                     true,
+		"PERMISSION":                 true,
+		"PLACING":                    true,
+		"PLANS":                      true,
+		"PLI":                        true,
+		"PORTION":                    true,
+		"POSITION":                   true,
+		"POSITION_REGEX":             true,
+		"POWER":                      true,
+		"PRECEDES":                   true,
+		"PRECEDING":                  true,
+		"PRECISION":                  true,
+		"PREPARE":                    true,
+		"PREPARED":                   true,
+		"PRESERVE":                   true,
+		"PRIMARY":                    true,
+		"PRIOR":                      true,
+		"PRIVILEGES":                 true,
+		"PROCEDURAL":                 true,
+		"PROCEDURE":                  true,
+		"PROGRAM":                    true,
+		"PUBLIC":                     true,
+		"QUOTE":                      true,
+		"RANGE":                      true,
+		"RANK":                       true,
+		"READ":                       true,
+		"READS":                      true,
+		"REAL":                       true,
+		"REASSIGN":                   true,
+		"RECHECK":                    true,
+		"RECOVERY":                   true,
+		"RECURSIVE":                  true,
+		"REF":                        true,
+		"REFERENCES":                 true,
+		"REFERENCING":                true,
+		"REFRESH":                    true,
+		"REGR_AVGX":                  true,
+		"REGR_AVGY":                  true,
+		"REGR_COUNT":                 true,
+		"REGR_INTERCEPT":             true,
+		"REGR_R2":                    true,
+		"REGR_SLOPE":                 true,
+		"REGR_SXX":                   true,
+		"REGR_SXY":                   true,
+		"REGR_SYY":                   true,
+		"REINDEX":                    true,
+		"RELATIVE":                   true,
+		"RELEASE":                    true,
+		"RENAME":                     true,
+		"REPEATABLE":                 true,
+		"REPLACE":                    true,
+		"REPLICA":                    true,
+		"REQUIRING":                  true,
+		"RESET":                      true,
+		"RESPECT":                    true,
+		"RESTART":                    true,
+		"RESTORE":                    true,
+		"RESTRICT":                   true,
+		"RESULT":                     true,
+		"RETURN":                     true,
+		"RETURNED_CARDINALITY":       true,
+		"RETURNED_LENGTH":            true,
+		"RETURNED_OCTET_LENGTH":      true,
+		"RETURNED_SQLSTATE":          true,
+		"RETURNING":                  true,
+		"RETURNS":                    true,
+		"REVOKE":                     true,
+		"RIGHT":                      true,
+		"ROLE":                       true,
+		"ROLLBACK":                   true,
+		"ROLLUP":                     true,
+		"ROUTINE":                    true,
+		"ROUTINE_CATALOG":            true,
+		"ROUTINE_NAME":               true,
+		"ROUTINE_SCHEMA":             true,
+		"ROW":                        true,
+		"ROWS":                       true,
+		"ROW_COUNT":                  true,
+		"ROW_NUMBER":                 true,
+		"RULE":                       true,
+		"SAVEPOINT":                  true,
+		"SCALE":                      true,
+		"SCHEMA":                     true,
+		"SCHEMA_NAME":                true,
+		"SCOPE":                      true,
+		"SCOPE_CATALOG":              true,
+		"SCOPE_NAME":                 true,
+		"SCOPE_SCHEMA":               true,
+		"SCROLL":                     true,
+		"SEARCH":                     true,
+		"SECOND":                     true,
+		"SECTION":                    true,
+		"SECURITY":                   true,
+		"SELECT":                     true,
+		"SELECTIVE":                  true,
+		"SELF":                       true,
+		"SENSITIVE":                  true,
+		"SEQUENCE":                   true,
+		"SEQUENCES":                  true,
+		"SERIALIZABLE":               true,
+		"SERVER":                     true,
+		"SERVER_NAME":                true,
+		"SESSION":                    true,
+		"SESSION_USER":               true,
+		"SET":                        true,
+		"SETOF":                      true,
+		"SETS":                       true,
+		"SHARE":                      true,
+		"SHOW":                       true,
+		"SIMILAR":                    true,
+		"SIMPLE":                     true,
+		"SIZE":                       true,
+		"SMALLINT":                   true,
+		"SNAPSHOT":                   true,
+		"SOME":                       true,
+		"SOURCE":                     true,
+		"SPACE":                      true,
+		"SPECIFIC":                   true,
+		"SPECIFICTYPE":               true,
+		"SPECIFIC_NAME":              true,
+		"SQL":                        true,
+		"SQLCODE":                    true,
+		"SQLERROR":                   true,
+		"SQLEXCEPTION":               true,
+		"SQLSTATE":                   true,
+		"SQLWARNING":                 true,
+		"SQRT":                       true,
+		"STABLE":                     true,
+		"STANDALONE":                 true,
+		"START":                      true,
+		"STATE":                      true,
+		"STATEMENT":                  true,
+		"STATIC":                     true,
+		"STATISTICS":                 true,
+		"STDDEV_POP":                 true,
+		"STDDEV_SAMP":                true,
+		"STDIN":                      true,
+		"STDOUT":                     true,
+		"STORAGE":                    true,
+		"STRICT":                     true,
+		"STRIP":                      true,
+		"STRUCTURE":                  true,
+		"STYLE":                      true,
+		"SUBCLASS_ORIGIN":            true,
+		"SUBMULTISET":                true,
+		"SUBSTRING":                  true,
+		"SUBSTRING_REGEX":            true,
+		"SUCCEEDS":                   true,
+		"SUM":                        true,
+		"SYMMETRIC":                  true,
+		"SYSID":                      true,
+		"SYSTEM":                     true,
+		"SYSTEM_TIME":                true,
+		"SYSTEM_USER":                true,
+		"T":                          true,
+		"TABLE":                      true,
+		"TABLES":                     true,
+		"TABLESAMPLE":                true,
+		"TABLESPACE":                 true,
+		"TABLE_NAME":                 true,
+		"TEMP":                       true,
+		"TEMPLATE":                   true,
+		"TEMPORARY":                  true,
+		"TEXT":                       true,
+		"THEN":                       true,
+		"TIES":                       true,
+		"TIME":                       true,
+		"TIMESTAMP":                  true,
+		"TIMEZONE_HOUR":              true,
+		"TIMEZONE_MINUTE":            true,
+		"TO":                         true,
+		"TOKEN":                      true,
+		"TOP_LEVEL_COUNT":            true,
+		"TRAILING":                   true,
+		"TRANSACTION":                true,
+		"TRANSACTIONS_COMMITTED":     true,
+		"TRANSACTIONS_ROLLED_BACK":   true,
+		"TRANSACTION_ACTIVE":         true,
+		"TRANSFORM":                  true,
+		"TRANSFORMS":                 true,
+		"TRANSLATE":                  true,
+		"TRANSLATE_REGEX":            true,
+		"TRANSLATION":                true,
+		"TREAT":                      true,
+		"TRIGGER":                    true,
+		"TRIGGER_CATALOG":            true,
+		"TRIGGER_NAME":               true,
+		"TRIGGER_SCHEMA":             true,
+		"TRIM":                       true,
+		"TRIM_ARRAY":                 true,
+		"TRUE":                       true,
+		"TRUNCATE":                   true,
+		"TRUSTED":                    true,
+		"TYPE":                       true,
+		"TYPES":                      true,
+		"UESCAPE":                    true,
+		"UNBOUNDED":                  true,
+		"UNCOMMITTED":                true,
+		"UNDER":                      true,
+		"UNENCRYPTED":                true,
+		"UNION":                      true,
+		"UNIQUE":                     true,
+		"UNKNOWN":                    true,
+		"UNLINK":                     true,
+		"UNLISTEN":                   true,
+		"UNLOGGED":                   true,
+		"UNNAMED":                    true,
+		"UNNEST":                     true,
+		"UNTIL":                      true,
+		"UNTYPED":                    true,
+		"UPDATE":                     true,
+		"UPPER":                      true,
+		"URI":                        true,
+		"USAGE":                      true,
+		"USER":                       true,
+		"USER_DEFINED_TYPE_CATALOG": true,
+		"USER_DEFINED_TYPE_CODE":    true,
+		"USER_DEFINED_TYPE_NAME":    true,
+		"USER_DEFINED_TYPE_SCHEMA":  true,
+		"USING":                     true,
+		"VACUUM":                    true,
+		"VALID":                     true,
+		"VALIDATE":                  true,
+		"VALIDATOR":                 true,
+		"VALUE":                     true,
+		"VALUES":                    true,
+		"VALUE_OF":                  true,
+		"VARBINARY":                 true,
+		"VARCHAR":                   true,
+		"VARIADIC":                  true,
+		"VARYING":                   true,
+		"VAR_POP":                   true,
+		"VAR_SAMP":                  true,
+		"VERBOSE":                   true,
+		"VERSION":                   true,
+		"VERSIONING":                true,
+		"VIEW":                      true,
+		"VOLATILE":                  true,
+		"WHEN":                      true,
+		"WHENEVER":                  true,
+		"WHERE":                     true,
+		"WHITESPACE":                true,
+		"WIDTH_BUCKET":              true,
+		"WINDOW":                    true,
+		"WITH":                      true,
+		"WITHIN":                    true,
+		"WITHOUT":                   true,
+		"WORK":                      true,
+		"WRAPPER":                   true,
+		"WRITE":                     true,
+		"XML":                       true,
+		"XMLAGG":                    true,
+		"XMLATTRIBUTES":             true,
+		"XMLBINARY":                 true,
+		"XMLCAST":                   true,
+		"XMLCOMMENT":                true,
+		"XMLCONCAT":                 true,
+		"XMLDECLARATION":            true,
+		"XMLDOCUMENT":               true,
+		"XMLELEMENT":                true,
+		"XMLEXISTS":                 true,
+		"XMLFOREST":                 true,
+		"XMLITERATE":                true,
+		"XMLNAMESPACES":             true,
+		"XMLPARSE":                  true,
+		"XMLPI":                     true,
+		"XMLQUERY":                  true,
+		"XMLROOT":                   true,
+		"XMLSCHEMA":                 true,
+		"XMLSERIALIZE":              true,
+		"XMLTABLE":                  true,
+		"XMLTEXT":                   true,
+		"XMLVALIDATE":               true,
+		"YEAR":                      true,
+		"YES":                       true,
+		"ZONE":                      true,
+	}
+
+	// DefaultPostgresSchema default postgres schema
+	DefaultPostgresSchema = "public"
+)
+
+const postgresPublicSchema = "public"
+
+type postgres struct {
+	core.Base
+}
+
+func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	err := db.Base.Init(d, db, uri, drivername, dataSourceName)
+	if err != nil {
+		return err
+	}
+	if db.Schema == "" {
+		db.Schema = DefaultPostgresSchema
+	}
+	return nil
+}
+
+func (db *postgres) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.TinyInt:
+		res = core.SmallInt
+		return res
+	case core.Bit:
+		res = core.Boolean
+		return res
+	case core.MediumInt, core.Int, core.Integer:
+		if c.IsAutoIncrement {
+			return core.Serial
+		}
+		return core.Integer
+	case core.BigInt:
+		if c.IsAutoIncrement {
+			return core.BigSerial
+		}
+		return core.BigInt
+	case core.Serial, core.BigSerial:
+		c.IsAutoIncrement = true
+		c.Nullable = false
+		res = t
+	case core.Binary, core.VarBinary:
+		return core.Bytea
+	case core.DateTime:
+		res = core.TimeStamp
+	case core.TimeStampz:
+		return "timestamp with time zone"
+	case core.Float:
+		res = core.Real
+	case core.TinyText, core.MediumText, core.LongText:
+		res = core.Text
+	case core.NVarchar:
+		res = core.Varchar
+	case core.Uuid:
+		return core.Uuid
+	case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
+		return core.Bytea
+	case core.Double:
+		return "DOUBLE PRECISION"
+	default:
+		if c.IsAutoIncrement {
+			return core.Serial
+		}
+		res = t
+	}
+
+	if strings.EqualFold(res, "bool") {
+		// for bool, we don't need length information
+		return res
+	}
+	hasLen1 := (c.Length > 0)
+	hasLen2 := (c.Length2 > 0)
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *postgres) SupportInsertMany() bool {
+	return true
+}
+
+func (db *postgres) IsReserved(name string) bool {
+	_, ok := postgresReservedWords[name]
+	return ok
+}
+
+func (db *postgres) Quote(name string) string {
+	name = strings.Replace(name, ".", `"."`, -1)
+	return "\"" + name + "\""
+}
+
+func (db *postgres) QuoteStr() string {
+	return "\""
+}
+
+func (db *postgres) AutoIncrStr() string {
+	return ""
+}
+
+func (db *postgres) SupportEngine() bool {
+	return false
+}
+
+func (db *postgres) SupportCharset() bool {
+	return false
+}
+
+func (db *postgres) IndexOnTable() bool {
+	return false
+}
+
+func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	if len(db.Schema) == 0 {
+		args := []interface{}{tableName, idxName}
+		return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
+	}
+
+	args := []interface{}{db.Schema, tableName, idxName}
+	return `SELECT indexname FROM pg_indexes ` +
+		`WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
+}
+
+func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
+	if len(db.Schema) == 0 {
+		args := []interface{}{tableName}
+		return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
+	}
+
+	args := []interface{}{db.Schema, tableName}
+	return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
+}
+
+func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
+	if len(db.Schema) == 0 {
+		return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
+			tableName, col.Name, db.SqlType(col))
+	}
+	return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
+		db.Schema, tableName, col.Name, db.SqlType(col))
+}
+
+func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
+	quote := db.Quote
+	idxName := index.Name
+
+	tableName = strings.Replace(tableName, `"`, "", -1)
+	tableName = strings.Replace(tableName, `.`, "_", -1)
+
+	if !strings.HasPrefix(idxName, "UQE_") &&
+		!strings.HasPrefix(idxName, "IDX_") {
+		if index.Type == core.UniqueType {
+			idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+		} else {
+			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+		}
+	}
+	if db.Uri.Schema != "" {
+		idxName = db.Uri.Schema + "." + idxName
+	}
+	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
+}
+
+func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{db.Schema, tableName, colName}
+	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" +
+		" AND column_name = $3"
+	if len(db.Schema) == 0 {
+		args = []interface{}{tableName, colName}
+		query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
+			" AND column_name = $2"
+	}
+	db.LogSQL(query, args)
+
+	rows, err := db.DB().Query(query, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	return rows.Next(), nil
+}
+
+func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
+    CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
+    CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
+FROM pg_attribute f
+    JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid
+    LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
+    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+    LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
+    LEFT JOIN pg_class AS g ON p.confrelid = g.oid
+    LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
+WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
+
+	var f string
+	if len(db.Schema) != 0 {
+		args = append(args, db.Schema)
+		f = " AND s.table_schema = $2"
+	}
+	s = fmt.Sprintf(s, f)
+
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]int)
+
+		var colName, isNullable, dataType string
+		var maxLenStr, colDefault, numPrecision, numRadix *string
+		var isPK, isUnique bool
+		err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix, &isPK, &isUnique)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		//fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique)
+		var maxLen int
+		if maxLenStr != nil {
+			maxLen, err = strconv.Atoi(*maxLenStr)
+			if err != nil {
+				return nil, nil, err
+			}
+		}
+
+		col.Name = strings.Trim(colName, `" `)
+
+		if colDefault != nil || isPK {
+			if isPK {
+				col.IsPrimaryKey = true
+			} else {
+				col.Default = *colDefault
+			}
+		}
+
+		if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") {
+			col.IsAutoIncrement = true
+		}
+
+		col.Nullable = (isNullable == "YES")
+
+		switch dataType {
+		case "character varying", "character":
+			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 0, DefaultLength2: 0}
+		case "timestamp without time zone":
+			col.SQLType = core.SQLType{Name: core.DateTime, DefaultLength: 0, DefaultLength2: 0}
+		case "timestamp with time zone":
+			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
+		case "double precision":
+			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0}
+		case "boolean":
+			col.SQLType = core.SQLType{Name: core.Bool, DefaultLength: 0, DefaultLength2: 0}
+		case "time without time zone":
+			col.SQLType = core.SQLType{Name: core.Time, DefaultLength: 0, DefaultLength2: 0}
+		case "oid":
+			col.SQLType = core.SQLType{Name: core.BigInt, DefaultLength: 0, DefaultLength2: 0}
+		default:
+			col.SQLType = core.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
+		}
+		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
+			return nil, nil, fmt.Errorf("Unknown colType: %v", dataType)
+		}
+
+		col.Length = maxLen
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+
+	return colSeq, cols, nil
+}
+
+func (db *postgres) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT tablename FROM pg_tables"
+	if len(db.Schema) != 0 {
+		args = append(args, db.Schema)
+		s = s + " WHERE schemaname = $1"
+	}
+
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name string
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, err
+		}
+		table.Name = name
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+
+func getIndexColName(indexdef string) []string {
+	var colNames []string
+
+	cs := strings.Split(indexdef, "(")
+	for _, v := range strings.Split(strings.Split(cs[1], ")")[0], ",") {
+		colNames = append(colNames, strings.Split(strings.TrimLeft(v, " "), " ")[0])
+	}
+
+	return colNames
+}
+
+
+func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
+	if len(db.Schema) != 0 {
+		args = append(args, db.Schema)
+		s = s + " AND schemaname=$2"
+	}
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, indexdef string
+		var colNames []string
+		err = rows.Scan(&indexName, &indexdef)
+		if err != nil {
+			return nil, err
+		}
+		indexName = strings.Trim(indexName, `" `)
+		if strings.HasSuffix(indexName, "_pkey") {
+			continue
+		}
+		if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+		colNames = getIndexColName(indexdef)
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			newIdxName := indexName[5+len(tableName):]
+			isRegular = true
+			if newIdxName != "" {
+				indexName = newIdxName
+			}
+		}
+
+		index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
+		for _, colName := range colNames {
+			index.Cols = append(index.Cols, strings.Trim(colName, `" `))
+		}
+		index.IsRegular = isRegular
+		indexes[index.Name] = index
+	}
+	return indexes, nil
+}
+
+func (db *postgres) Filters() []core.Filter {
+	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 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)
+	}
+
+	escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
+
+	if u.Path != "" {
+		return escaper.Replace(u.Path[1:]), nil
+	}
+
+	return "", nil
+}
+
+func parseOpts(name string, o values) error {
+	if len(name) == 0 {
+		return fmt.Errorf("invalid options: %s", name)
+	}
+
+	name = strings.TrimSpace(name)
+
+	ps := strings.Split(name, " ")
+	for _, p := range ps {
+		kv := strings.Split(p, "=")
+		if len(kv) < 2 {
+			return fmt.Errorf("invalid option: %q", p)
+		}
+		o.Set(kv[0], kv[1])
+	}
+
+	return nil
+}
+
+func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.POSTGRES}
+	var err error
+
+	if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
+		db.DbName, err = parseURL(dataSourceName)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		o := make(values)
+		err = parseOpts(dataSourceName, o)
+		if err != nil {
+			return nil, err
+		}
+
+		db.DbName = o.Get("dbname")
+	}
+
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+
+	return db, nil
+}
+
+type pqDriverPgx struct {
+	pqDriver
+}
+
+func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	// Remove the leading characters for driver to work
+	if len(dataSourceName) >= 9 && dataSourceName[0] == 0 {
+		dataSourceName = dataSourceName[9:]
+	}
+	return pgx.pqDriver.Parse(driverName, dataSourceName)
+}

+ 460 - 0
vendor/gitea.com/xorm/xorm/dialect_sqlite3.go

@@ -0,0 +1,460 @@
+// 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 (
+	"database/sql"
+	"errors"
+	"fmt"
+	"regexp"
+	"strings"
+
+	"xorm.io/core"
+)
+
+var (
+	sqlite3ReservedWords = map[string]bool{
+		"ABORT":             true,
+		"ACTION":            true,
+		"ADD":               true,
+		"AFTER":             true,
+		"ALL":               true,
+		"ALTER":             true,
+		"ANALYZE":           true,
+		"AND":               true,
+		"AS":                true,
+		"ASC":               true,
+		"ATTACH":            true,
+		"AUTOINCREMENT":     true,
+		"BEFORE":            true,
+		"BEGIN":             true,
+		"BETWEEN":           true,
+		"BY":                true,
+		"CASCADE":           true,
+		"CASE":              true,
+		"CAST":              true,
+		"CHECK":             true,
+		"COLLATE":           true,
+		"COLUMN":            true,
+		"COMMIT":            true,
+		"CONFLICT":          true,
+		"CONSTRAINT":        true,
+		"CREATE":            true,
+		"CROSS":             true,
+		"CURRENT_DATE":      true,
+		"CURRENT_TIME":      true,
+		"CURRENT_TIMESTAMP": true,
+		"DATABASE":          true,
+		"DEFAULT":           true,
+		"DEFERRABLE":        true,
+		"DEFERRED":          true,
+		"DELETE":            true,
+		"DESC":              true,
+		"DETACH":            true,
+		"DISTINCT":          true,
+		"DROP":              true,
+		"EACH":              true,
+		"ELSE":              true,
+		"END":               true,
+		"ESCAPE":            true,
+		"EXCEPT":            true,
+		"EXCLUSIVE":         true,
+		"EXISTS":            true,
+		"EXPLAIN":           true,
+		"FAIL":              true,
+		"FOR":               true,
+		"FOREIGN":           true,
+		"FROM":              true,
+		"FULL":              true,
+		"GLOB":              true,
+		"GROUP":             true,
+		"HAVING":            true,
+		"IF":                true,
+		"IGNORE":            true,
+		"IMMEDIATE":         true,
+		"IN":                true,
+		"INDEX":             true,
+		"INDEXED":           true,
+		"INITIALLY":         true,
+		"INNER":             true,
+		"INSERT":            true,
+		"INSTEAD":           true,
+		"INTERSECT":         true,
+		"INTO":              true,
+		"IS":                true,
+		"ISNULL":            true,
+		"JOIN":              true,
+		"KEY":               true,
+		"LEFT":              true,
+		"LIKE":              true,
+		"LIMIT":             true,
+		"MATCH":             true,
+		"NATURAL":           true,
+		"NO":                true,
+		"NOT":               true,
+		"NOTNULL":           true,
+		"NULL":              true,
+		"OF":                true,
+		"OFFSET":            true,
+		"ON":                true,
+		"OR":                true,
+		"ORDER":             true,
+		"OUTER":             true,
+		"PLAN":              true,
+		"PRAGMA":            true,
+		"PRIMARY":           true,
+		"QUERY":             true,
+		"RAISE":             true,
+		"RECURSIVE":         true,
+		"REFERENCES":        true,
+		"REGEXP":            true,
+		"REINDEX":           true,
+		"RELEASE":           true,
+		"RENAME":            true,
+		"REPLACE":           true,
+		"RESTRICT":          true,
+		"RIGHT":             true,
+		"ROLLBACK":          true,
+		"ROW":               true,
+		"SAVEPOINT":         true,
+		"SELECT":            true,
+		"SET":               true,
+		"TABLE":             true,
+		"TEMP":              true,
+		"TEMPORARY":         true,
+		"THEN":              true,
+		"TO":                true,
+		"TRANSACTI":         true,
+		"TRIGGER":           true,
+		"UNION":             true,
+		"UNIQUE":            true,
+		"UPDATE":            true,
+		"USING":             true,
+		"VACUUM":            true,
+		"VALUES":            true,
+		"VIEW":              true,
+		"VIRTUAL":           true,
+		"WHEN":              true,
+		"WHERE":             true,
+		"WITH":              true,
+		"WITHOUT":           true,
+	}
+)
+
+type sqlite3 struct {
+	core.Base
+}
+
+func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *sqlite3) SqlType(c *core.Column) string {
+	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		if c.Default == "true" {
+			c.Default = "1"
+		} else if c.Default == "false" {
+			c.Default = "0"
+		}
+		return core.Integer
+	case core.Date, core.DateTime, core.TimeStamp, core.Time:
+		return core.DateTime
+	case core.TimeStampz:
+		return core.Text
+	case core.Char, core.Varchar, core.NVarchar, core.TinyText,
+		core.Text, core.MediumText, core.LongText, core.Json:
+		return core.Text
+	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
+		return core.Integer
+	case core.Float, core.Double, core.Real:
+		return core.Real
+	case core.Decimal, core.Numeric:
+		return core.Numeric
+	case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
+		return core.Blob
+	case core.Serial, core.BigSerial:
+		c.IsPrimaryKey = true
+		c.IsAutoIncrement = true
+		c.Nullable = false
+		return core.Integer
+	default:
+		return t
+	}
+}
+
+func (db *sqlite3) FormatBytes(bs []byte) string {
+	return fmt.Sprintf("X'%x'", bs)
+}
+
+func (db *sqlite3) SupportInsertMany() bool {
+	return true
+}
+
+func (db *sqlite3) IsReserved(name string) bool {
+	_, ok := sqlite3ReservedWords[name]
+	return ok
+}
+
+func (db *sqlite3) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *sqlite3) QuoteStr() string {
+	return "`"
+}
+
+func (db *sqlite3) AutoIncrStr() string {
+	return "AUTOINCREMENT"
+}
+
+func (db *sqlite3) SupportEngine() bool {
+	return false
+}
+
+func (db *sqlite3) SupportCharset() bool {
+	return false
+}
+
+func (db *sqlite3) IndexOnTable() bool {
+	return false
+}
+
+func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{idxName}
+	return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
+}
+
+func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
+}
+
+func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
+	// var unique string
+	quote := db.Quote
+	idxName := index.Name
+
+	if !strings.HasPrefix(idxName, "UQE_") &&
+		!strings.HasPrefix(idxName, "IDX_") {
+		if index.Type == core.UniqueType {
+			idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+		} else {
+			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+		}
+	}
+	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
+}
+
+func (db *sqlite3) ForUpdateSql(query string) string {
+	return query
+}
+
+/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	return sql, args
+}*/
+
+func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{tableName}
+	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	db.LogSQL(query, args)
+	rows, err := db.DB().Query(query, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
+	db.LogSQL(s, args)
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	var name string
+	for rows.Next() {
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, nil, err
+		}
+		break
+	}
+
+	if name == "" {
+		return nil, nil, errors.New("no table named " + tableName)
+	}
+
+	nStart := strings.Index(name, "(")
+	nEnd := strings.LastIndex(name, ")")
+	reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
+	colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for _, colStr := range colCreates {
+		reg = regexp.MustCompile(`,\s`)
+		colStr = reg.ReplaceAllString(colStr, ",")
+		if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") {
+			parts := strings.Split(strings.TrimSpace(colStr), "(")
+			if len(parts) == 2 {
+				pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",")
+				for _, pk := range pkCols {
+					if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok {
+						col.IsPrimaryKey = true
+					}
+				}
+			}
+			continue
+		}
+
+		fields := strings.Fields(strings.TrimSpace(colStr))
+		col := new(core.Column)
+		col.Indexes = make(map[string]int)
+		col.Nullable = true
+		col.DefaultIsEmpty = true
+
+		for idx, field := range fields {
+			if idx == 0 {
+				col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
+				continue
+			} else if idx == 1 {
+				col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
+			}
+			switch field {
+			case "PRIMARY":
+				col.IsPrimaryKey = true
+			case "AUTOINCREMENT":
+				col.IsAutoIncrement = true
+			case "NULL":
+				if fields[idx-1] == "NOT" {
+					col.Nullable = false
+				} else {
+					col.Nullable = true
+				}
+			case "DEFAULT":
+				col.Default = fields[idx+1]
+				col.DefaultIsEmpty = false
+			}
+		}
+		if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty {
+			col.Default = "'" + col.Default + "'"
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *sqlite3) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT name FROM sqlite_master WHERE type='table'"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		err = rows.Scan(&table.Name)
+		if err != nil {
+			return nil, err
+		}
+		if table.Name == "sqlite_sequence" {
+			continue
+		}
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
+	db.LogSQL(s, args)
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var tmpSQL sql.NullString
+		err = rows.Scan(&tmpSQL)
+		if err != nil {
+			return nil, err
+		}
+
+		if !tmpSQL.Valid {
+			continue
+		}
+		sql := tmpSQL.String
+
+		index := new(core.Index)
+		nNStart := strings.Index(sql, "INDEX")
+		nNEnd := strings.Index(sql, "ON")
+		if nNStart == -1 || nNEnd == -1 {
+			continue
+		}
+
+		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			index.Name = indexName[5+len(tableName):]
+			isRegular = true
+		} else {
+			index.Name = indexName
+		}
+
+		if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
+			index.Type = core.UniqueType
+		} else {
+			index.Type = core.IndexType
+		}
+
+		nStart := strings.Index(sql, "(")
+		nEnd := strings.Index(sql, ")")
+		colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
+
+		index.Cols = make([]string, 0)
+		for _, col := range colIndexes {
+			index.Cols = append(index.Cols, strings.Trim(col, "` []"))
+		}
+		index.IsRegular = isRegular
+		indexes[index.Name] = index
+	}
+
+	return indexes, nil
+}
+
+func (db *sqlite3) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}}
+}
+
+type sqlite3Driver struct {
+}
+
+func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	if strings.Contains(dataSourceName, "?") {
+		dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
+	}
+
+	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
+}

+ 184 - 0
vendor/gitea.com/xorm/xorm/doc.go

@@ -0,0 +1,184 @@
+// Copyright 2013 - 2016 The XORM Authors. All rights reserved.
+// Use of this source code is governed by a BSD
+// license that can be found in the LICENSE file.
+
+/*
+
+Package xorm is a simple and powerful ORM for Go.
+
+Installation
+
+Make sure you have installed Go 1.6+ and then:
+
+    go get github.com/go-xorm/xorm
+
+Create Engine
+
+Firstly, we should new an engine for a database
+
+    engine, err := xorm.NewEngine(driverName, dataSourceName)
+
+Method NewEngine's parameters is the same as sql.Open. It depends
+drivers' implementation.
+Generally, one engine for an application is enough. You can set it as package variable.
+
+Raw Methods
+
+XORM also support raw SQL execution:
+
+1. query a SQL string, the returned results is []map[string][]byte
+
+    results, err := engine.Query("select * from user")
+
+2. execute a SQL string, the returned results
+
+    affected, err := engine.Exec("update user set .... where ...")
+
+ORM Methods
+
+There are 8 major ORM methods and many helpful methods to use to operate database.
+
+1. Insert one or multiple records to database
+
+    affected, err := engine.Insert(&struct)
+    // INSERT INTO struct () values ()
+    affected, err := engine.Insert(&struct1, &struct2)
+    // INSERT INTO struct1 () values ()
+    // INSERT INTO struct2 () values ()
+    affected, err := engine.Insert(&sliceOfStruct)
+    // INSERT INTO struct () values (),(),()
+    affected, err := engine.Insert(&struct1, &sliceOfStruct2)
+    // INSERT INTO struct1 () values ()
+    // INSERT INTO struct2 () values (),(),()
+
+2. Query one record or one variable from database
+
+    has, err := engine.Get(&user)
+    // SELECT * FROM user LIMIT 1
+
+    var id int64
+    has, err := engine.Table("user").Where("name = ?", name).Get(&id)
+    // SELECT id FROM user WHERE name = ? LIMIT 1
+
+3. Query multiple records from database
+
+    var sliceOfStructs []Struct
+    err := engine.Find(&sliceOfStructs)
+    // SELECT * FROM user
+
+    var mapOfStructs = make(map[int64]Struct)
+    err := engine.Find(&mapOfStructs)
+    // SELECT * FROM user
+
+    var int64s []int64
+    err := engine.Table("user").Cols("id").Find(&int64s)
+    // SELECT id FROM user
+
+4. Query multiple records and record by record handle, there two methods, one is Iterate,
+another is Rows
+
+    err := engine.Iterate(...)
+    // SELECT * FROM user
+
+    rows, err := engine.Rows(...)
+    // SELECT * FROM user
+    defer rows.Close()
+    bean := new(Struct)
+    for rows.Next() {
+        err = rows.Scan(bean)
+    }
+
+5. Update one or more records
+
+    affected, err := engine.ID(...).Update(&user)
+    // UPDATE user SET ...
+
+6. Delete one or more records, Delete MUST has condition
+
+    affected, err := engine.Where(...).Delete(&user)
+    // DELETE FROM user Where ...
+
+7. Count records
+
+    counts, err := engine.Count(&user)
+    // SELECT count(*) AS total FROM user
+
+    counts, err := engine.SQL("select count(*) FROM user").Count()
+    // select count(*) FROM user
+
+8. Sum records
+
+    sumFloat64, err := engine.Sum(&user, "id")
+    // SELECT sum(id) from user
+
+    sumFloat64s, err := engine.Sums(&user, "id1", "id2")
+    // SELECT sum(id1), sum(id2) from user
+
+    sumInt64s, err := engine.SumsInt(&user, "id1", "id2")
+    // SELECT sum(id1), sum(id2) from user
+
+Conditions
+
+The above 8 methods could use with condition methods chainable.
+Attention: the above 8 methods should be the last chainable method.
+
+1. ID, In
+
+    engine.ID(1).Get(&user) // for single primary key
+    // SELECT * FROM user WHERE id = 1
+    engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
+    // SELECT * FROM user WHERE id1 = 1 AND id2 = 2
+    engine.In("id", 1, 2, 3).Find(&users)
+    // SELECT * FROM user WHERE id IN (1, 2, 3)
+    engine.In("id", []int{1, 2, 3}).Find(&users)
+    // SELECT * FROM user WHERE id IN (1, 2, 3)
+
+2. Where, And, Or
+
+    engine.Where().And().Or().Find()
+    // SELECT * FROM user WHERE (.. AND ..) OR ...
+
+3. OrderBy, Asc, Desc
+
+    engine.Asc().Desc().Find()
+    // SELECT * FROM user ORDER BY .. ASC, .. DESC
+    engine.OrderBy().Find()
+    // SELECT * FROM user ORDER BY ..
+
+4. Limit, Top
+
+    engine.Limit().Find()
+    // SELECT * FROM user LIMIT .. OFFSET ..
+    engine.Top(5).Find()
+    // SELECT TOP 5 * FROM user // for mssql
+    // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases
+
+5. SQL, let you custom SQL
+
+    var users []User
+    engine.SQL("select * from user").Find(&users)
+
+6. Cols, Omit, Distinct
+
+    var users []*User
+    engine.Cols("col1, col2").Find(&users)
+    // SELECT col1, col2 FROM user
+    engine.Cols("col1", "col2").Where().Update(user)
+    // UPDATE user set col1 = ?, col2 = ? Where ...
+    engine.Omit("col1").Find(&users)
+    // SELECT col2, col3 FROM user
+    engine.Omit("col1").Insert(&user)
+    // INSERT INTO table (non-col1) VALUES ()
+    engine.Distinct("col1").Find(&users)
+    // SELECT DISTINCT col1 FROM user
+
+7. Join, GroupBy, Having
+
+    engine.GroupBy("name").Having("name='xlw'").Find(&users)
+    //SELECT * FROM user GROUP BY name HAVING name='xlw'
+    engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find(&users)
+    //SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
+
+More usage, please visit http://xorm.io/docs
+*/
+package xorm

+ 1644 - 0
vendor/gitea.com/xorm/xorm/engine.go

@@ -0,0 +1,1644 @@
+// 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 (
+	"bufio"
+	"bytes"
+	"context"
+	"database/sql"
+	"encoding/gob"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"xorm.io/builder"
+	"xorm.io/core"
+)
+
+// Engine is the major struct of xorm, it means a database manager.
+// Commonly, an application only need one engine
+type Engine struct {
+	db      *core.DB
+	dialect core.Dialect
+
+	ColumnMapper  core.IMapper
+	TableMapper   core.IMapper
+	TagIdentifier string
+	Tables        map[reflect.Type]*core.Table
+
+	mutex  *sync.RWMutex
+	Cacher core.Cacher
+
+	showSQL      bool
+	showExecTime bool
+
+	logger     core.ILogger
+	TZLocation *time.Location // The timezone of the application
+	DatabaseTZ *time.Location // The timezone of the database
+
+	disableGlobalCache bool
+
+	tagHandlers map[string]tagHandler
+
+	engineGroup *EngineGroup
+
+	cachers    map[string]core.Cacher
+	cacherLock sync.RWMutex
+
+	defaultContext context.Context
+}
+
+func (engine *Engine) setCacher(tableName string, cacher core.Cacher) {
+	engine.cacherLock.Lock()
+	engine.cachers[tableName] = cacher
+	engine.cacherLock.Unlock()
+}
+
+func (engine *Engine) SetCacher(tableName string, cacher core.Cacher) {
+	engine.setCacher(tableName, cacher)
+}
+
+func (engine *Engine) getCacher(tableName string) core.Cacher {
+	var cacher core.Cacher
+	var ok bool
+	engine.cacherLock.RLock()
+	cacher, ok = engine.cachers[tableName]
+	engine.cacherLock.RUnlock()
+	if !ok && !engine.disableGlobalCache {
+		cacher = engine.Cacher
+	}
+	return cacher
+}
+
+func (engine *Engine) GetCacher(tableName string) core.Cacher {
+	return engine.getCacher(tableName)
+}
+
+// BufferSize sets buffer size for iterate
+func (engine *Engine) BufferSize(size int) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.BufferSize(size)
+}
+
+// CondDeleted returns the conditions whether a record is soft deleted.
+func (engine *Engine) CondDeleted(colName string) builder.Cond {
+	if engine.dialect.DBType() == core.MSSQL {
+		return builder.IsNull{colName}
+	}
+	return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1})
+}
+
+// ShowSQL show SQL statement or not on logger if log level is great than INFO
+func (engine *Engine) ShowSQL(show ...bool) {
+	engine.logger.ShowSQL(show...)
+	if len(show) == 0 {
+		engine.showSQL = true
+	} else {
+		engine.showSQL = show[0]
+	}
+}
+
+// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
+func (engine *Engine) ShowExecTime(show ...bool) {
+	if len(show) == 0 {
+		engine.showExecTime = true
+	} else {
+		engine.showExecTime = show[0]
+	}
+}
+
+// Logger return the logger interface
+func (engine *Engine) Logger() core.ILogger {
+	return engine.logger
+}
+
+// SetLogger set the new logger
+func (engine *Engine) SetLogger(logger core.ILogger) {
+	engine.logger = logger
+	engine.showSQL = logger.IsShowSQL()
+	engine.dialect.SetLogger(logger)
+}
+
+// SetLogLevel sets the logger level
+func (engine *Engine) SetLogLevel(level core.LogLevel) {
+	engine.logger.SetLevel(level)
+}
+
+// SetDisableGlobalCache disable global cache or not
+func (engine *Engine) SetDisableGlobalCache(disable bool) {
+	if engine.disableGlobalCache != disable {
+		engine.disableGlobalCache = disable
+	}
+}
+
+// DriverName return the current sql driver's name
+func (engine *Engine) DriverName() string {
+	return engine.dialect.DriverName()
+}
+
+// DataSourceName return the current connection string
+func (engine *Engine) DataSourceName() string {
+	return engine.dialect.DataSourceName()
+}
+
+// SetMapper set the name mapping rules
+func (engine *Engine) SetMapper(mapper core.IMapper) {
+	engine.SetTableMapper(mapper)
+	engine.SetColumnMapper(mapper)
+}
+
+// SetTableMapper set the table name mapping rule
+func (engine *Engine) SetTableMapper(mapper core.IMapper) {
+	engine.TableMapper = mapper
+}
+
+// SetColumnMapper set the column name mapping rule
+func (engine *Engine) SetColumnMapper(mapper core.IMapper) {
+	engine.ColumnMapper = mapper
+}
+
+// SupportInsertMany If engine's database support batch insert records like
+// "insert into user values (name, age), (name, age)".
+// When the return is ture, then engine.Insert(&users) will
+// generate batch sql and exeute.
+func (engine *Engine) SupportInsertMany() bool {
+	return engine.dialect.SupportInsertMany()
+}
+
+// QuoteStr Engine's database use which character as quote.
+// mysql, sqlite use ` and postgres use "
+func (engine *Engine) QuoteStr() string {
+	return engine.dialect.QuoteStr()
+}
+
+func (engine *Engine) quoteColumns(columnStr string) string {
+	columns := strings.Split(columnStr, ",")
+	for i := 0; i < len(columns); i++ {
+		columns[i] = engine.Quote(strings.TrimSpace(columns[i]))
+	}
+	return strings.Join(columns, ",")
+}
+
+// Quote Use QuoteStr quote the string sql
+func (engine *Engine) Quote(value string) string {
+	value = strings.TrimSpace(value)
+	if len(value) == 0 {
+		return value
+	}
+
+	if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' {
+		return value
+	}
+
+	value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1)
+
+	return engine.dialect.QuoteStr() + value + engine.dialect.QuoteStr()
+}
+
+// QuoteTo quotes string and writes into the buffer
+func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
+	if buf == nil {
+		return
+	}
+
+	value = strings.TrimSpace(value)
+	if value == "" {
+		return
+	}
+
+	if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' {
+		buf.WriteString(value)
+		return
+	}
+
+	value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1)
+
+	buf.WriteString(engine.dialect.QuoteStr())
+	buf.WriteString(value)
+	buf.WriteString(engine.dialect.QuoteStr())
+}
+
+func (engine *Engine) quote(sql string) string {
+	return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
+}
+
+// SqlType will be deprecated, please use SQLType instead
+//
+// Deprecated: use SQLType instead
+func (engine *Engine) SqlType(c *core.Column) string {
+	return engine.SQLType(c)
+}
+
+// SQLType A simple wrapper to dialect's core.SqlType method
+func (engine *Engine) SQLType(c *core.Column) string {
+	return engine.dialect.SqlType(c)
+}
+
+// AutoIncrStr Database's autoincrement statement
+func (engine *Engine) AutoIncrStr() string {
+	return engine.dialect.AutoIncrStr()
+}
+
+// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
+func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
+	engine.db.SetConnMaxLifetime(d)
+}
+
+// SetMaxOpenConns is only available for go 1.2+
+func (engine *Engine) SetMaxOpenConns(conns int) {
+	engine.db.SetMaxOpenConns(conns)
+}
+
+// SetMaxIdleConns set the max idle connections on pool, default is 2
+func (engine *Engine) SetMaxIdleConns(conns int) {
+	engine.db.SetMaxIdleConns(conns)
+}
+
+// SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
+func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
+	engine.Cacher = cacher
+}
+
+// GetDefaultCacher returns the default cacher
+func (engine *Engine) GetDefaultCacher() core.Cacher {
+	return engine.Cacher
+}
+
+// NoCache If you has set default cacher, and you want temporilly stop use cache,
+// you can use NoCache()
+func (engine *Engine) NoCache() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.NoCache()
+}
+
+// NoCascade If you do not want to auto cascade load object
+func (engine *Engine) NoCascade() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.NoCascade()
+}
+
+// MapCacher Set a table use a special cacher
+func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error {
+	engine.setCacher(engine.TableName(bean, true), cacher)
+	return nil
+}
+
+// NewDB provides an interface to operate database directly
+func (engine *Engine) NewDB() (*core.DB, error) {
+	return core.OpenDialect(engine.dialect)
+}
+
+// DB return the wrapper of sql.DB
+func (engine *Engine) DB() *core.DB {
+	return engine.db
+}
+
+// Dialect return database dialect
+func (engine *Engine) Dialect() core.Dialect {
+	return engine.dialect
+}
+
+// NewSession New a session
+func (engine *Engine) NewSession() *Session {
+	session := &Session{engine: engine}
+	session.Init()
+	return session
+}
+
+// Close the engine
+func (engine *Engine) Close() error {
+	return engine.db.Close()
+}
+
+// Ping tests if database is alive
+func (engine *Engine) Ping() error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Ping()
+}
+
+// logging sql
+func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
+	if engine.showSQL && !engine.showExecTime {
+		if len(sqlArgs) > 0 {
+			engine.logger.Infof("[SQL] %v %#v", sqlStr, sqlArgs)
+		} else {
+			engine.logger.Infof("[SQL] %v", sqlStr)
+		}
+	}
+}
+
+// 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 (engine *Engine) Sql(querystring string, args ...interface{}) *Session {
+	return engine.SQL(querystring, args...)
+}
+
+// SQL method let's you manually write raw SQL and operate
+// For example:
+//
+//         engine.SQL("select * from user").Find(&users)
+//
+// This    code will execute "select * from user" and set the records to users
+func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.SQL(query, args...)
+}
+
+// NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields
+// will automatically be filled with current time when Insert or Update
+// invoked. Call NoAutoTime if you dont' want to fill automatically.
+func (engine *Engine) NoAutoTime() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.NoAutoTime()
+}
+
+// NoAutoCondition disable auto generate Where condition from bean or not
+func (engine *Engine) NoAutoCondition(no ...bool) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.NoAutoCondition(no...)
+}
+
+// DBMetas Retrieve all tables, columns, indexes' informations from database.
+func (engine *Engine) DBMetas() ([]*core.Table, error) {
+	tables, err := engine.dialect.GetTables()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, table := range tables {
+		colSeq, cols, err := engine.dialect.GetColumns(table.Name)
+		if err != nil {
+			return nil, err
+		}
+		for _, name := range colSeq {
+			table.AddColumn(cols[name])
+		}
+		indexes, err := engine.dialect.GetIndexes(table.Name)
+		if err != nil {
+			return nil, err
+		}
+		table.Indexes = indexes
+
+		for _, index := range indexes {
+			for _, name := range index.Cols {
+				if col := table.GetColumn(name); col != nil {
+					col.Indexes[index.Name] = index.Type
+				} else {
+					return nil, fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq())
+				}
+			}
+		}
+	}
+	return tables, nil
+}
+
+// DumpAllToFile dump database all table structs and data to a file
+func (engine *Engine) DumpAllToFile(fp string, tp ...core.DbType) error {
+	f, err := os.Create(fp)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return engine.DumpAll(f, tp...)
+}
+
+// DumpAll dump database all table structs and data to w
+func (engine *Engine) DumpAll(w io.Writer, tp ...core.DbType) error {
+	tables, err := engine.DBMetas()
+	if err != nil {
+		return err
+	}
+	return engine.DumpTables(tables, w, tp...)
+}
+
+// DumpTablesToFile dump specified tables to SQL file.
+func (engine *Engine) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error {
+	f, err := os.Create(fp)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return engine.DumpTables(tables, f, tp...)
+}
+
+// DumpTables dump specify tables to io.Writer
+func (engine *Engine) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error {
+	return engine.dumpTables(tables, w, tp...)
+}
+
+// dumpTables dump database all table structs and data to w with specify db type
+func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error {
+	var dialect core.Dialect
+	var distDBName string
+	if len(tp) == 0 {
+		dialect = engine.dialect
+		distDBName = string(engine.dialect.DBType())
+	} else {
+		dialect = core.QueryDialect(tp[0])
+		if dialect == nil {
+			return errors.New("Unsupported database type")
+		}
+		dialect.Init(nil, engine.dialect.URI(), "", "")
+		distDBName = string(tp[0])
+	}
+
+	_, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s, from %s to %s*/\n\n",
+		Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.DBType(), strings.ToUpper(distDBName)))
+	if err != nil {
+		return err
+	}
+
+	for i, table := range tables {
+		if i > 0 {
+			_, err = io.WriteString(w, "\n")
+			if err != nil {
+				return err
+			}
+		}
+		_, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n")
+		if err != nil {
+			return err
+		}
+		for _, index := range table.Indexes {
+			_, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n")
+			if err != nil {
+				return err
+			}
+		}
+
+		cols := table.ColumnsSeq()
+		colNames := engine.dialect.Quote(strings.Join(cols, engine.dialect.Quote(", ")))
+		destColNames := dialect.Quote(strings.Join(cols, dialect.Quote(", ")))
+
+		rows, err := engine.DB().Query("SELECT " + colNames + " FROM " + engine.Quote(table.Name))
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			dest := make([]interface{}, len(cols))
+			err = rows.ScanSlice(&dest)
+			if err != nil {
+				return err
+			}
+
+			_, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+destColNames+") VALUES (")
+			if err != nil {
+				return err
+			}
+
+			var temp string
+			for i, d := range dest {
+				col := table.GetColumn(cols[i])
+				if col == nil {
+					return errors.New("unknow column error")
+				}
+
+				if d == nil {
+					temp += ", NULL"
+				} else if col.SQLType.IsText() || col.SQLType.IsTime() {
+					var v = fmt.Sprintf("%s", d)
+					if strings.HasSuffix(v, " +0000 UTC") {
+						temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")])
+					} else {
+						temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
+					}
+				} else if col.SQLType.IsBlob() {
+					if reflect.TypeOf(d).Kind() == reflect.Slice {
+						temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte)))
+					} else if reflect.TypeOf(d).Kind() == reflect.String {
+						temp += fmt.Sprintf(", '%s'", d.(string))
+					}
+				} else if col.SQLType.IsNumeric() {
+					switch reflect.TypeOf(d).Kind() {
+					case reflect.Slice:
+						if col.SQLType.Name == core.Bool {
+							temp += fmt.Sprintf(", %v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
+						} else {
+							temp += fmt.Sprintf(", %s", string(d.([]byte)))
+						}
+					case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
+						if col.SQLType.Name == core.Bool {
+							temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Int() > 0))
+						} else {
+							temp += fmt.Sprintf(", %v", d)
+						}
+					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+						if col.SQLType.Name == core.Bool {
+							temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Uint() > 0))
+						} else {
+							temp += fmt.Sprintf(", %v", d)
+						}
+					default:
+						temp += fmt.Sprintf(", %v", d)
+					}
+				} else {
+					s := fmt.Sprintf("%v", d)
+					if strings.Contains(s, ":") || strings.Contains(s, "-") {
+						if strings.HasSuffix(s, " +0000 UTC") {
+							temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")])
+						} else {
+							temp += fmt.Sprintf(", '%s'", s)
+						}
+					} else {
+						temp += fmt.Sprintf(", %s", s)
+					}
+				}
+			}
+			_, err = io.WriteString(w, temp[2:]+");\n")
+			if err != nil {
+				return err
+			}
+		}
+
+		// FIXME: Hack for postgres
+		if string(dialect.DBType()) == core.POSTGRES && table.AutoIncrColumn() != nil {
+			_, err = io.WriteString(w, "SELECT setval('"+table.Name+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dialect.Quote(table.Name)+"), 1), false);\n")
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// Cascade use cascade or not
+func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Cascade(trueOrFalse...)
+}
+
+// Where method provide a condition query
+func (engine *Engine) Where(query interface{}, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Where(query, args...)
+}
+
+// Id will be deprecated, please use ID instead
+func (engine *Engine) Id(id interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Id(id)
+}
+
+// ID method provoide a condition as (id) = ?
+func (engine *Engine) ID(id interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.ID(id)
+}
+
+// Before apply before Processor, affected bean is passed to closure arg
+func (engine *Engine) Before(closures func(interface{})) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Before(closures)
+}
+
+// After apply after insert Processor, affected bean is passed to closure arg
+func (engine *Engine) After(closures func(interface{})) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.After(closures)
+}
+
+// Charset set charset when create table, only support mysql now
+func (engine *Engine) Charset(charset string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Charset(charset)
+}
+
+// StoreEngine set store engine when create table, only support mysql now
+func (engine *Engine) StoreEngine(storeEngine string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.StoreEngine(storeEngine)
+}
+
+// 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 (engine *Engine) Distinct(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Distinct(columns...)
+}
+
+// Select customerize your select columns or contents
+func (engine *Engine) Select(str string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Select(str)
+}
+
+// Cols only use the parameters as select or update columns
+func (engine *Engine) Cols(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Cols(columns...)
+}
+
+// AllCols indicates that all columns should be use
+func (engine *Engine) AllCols() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.AllCols()
+}
+
+// MustCols specify some columns must use even if they are empty
+func (engine *Engine) MustCols(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.MustCols(columns...)
+}
+
+// UseBool xorm 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 (engine *Engine) UseBool(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.UseBool(columns...)
+}
+
+// Omit only not use the parameters as select or update columns
+func (engine *Engine) Omit(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Omit(columns...)
+}
+
+// Nullable set null when column is zero-value and nullable for update
+func (engine *Engine) Nullable(columns ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Nullable(columns...)
+}
+
+// In will generate "column IN (?, ?)"
+func (engine *Engine) In(column string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.In(column, args...)
+}
+
+// NotIn will generate "column NOT IN (?, ?)"
+func (engine *Engine) NotIn(column string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.NotIn(column, args...)
+}
+
+// Incr provides a update string like "column = column + ?"
+func (engine *Engine) Incr(column string, arg ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Incr(column, arg...)
+}
+
+// Decr provides a update string like "column = column - ?"
+func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Decr(column, arg...)
+}
+
+// SetExpr provides a update string like "column = {expression}"
+func (engine *Engine) SetExpr(column string, expression string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.SetExpr(column, expression)
+}
+
+// Table temporarily change the Get, Find, Update's table
+func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Table(tableNameOrBean)
+}
+
+// Alias set the table alias
+func (engine *Engine) Alias(alias string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Alias(alias)
+}
+
+// Limit will generate "LIMIT start, limit"
+func (engine *Engine) Limit(limit int, start ...int) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Limit(limit, start...)
+}
+
+// Desc will generate "ORDER BY column1 DESC, column2 DESC"
+func (engine *Engine) Desc(colNames ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Desc(colNames...)
+}
+
+// Asc will generate "ORDER BY column1,column2 Asc"
+// This method can chainable use.
+//
+//        engine.Desc("name").Asc("age").Find(&users)
+//        // SELECT * FROM user ORDER BY name DESC, age ASC
+//
+func (engine *Engine) Asc(colNames ...string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Asc(colNames...)
+}
+
+// OrderBy will generate "ORDER BY order"
+func (engine *Engine) OrderBy(order string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.OrderBy(order)
+}
+
+// Prepare enables prepare statement
+func (engine *Engine) Prepare() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Prepare()
+}
+
+// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
+func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Join(joinOperator, tablename, condition, args...)
+}
+
+// GroupBy generate group by statement
+func (engine *Engine) GroupBy(keys string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.GroupBy(keys)
+}
+
+// Having generate having statement
+func (engine *Engine) Having(conditions string) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Having(conditions)
+}
+
+// UnMapType removes the datbase mapper of a type
+func (engine *Engine) UnMapType(t reflect.Type) {
+	engine.mutex.Lock()
+	defer engine.mutex.Unlock()
+	delete(engine.Tables, t)
+}
+
+func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) {
+	t := v.Type()
+	engine.mutex.Lock()
+	defer engine.mutex.Unlock()
+	table, ok := engine.Tables[t]
+	if !ok {
+		var err error
+		table, err = engine.mapType(v)
+		if err != nil {
+			return nil, err
+		}
+
+		engine.Tables[t] = table
+		if engine.Cacher != nil {
+			if v.CanAddr() {
+				engine.GobRegister(v.Addr().Interface())
+			} else {
+				engine.GobRegister(v.Interface())
+			}
+		}
+	}
+	return table, nil
+}
+
+// GobRegister register one struct to gob for cache use
+func (engine *Engine) GobRegister(v interface{}) *Engine {
+	gob.Register(v)
+	return engine
+}
+
+// Table table struct
+type Table struct {
+	*core.Table
+	Name string
+}
+
+// IsValid if table is valid
+func (t *Table) IsValid() bool {
+	return t.Table != nil && len(t.Name) > 0
+}
+
+// TableInfo get table info according to bean's content
+func (engine *Engine) TableInfo(bean interface{}) *Table {
+	v := rValue(bean)
+	tb, err := engine.autoMapType(v)
+	if err != nil {
+		engine.logger.Error(err)
+	}
+	return &Table{tb, engine.TableName(bean)}
+}
+
+func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
+	if index, ok := table.Indexes[indexName]; ok {
+		index.AddColumn(col.Name)
+		col.Indexes[index.Name] = indexType
+	} else {
+		index := core.NewIndex(indexName, indexType)
+		index.AddColumn(col.Name)
+		table.AddIndex(index)
+		col.Indexes[index.Name] = indexType
+	}
+}
+
+// TableName table name interface to define customerize table name
+type TableName interface {
+	TableName() string
+}
+
+var (
+	tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
+)
+
+func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
+	t := v.Type()
+	table := core.NewEmptyTable()
+	table.Type = t
+	table.Name = engine.tbNameForMap(v)
+
+	var idFieldColName string
+	var hasCacheTag, hasNoCacheTag bool
+
+	for i := 0; i < t.NumField(); i++ {
+		tag := t.Field(i).Tag
+
+		ormTagStr := tag.Get(engine.TagIdentifier)
+		var col *core.Column
+		fieldValue := v.Field(i)
+		fieldType := fieldValue.Type()
+
+		if ormTagStr != "" {
+			col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
+				IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)}
+			tags := splitTag(ormTagStr)
+
+			if len(tags) > 0 {
+				if tags[0] == "-" {
+					continue
+				}
+
+				var ctx = tagContext{
+					table:      table,
+					col:        col,
+					fieldValue: fieldValue,
+					indexNames: make(map[string]int),
+					engine:     engine,
+				}
+
+				if strings.HasPrefix(strings.ToUpper(tags[0]), "EXTENDS") {
+					pStart := strings.Index(tags[0], "(")
+					if pStart > -1 && strings.HasSuffix(tags[0], ")") {
+						var tagPrefix = strings.TrimFunc(tags[0][pStart+1:len(tags[0])-1], func(r rune) bool {
+							return r == '\'' || r == '"'
+						})
+
+						ctx.params = []string{tagPrefix}
+					}
+
+					if err := ExtendsTagHandler(&ctx); err != nil {
+						return nil, err
+					}
+					continue
+				}
+
+				for j, key := range tags {
+					if ctx.ignoreNext {
+						ctx.ignoreNext = false
+						continue
+					}
+
+					k := strings.ToUpper(key)
+					ctx.tagName = k
+					ctx.params = []string{}
+
+					pStart := strings.Index(k, "(")
+					if pStart == 0 {
+						return nil, errors.New("( could not be the first charactor")
+					}
+					if pStart > -1 {
+						if !strings.HasSuffix(k, ")") {
+							return nil, fmt.Errorf("field %s tag %s cannot match ) charactor", col.FieldName, key)
+						}
+
+						ctx.tagName = k[:pStart]
+						ctx.params = strings.Split(key[pStart+1:len(k)-1], ",")
+					}
+
+					if j > 0 {
+						ctx.preTag = strings.ToUpper(tags[j-1])
+					}
+					if j < len(tags)-1 {
+						ctx.nextTag = tags[j+1]
+					} else {
+						ctx.nextTag = ""
+					}
+
+					if h, ok := engine.tagHandlers[ctx.tagName]; ok {
+						if err := h(&ctx); err != nil {
+							return nil, err
+						}
+					} else {
+						if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") {
+							col.Name = key[1 : len(key)-1]
+						} else {
+							col.Name = key
+						}
+					}
+
+					if ctx.hasCacheTag {
+						hasCacheTag = true
+					}
+					if ctx.hasNoCacheTag {
+						hasNoCacheTag = true
+					}
+				}
+
+				if col.SQLType.Name == "" {
+					col.SQLType = core.Type2SQLType(fieldType)
+				}
+				engine.dialect.SqlType(col)
+				if col.Length == 0 {
+					col.Length = col.SQLType.DefaultLength
+				}
+				if col.Length2 == 0 {
+					col.Length2 = col.SQLType.DefaultLength2
+				}
+				if col.Name == "" {
+					col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
+				}
+
+				if ctx.isUnique {
+					ctx.indexNames[col.Name] = core.UniqueType
+				} else if ctx.isIndex {
+					ctx.indexNames[col.Name] = core.IndexType
+				}
+
+				for indexName, indexType := range ctx.indexNames {
+					addIndex(indexName, table, col, indexType)
+				}
+			}
+		} else {
+			var sqlType core.SQLType
+			if fieldValue.CanAddr() {
+				if _, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+					sqlType = core.SQLType{Name: core.Text}
+				}
+			}
+			if _, ok := fieldValue.Interface().(core.Conversion); ok {
+				sqlType = core.SQLType{Name: core.Text}
+			} else {
+				sqlType = core.Type2SQLType(fieldType)
+			}
+			col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name),
+				t.Field(i).Name, sqlType, sqlType.DefaultLength,
+				sqlType.DefaultLength2, true)
+
+			if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
+				idFieldColName = col.Name
+			}
+		}
+		if col.IsAutoIncrement {
+			col.Nullable = false
+		}
+
+		table.AddColumn(col)
+
+	} // end for
+
+	if idFieldColName != "" && len(table.PrimaryKeys) == 0 {
+		col := table.GetColumn(idFieldColName)
+		col.IsPrimaryKey = true
+		col.IsAutoIncrement = true
+		col.Nullable = false
+		table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
+		table.AutoIncrement = col.Name
+	}
+
+	if hasCacheTag {
+		if engine.Cacher != nil { // !nash! use engine's cacher if provided
+			engine.logger.Info("enable cache on table:", table.Name)
+			engine.setCacher(table.Name, engine.Cacher)
+		} else {
+			engine.logger.Info("enable LRU cache on table:", table.Name)
+			engine.setCacher(table.Name, NewLRUCacher2(NewMemoryStore(), time.Hour, 10000))
+		}
+	}
+	if hasNoCacheTag {
+		engine.logger.Info("disable cache on table:", table.Name)
+		engine.setCacher(table.Name, nil)
+	}
+
+	return table, nil
+}
+
+// IsTableEmpty if a table has any reocrd
+func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.IsTableEmpty(bean)
+}
+
+// IsTableExist if a table is exist
+func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.IsTableExist(beanOrTableName)
+}
+
+// IdOf get id from one struct
+//
+// Deprecated: use IDOf instead.
+func (engine *Engine) IdOf(bean interface{}) core.PK {
+	return engine.IDOf(bean)
+}
+
+// IDOf get id from one struct
+func (engine *Engine) IDOf(bean interface{}) core.PK {
+	return engine.IdOfV(reflect.ValueOf(bean))
+}
+
+// IdOfV get id from one value of struct
+//
+// Deprecated: use IDOfV instead.
+func (engine *Engine) IdOfV(rv reflect.Value) core.PK {
+	return engine.IDOfV(rv)
+}
+
+// IDOfV get id from one value of struct
+func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
+	pk, err := engine.idOfV(rv)
+	if err != nil {
+		engine.logger.Error(err)
+		return nil
+	}
+	return pk
+}
+
+func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
+	v := reflect.Indirect(rv)
+	table, err := engine.autoMapType(v)
+	if err != nil {
+		return nil, err
+	}
+
+	pk := make([]interface{}, len(table.PrimaryKeys))
+	for i, col := range table.PKColumns() {
+		var err error
+
+		fieldName := col.FieldName
+		for {
+			parts := strings.SplitN(fieldName, ".", 2)
+			if len(parts) == 1 {
+				break
+			}
+
+			v = v.FieldByName(parts[0])
+			if v.Kind() == reflect.Ptr {
+				v = v.Elem()
+			}
+			if v.Kind() != reflect.Struct {
+				return nil, ErrUnSupportedType
+			}
+			fieldName = parts[1]
+		}
+
+		pkField := v.FieldByName(fieldName)
+		switch pkField.Kind() {
+		case reflect.String:
+			pk[i], err = engine.idTypeAssertion(col, pkField.String())
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			pk[i], err = engine.idTypeAssertion(col, strconv.FormatInt(pkField.Int(), 10))
+		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			// id of uint will be converted to int64
+			pk[i], err = engine.idTypeAssertion(col, strconv.FormatUint(pkField.Uint(), 10))
+		}
+
+		if err != nil {
+			return nil, err
+		}
+	}
+	return core.PK(pk), nil
+}
+
+func (engine *Engine) idTypeAssertion(col *core.Column, sid string) (interface{}, error) {
+	if col.SQLType.IsNumeric() {
+		n, err := strconv.ParseInt(sid, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+		return n, nil
+	} else if col.SQLType.IsText() {
+		return sid, nil
+	} else {
+		return nil, errors.New("not supported")
+	}
+}
+
+// CreateIndexes create indexes
+func (engine *Engine) CreateIndexes(bean interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.CreateIndexes(bean)
+}
+
+// CreateUniques create uniques
+func (engine *Engine) CreateUniques(bean interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.CreateUniques(bean)
+}
+
+// ClearCacheBean if enabled cache, clear the cache bean
+func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
+	tableName := engine.TableName(bean)
+	cacher := engine.getCacher(tableName)
+	if cacher != nil {
+		cacher.ClearIds(tableName)
+		cacher.DelBean(tableName, id)
+	}
+	return nil
+}
+
+// ClearCache if enabled cache, clear some tables' cache
+func (engine *Engine) ClearCache(beans ...interface{}) error {
+	for _, bean := range beans {
+		tableName := engine.TableName(bean)
+		cacher := engine.getCacher(tableName)
+		if cacher != nil {
+			cacher.ClearIds(tableName)
+			cacher.ClearBeans(tableName)
+		}
+	}
+	return nil
+}
+
+// Sync the new struct changes to database, this method will automatically add
+// table, column, index, unique. but will not delete or change anything.
+// If you change some field, you should change the database manually.
+func (engine *Engine) Sync(beans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+
+	for _, bean := range beans {
+		v := rValue(bean)
+		tableNameNoSchema := engine.TableName(bean)
+		table, err := engine.autoMapType(v)
+		if err != nil {
+			return err
+		}
+
+		isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
+		if err != nil {
+			return err
+		}
+		if !isExist {
+			err = session.createTable(bean)
+			if err != nil {
+				return err
+			}
+		}
+		/*isEmpty, err := engine.IsEmptyTable(bean)
+		  if err != nil {
+		      return err
+		  }*/
+		var isEmpty bool
+		if isEmpty {
+			err = session.dropTable(bean)
+			if err != nil {
+				return err
+			}
+			err = session.createTable(bean)
+			if err != nil {
+				return err
+			}
+		} else {
+			for _, col := range table.Columns() {
+				isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name)
+				if err != nil {
+					return err
+				}
+				if !isExist {
+					if err := session.statement.setRefBean(bean); err != nil {
+						return err
+					}
+					err = session.addColumn(col.Name)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			for name, index := range table.Indexes {
+				if err := session.statement.setRefBean(bean); err != nil {
+					return err
+				}
+				if index.Type == core.UniqueType {
+					isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
+					if err != nil {
+						return err
+					}
+					if !isExist {
+						if err := session.statement.setRefBean(bean); err != nil {
+							return err
+						}
+
+						err = session.addUnique(tableNameNoSchema, name)
+						if err != nil {
+							return err
+						}
+					}
+				} else if index.Type == core.IndexType {
+					isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
+					if err != nil {
+						return err
+					}
+					if !isExist {
+						if err := session.statement.setRefBean(bean); err != nil {
+							return err
+						}
+
+						err = session.addIndex(tableNameNoSchema, name)
+						if err != nil {
+							return err
+						}
+					}
+				} else {
+					return errors.New("unknow index type")
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// Sync2 synchronize structs to database tables
+func (engine *Engine) Sync2(beans ...interface{}) error {
+	s := engine.NewSession()
+	defer s.Close()
+	return s.Sync2(beans...)
+}
+
+// CreateTables create tabls according bean
+func (engine *Engine) CreateTables(beans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+
+	err := session.Begin()
+	if err != nil {
+		return err
+	}
+
+	for _, bean := range beans {
+		err = session.createTable(bean)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	return session.Commit()
+}
+
+// DropTables drop specify tables
+func (engine *Engine) DropTables(beans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+
+	err := session.Begin()
+	if err != nil {
+		return err
+	}
+
+	for _, bean := range beans {
+		err = session.dropTable(bean)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	return session.Commit()
+}
+
+// DropIndexes drop indexes of a table
+func (engine *Engine) DropIndexes(bean interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.DropIndexes(bean)
+}
+
+// Exec raw sql
+func (engine *Engine) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Exec(sqlOrArgs...)
+}
+
+// Query a raw sql and return records as []map[string][]byte
+func (engine *Engine) Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Query(sqlOrArgs...)
+}
+
+// QueryString runs a raw sql and return records as []map[string]string
+func (engine *Engine) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryString(sqlOrArgs...)
+}
+
+// QueryInterface runs a raw sql and return records as []map[string]interface{}
+func (engine *Engine) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryInterface(sqlOrArgs...)
+}
+
+// Insert one or more records
+func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Insert(beans...)
+}
+
+// InsertOne insert only one record
+func (engine *Engine) InsertOne(bean interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.InsertOne(bean)
+}
+
+// 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 (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Update(bean, condiBeans...)
+}
+
+// Delete records, bean's non-empty fields are conditions
+func (engine *Engine) Delete(bean interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Delete(bean)
+}
+
+// Get retrieve one record from table, bean's non-empty fields
+// are conditions
+func (engine *Engine) Get(bean interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Get(bean)
+}
+
+// Exist returns true if the record exist otherwise return false
+func (engine *Engine) Exist(bean ...interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Exist(bean...)
+}
+
+// Find retrieve records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Find(beans, condiBeans...)
+}
+
+// FindAndCount find the results and also return the counts
+func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.FindAndCount(rowsSlicePtr, condiBean...)
+}
+
+// Iterate record by record handle records from table, bean's non-empty fields
+// are conditions.
+func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Iterate(bean, fun)
+}
+
+// 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 (engine *Engine) Rows(bean interface{}) (*Rows, error) {
+	session := engine.NewSession()
+	return session.Rows(bean)
+}
+
+// Count counts the records. bean's non-empty fields are conditions.
+func (engine *Engine) Count(bean ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Count(bean...)
+}
+
+// Sum sum the records by some column. bean's non-empty fields are conditions.
+func (engine *Engine) Sum(bean interface{}, colName string) (float64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Sum(bean, colName)
+}
+
+// SumInt sum the records by some column. bean's non-empty fields are conditions.
+func (engine *Engine) SumInt(bean interface{}, colName string) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.SumInt(bean, colName)
+}
+
+// Sums sum the records by some columns. bean's non-empty fields are conditions.
+func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Sums(bean, colNames...)
+}
+
+// SumsInt like Sums but return slice of int64 instead of float64.
+func (engine *Engine) SumsInt(bean interface{}, colNames ...string) ([]int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.SumsInt(bean, colNames...)
+}
+
+// ImportFile SQL DDL file
+func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
+	file, err := os.Open(ddlPath)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	return engine.Import(file)
+}
+
+// Import SQL DDL from io.Reader
+func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
+	var results []sql.Result
+	var lastError error
+	scanner := bufio.NewScanner(r)
+
+	semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+		if atEOF && len(data) == 0 {
+			return 0, nil, nil
+		}
+		if i := bytes.IndexByte(data, ';'); i >= 0 {
+			return i + 1, data[0:i], nil
+		}
+		// If we're at EOF, we have a final, non-terminated line. Return it.
+		if atEOF {
+			return len(data), data, nil
+		}
+		// Request more data.
+		return 0, nil, nil
+	}
+
+	scanner.Split(semiColSpliter)
+
+	for scanner.Scan() {
+		query := strings.Trim(scanner.Text(), " \t\n\r")
+		if len(query) > 0 {
+			engine.logSQL(query)
+			result, err := engine.DB().Exec(query)
+			results = append(results, result)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return results, lastError
+}
+
+// nowTime return current time
+func (engine *Engine) nowTime(col *core.Column) (interface{}, time.Time) {
+	t := time.Now()
+	var tz = engine.DatabaseTZ
+	if !col.DisableTimeZone && col.TimeZone != nil {
+		tz = col.TimeZone
+	}
+	return engine.formatTime(col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation)
+}
+
+func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
+	if t.IsZero() {
+		if col.Nullable {
+			return nil
+		}
+		return ""
+	}
+
+	if col.TimeZone != nil {
+		return engine.formatTime(col.SQLType.Name, t.In(col.TimeZone))
+	}
+	return engine.formatTime(col.SQLType.Name, t.In(engine.DatabaseTZ))
+}
+
+// formatTime format time as column type
+func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) {
+	switch sqlTypeName {
+	case core.Time:
+		s := t.Format("2006-01-02 15:04:05") //time.RFC3339
+		v = s[11:19]
+	case core.Date:
+		v = t.Format("2006-01-02")
+	case core.DateTime, core.TimeStamp:
+		v = t.Format("2006-01-02 15:04:05")
+	case core.TimeStampz:
+		if engine.dialect.DBType() == core.MSSQL {
+			v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
+		} else {
+			v = t.Format(time.RFC3339Nano)
+		}
+	case core.BigInt, core.Int:
+		v = t.Unix()
+	default:
+		v = t
+	}
+	return
+}
+
+// GetColumnMapper returns the column name mapper
+func (engine *Engine) GetColumnMapper() core.IMapper {
+	return engine.ColumnMapper
+}
+
+// GetTableMapper returns the table name mapper
+func (engine *Engine) GetTableMapper() core.IMapper {
+	return engine.TableMapper
+}
+
+// GetTZLocation returns time zone of the application
+func (engine *Engine) GetTZLocation() *time.Location {
+	return engine.TZLocation
+}
+
+// SetTZLocation sets time zone of the application
+func (engine *Engine) SetTZLocation(tz *time.Location) {
+	engine.TZLocation = tz
+}
+
+// GetTZDatabase returns time zone of the database
+func (engine *Engine) GetTZDatabase() *time.Location {
+	return engine.DatabaseTZ
+}
+
+// SetTZDatabase sets time zone of the database
+func (engine *Engine) SetTZDatabase(tz *time.Location) {
+	engine.DatabaseTZ = tz
+}
+
+// SetSchema sets the schema of database
+func (engine *Engine) SetSchema(schema string) {
+	engine.dialect.URI().Schema = schema
+}
+
+// Unscoped always disable struct tag "deleted"
+func (engine *Engine) Unscoped() *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Unscoped()
+}

+ 232 - 0
vendor/gitea.com/xorm/xorm/engine_cond.go

@@ -0,0 +1,232 @@
+// 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"
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+
+	"xorm.io/builder"
+	"xorm.io/core"
+)
+
+func (engine *Engine) buildConds(table *core.Table, bean interface{},
+	includeVersion bool, includeUpdated bool, includeNil bool,
+	includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
+	mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
+	var conds []builder.Cond
+	for _, col := range table.Columns() {
+		if !includeVersion && col.IsVersion {
+			continue
+		}
+		if !includeUpdated && col.IsUpdated {
+			continue
+		}
+		if !includeAutoIncr && col.IsAutoIncrement {
+			continue
+		}
+
+		if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
+			continue
+		}
+		if col.SQLType.IsJson() {
+			continue
+		}
+
+		var colName string
+		if addedTableName {
+			var nm = tableName
+			if len(aliasName) > 0 {
+				nm = aliasName
+			}
+			colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
+		} else {
+			colName = engine.Quote(col.Name)
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			if !strings.Contains(err.Error(), "is not valid") {
+				engine.logger.Warn(err)
+			}
+			continue
+		}
+
+		if col.IsDeleted && !unscoped { // tag "deleted" is enabled
+			conds = append(conds, engine.CondDeleted(colName))
+		}
+
+		fieldValue := *fieldValuePtr
+		if fieldValue.Interface() == nil {
+			continue
+		}
+
+		fieldType := reflect.TypeOf(fieldValue.Interface())
+		requiredField := useAllCols
+
+		if b, ok := getFlagForColumn(mustColumnMap, col); ok {
+			if b {
+				requiredField = true
+			} else {
+				continue
+			}
+		}
+
+		if fieldType.Kind() == reflect.Ptr {
+			if fieldValue.IsNil() {
+				if includeNil {
+					conds = append(conds, builder.Eq{colName: nil})
+				}
+				continue
+			} else if !fieldValue.IsValid() {
+				continue
+			} else {
+				// dereference ptr type to instance type
+				fieldValue = fieldValue.Elem()
+				fieldType = reflect.TypeOf(fieldValue.Interface())
+				requiredField = true
+			}
+		}
+
+		var val interface{}
+		switch fieldType.Kind() {
+		case reflect.Bool:
+			if allUseBool || requiredField {
+				val = fieldValue.Interface()
+			} else {
+				// if a bool in a struct, it will not be as a condition because it default is false,
+				// please use Where() instead
+				continue
+			}
+		case reflect.String:
+			if !requiredField && fieldValue.String() == "" {
+				continue
+			}
+			// for MyString, should convert to string or panic
+			if fieldType.String() != reflect.String.String() {
+				val = fieldValue.String()
+			} else {
+				val = fieldValue.Interface()
+			}
+		case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
+			if !requiredField && fieldValue.Int() == 0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Float32, reflect.Float64:
+			if !requiredField && fieldValue.Float() == 0.0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
+			if !requiredField && fieldValue.Uint() == 0 {
+				continue
+			}
+			t := int64(fieldValue.Uint())
+			val = reflect.ValueOf(&t).Interface()
+		case reflect.Struct:
+			if fieldType.ConvertibleTo(core.TimeType) {
+				t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
+				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
+					continue
+				}
+				val = engine.formatColTime(col, t)
+			} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
+				continue
+			} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
+				val, _ = valNul.Value()
+				if val == nil {
+					continue
+				}
+			} else {
+				if col.SQLType.IsJson() {
+					if col.SQLType.IsText() {
+						bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
+						if err != nil {
+							engine.logger.Error(err)
+							continue
+						}
+						val = string(bytes)
+					} else if col.SQLType.IsBlob() {
+						var bytes []byte
+						var err error
+						bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
+						if err != nil {
+							engine.logger.Error(err)
+							continue
+						}
+						val = bytes
+					}
+				} else {
+					engine.autoMapType(fieldValue)
+					if table, ok := engine.Tables[fieldValue.Type()]; ok {
+						if len(table.PrimaryKeys) == 1 {
+							pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
+							// fix non-int pk issues
+							//if pkField.Int() != 0 {
+							if pkField.IsValid() && !isZero(pkField.Interface()) {
+								val = pkField.Interface()
+							} else {
+								continue
+							}
+						} else {
+							//TODO: how to handler?
+							return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
+						}
+					} else {
+						val = fieldValue.Interface()
+					}
+				}
+			}
+		case reflect.Array:
+			continue
+		case reflect.Slice, reflect.Map:
+			if fieldValue == reflect.Zero(fieldType) {
+				continue
+			}
+			if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
+				continue
+			}
+
+			if col.SQLType.IsText() {
+				bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
+				if err != nil {
+					engine.logger.Error(err)
+					continue
+				}
+				val = string(bytes)
+			} else if col.SQLType.IsBlob() {
+				var bytes []byte
+				var err error
+				if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
+					fieldType.Elem().Kind() == reflect.Uint8 {
+					if fieldValue.Len() > 0 {
+						val = fieldValue.Bytes()
+					} else {
+						continue
+					}
+				} else {
+					bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
+					if err != nil {
+						engine.logger.Error(err)
+						continue
+					}
+					val = bytes
+				}
+			} else {
+				continue
+			}
+		default:
+			val = fieldValue.Interface()
+		}
+
+		conds = append(conds, builder.Eq{colName: val})
+	}
+
+	return builder.And(conds...), nil
+}

+ 28 - 0
vendor/gitea.com/xorm/xorm/engine_context.go

@@ -0,0 +1,28 @@
+// Copyright 2019 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.
+
+// +build go1.8
+
+package xorm
+
+import "context"
+
+// Context creates a session with the context
+func (engine *Engine) Context(ctx context.Context) *Session {
+	session := engine.NewSession()
+	session.isAutoClose = true
+	return session.Context(ctx)
+}
+
+// SetDefaultContext set the default context
+func (engine *Engine) SetDefaultContext(ctx context.Context) {
+	engine.defaultContext = ctx
+}
+
+// PingContext tests if database is alive
+func (engine *Engine) PingContext(ctx context.Context) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.PingContext(ctx)
+}

+ 219 - 0
vendor/gitea.com/xorm/xorm/engine_group.go

@@ -0,0 +1,219 @@
+// 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 (
+	"context"
+	"time"
+
+	"xorm.io/core"
+)
+
+// EngineGroup defines an engine group
+type EngineGroup struct {
+	*Engine
+	slaves []*Engine
+	policy GroupPolicy
+}
+
+// NewEngineGroup creates a new engine group
+func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) {
+	var eg EngineGroup
+	if len(policies) > 0 {
+		eg.policy = policies[0]
+	} else {
+		eg.policy = RoundRobinPolicy()
+	}
+
+	driverName, ok1 := args1.(string)
+	conns, ok2 := args2.([]string)
+	if ok1 && ok2 {
+		engines := make([]*Engine, len(conns))
+		for i, conn := range conns {
+			engine, err := NewEngine(driverName, conn)
+			if err != nil {
+				return nil, err
+			}
+			engine.engineGroup = &eg
+			engines[i] = engine
+		}
+
+		eg.Engine = engines[0]
+		eg.slaves = engines[1:]
+		return &eg, nil
+	}
+
+	master, ok3 := args1.(*Engine)
+	slaves, ok4 := args2.([]*Engine)
+	if ok3 && ok4 {
+		master.engineGroup = &eg
+		for i := 0; i < len(slaves); i++ {
+			slaves[i].engineGroup = &eg
+		}
+		eg.Engine = master
+		eg.slaves = slaves
+		return &eg, nil
+	}
+	return nil, ErrParamsType
+}
+
+// Close the engine
+func (eg *EngineGroup) Close() error {
+	err := eg.Engine.Close()
+	if err != nil {
+		return err
+	}
+
+	for i := 0; i < len(eg.slaves); i++ {
+		err := eg.slaves[i].Close()
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Context returned a group session
+func (eg *EngineGroup) Context(ctx context.Context) *Session {
+	sess := eg.NewSession()
+	sess.isAutoClose = true
+	return sess.Context(ctx)
+}
+
+// NewSession returned a group session
+func (eg *EngineGroup) NewSession() *Session {
+	sess := eg.Engine.NewSession()
+	sess.sessionType = groupSession
+	return sess
+}
+
+// Master returns the master engine
+func (eg *EngineGroup) Master() *Engine {
+	return eg.Engine
+}
+
+// Ping tests if database is alive
+func (eg *EngineGroup) Ping() error {
+	if err := eg.Engine.Ping(); err != nil {
+		return err
+	}
+
+	for _, slave := range eg.slaves {
+		if err := slave.Ping(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// SetColumnMapper set the column name mapping rule
+func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
+	eg.Engine.ColumnMapper = mapper
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].ColumnMapper = mapper
+	}
+}
+
+// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
+func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
+	eg.Engine.SetConnMaxLifetime(d)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].SetConnMaxLifetime(d)
+	}
+}
+
+// SetDefaultCacher set the default cacher
+func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
+	eg.Engine.SetDefaultCacher(cacher)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].SetDefaultCacher(cacher)
+	}
+}
+
+// SetLogger set the new logger
+func (eg *EngineGroup) SetLogger(logger core.ILogger) {
+	eg.Engine.SetLogger(logger)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].SetLogger(logger)
+	}
+}
+
+// SetLogLevel sets the logger level
+func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
+	eg.Engine.SetLogLevel(level)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].SetLogLevel(level)
+	}
+}
+
+// SetMapper set the name mapping rules
+func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
+	eg.Engine.SetMapper(mapper)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].SetMapper(mapper)
+	}
+}
+
+// SetMaxIdleConns set the max idle connections on pool, default is 2
+func (eg *EngineGroup) SetMaxIdleConns(conns int) {
+	eg.Engine.db.SetMaxIdleConns(conns)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].db.SetMaxIdleConns(conns)
+	}
+}
+
+// SetMaxOpenConns is only available for go 1.2+
+func (eg *EngineGroup) SetMaxOpenConns(conns int) {
+	eg.Engine.db.SetMaxOpenConns(conns)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].db.SetMaxOpenConns(conns)
+	}
+}
+
+// SetPolicy set the group policy
+func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
+	eg.policy = policy
+	return eg
+}
+
+// SetTableMapper set the table name mapping rule
+func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
+	eg.Engine.TableMapper = mapper
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].TableMapper = mapper
+	}
+}
+
+// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
+func (eg *EngineGroup) ShowExecTime(show ...bool) {
+	eg.Engine.ShowExecTime(show...)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].ShowExecTime(show...)
+	}
+}
+
+// ShowSQL show SQL statement or not on logger if log level is great than INFO
+func (eg *EngineGroup) ShowSQL(show ...bool) {
+	eg.Engine.ShowSQL(show...)
+	for i := 0; i < len(eg.slaves); i++ {
+		eg.slaves[i].ShowSQL(show...)
+	}
+}
+
+// Slave returns one of the physical databases which is a slave according the policy
+func (eg *EngineGroup) Slave() *Engine {
+	switch len(eg.slaves) {
+	case 0:
+		return eg.Engine
+	case 1:
+		return eg.slaves[0]
+	}
+	return eg.policy.Slave(eg)
+}
+
+// Slaves returns all the slaves
+func (eg *EngineGroup) Slaves() []*Engine {
+	return eg.slaves
+}

+ 116 - 0
vendor/gitea.com/xorm/xorm/engine_group_policy.go

@@ -0,0 +1,116 @@
+// 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 (
+	"math/rand"
+	"sync"
+	"time"
+)
+
+// GroupPolicy is be used by chosing the current slave from slaves
+type GroupPolicy interface {
+	Slave(*EngineGroup) *Engine
+}
+
+// GroupPolicyHandler should be used when a function is a GroupPolicy
+type GroupPolicyHandler func(*EngineGroup) *Engine
+
+// Slave implements the chosen of slaves
+func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine {
+	return h(eg)
+}
+
+// RandomPolicy implmentes randomly chose the slave of slaves
+func RandomPolicy() GroupPolicyHandler {
+	var r = rand.New(rand.NewSource(time.Now().UnixNano()))
+	return func(g *EngineGroup) *Engine {
+		return g.Slaves()[r.Intn(len(g.Slaves()))]
+	}
+}
+
+// WeightRandomPolicy implmentes randomly chose the slave of slaves
+func WeightRandomPolicy(weights []int) GroupPolicyHandler {
+	var rands = make([]int, 0, len(weights))
+	for i := 0; i < len(weights); i++ {
+		for n := 0; n < weights[i]; n++ {
+			rands = append(rands, i)
+		}
+	}
+	var r = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+	return func(g *EngineGroup) *Engine {
+		var slaves = g.Slaves()
+		idx := rands[r.Intn(len(rands))]
+		if idx >= len(slaves) {
+			idx = len(slaves) - 1
+		}
+		return slaves[idx]
+	}
+}
+
+func RoundRobinPolicy() GroupPolicyHandler {
+	var pos = -1
+	var lock sync.Mutex
+	return func(g *EngineGroup) *Engine {
+		var slaves = g.Slaves()
+
+		lock.Lock()
+		defer lock.Unlock()
+		pos++
+		if pos >= len(slaves) {
+			pos = 0
+		}
+
+		return slaves[pos]
+	}
+}
+
+func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
+	var rands = make([]int, 0, len(weights))
+	for i := 0; i < len(weights); i++ {
+		for n := 0; n < weights[i]; n++ {
+			rands = append(rands, i)
+		}
+	}
+	var pos = -1
+	var lock sync.Mutex
+
+	return func(g *EngineGroup) *Engine {
+		var slaves = g.Slaves()
+		lock.Lock()
+		defer lock.Unlock()
+		pos++
+		if pos >= len(rands) {
+			pos = 0
+		}
+
+		idx := rands[pos]
+		if idx >= len(slaves) {
+			idx = len(slaves) - 1
+		}
+		return slaves[idx]
+	}
+}
+
+// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
+func LeastConnPolicy() GroupPolicyHandler {
+	return func(g *EngineGroup) *Engine {
+		var slaves = g.Slaves()
+		connections := 0
+		idx := 0
+		for i := 0; i < len(slaves); i++ {
+			openConnections := slaves[i].DB().Stats().OpenConnections
+			if i == 0 {
+				connections = openConnections
+				idx = i
+			} else if openConnections <= connections {
+				connections = openConnections
+				idx = i
+			}
+		}
+		return slaves[idx]
+	}
+}

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

@@ -0,0 +1,113 @@
+// Copyright 2018 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+
+	"xorm.io/core"
+)
+
+// tbNameWithSchema will automatically add schema prefix on table name
+func (engine *Engine) tbNameWithSchema(v string) string {
+	// Add schema name as prefix of table name.
+	// Only for postgres database.
+	if engine.dialect.DBType() == core.POSTGRES &&
+		engine.dialect.URI().Schema != "" &&
+		engine.dialect.URI().Schema != postgresPublicSchema &&
+		strings.Index(v, ".") == -1 {
+		return engine.dialect.URI().Schema + "." + v
+	}
+	return v
+}
+
+// TableName returns table name with schema prefix if has
+func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
+	tbName := engine.tbNameNoSchema(bean)
+	if len(includeSchema) > 0 && includeSchema[0] {
+		tbName = engine.tbNameWithSchema(tbName)
+	}
+
+	return tbName
+}
+
+// tbName get some table's table name
+func (session *Session) tbNameNoSchema(table *core.Table) string {
+	if len(session.statement.AltTableName) > 0 {
+		return session.statement.AltTableName
+	}
+
+	return table.Name
+}
+
+func (engine *Engine) tbNameForMap(v reflect.Value) string {
+	if v.Type().Implements(tpTableName) {
+		return v.Interface().(TableName).TableName()
+	}
+	if v.Kind() == reflect.Ptr {
+		v = v.Elem()
+		if v.Type().Implements(tpTableName) {
+			return v.Interface().(TableName).TableName()
+		}
+	}
+
+	return engine.TableMapper.Obj2Table(v.Type().Name())
+}
+
+func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
+	switch tablename.(type) {
+	case []string:
+		t := tablename.([]string)
+		if len(t) > 1 {
+			return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
+		} else if len(t) == 1 {
+			return engine.Quote(t[0])
+		}
+	case []interface{}:
+		t := tablename.([]interface{})
+		l := len(t)
+		var table string
+		if l > 0 {
+			f := t[0]
+			switch f.(type) {
+			case string:
+				table = f.(string)
+			case TableName:
+				table = f.(TableName).TableName()
+			default:
+				v := rValue(f)
+				t := v.Type()
+				if t.Kind() == reflect.Struct {
+					table = engine.tbNameForMap(v)
+				} else {
+					table = engine.Quote(fmt.Sprintf("%v", f))
+				}
+			}
+		}
+		if l > 1 {
+			return fmt.Sprintf("%v AS %v", engine.Quote(table),
+				engine.Quote(fmt.Sprintf("%v", t[1])))
+		} else if l == 1 {
+			return engine.Quote(table)
+		}
+	case TableName:
+		return tablename.(TableName).TableName()
+	case string:
+		return tablename.(string)
+	case reflect.Value:
+		v := tablename.(reflect.Value)
+		return engine.tbNameForMap(v)
+	default:
+		v := rValue(tablename)
+		t := v.Type()
+		if t.Kind() == reflect.Struct {
+			return engine.tbNameForMap(v)
+		}
+		return engine.Quote(fmt.Sprintf("%v", tablename))
+	}
+	return ""
+}

+ 51 - 0
vendor/gitea.com/xorm/xorm/error.go

@@ -0,0 +1,51 @@
+// 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"
+)
+
+var (
+	// ErrParamsType params error
+	ErrParamsType = errors.New("Params type error")
+	// ErrTableNotFound table not found error
+	ErrTableNotFound = errors.New("Table not found")
+	// ErrUnSupportedType unsupported error
+	ErrUnSupportedType = errors.New("Unsupported type error")
+	// ErrNotExist record does not exist error
+	ErrNotExist = errors.New("Record does not exist")
+	// ErrCacheFailed cache failed error
+	ErrCacheFailed = errors.New("Cache failed")
+	// ErrNeedDeletedCond delete needs less one condition error
+	ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
+	// ErrNotImplemented not implemented
+	ErrNotImplemented = errors.New("Not implemented")
+	// ErrConditionType condition type unsupported
+	ErrConditionType = errors.New("Unsupported condition type")
+	// ErrUnSupportedSQLType parameter of SQL is not supported
+	ErrUnSupportedSQLType = errors.New("unsupported sql type")
+)
+
+// ErrFieldIsNotExist columns does not exist
+type ErrFieldIsNotExist struct {
+	FieldName string
+	TableName string
+}
+
+func (e ErrFieldIsNotExist) Error() string {
+	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
+}
+
+// ErrFieldIsNotValid is not valid
+type ErrFieldIsNotValid struct {
+	FieldName string
+	TableName string
+}
+
+func (e ErrFieldIsNotValid) Error() string {
+	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
+}

+ 6 - 0
vendor/gitea.com/xorm/xorm/gen_reserved.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+if [ -f $1 ];then
+    cat $1| awk '{printf("\""$1"\":true,\n")}' 
+else
+    echo "argument $1 if not a file!"
+fi

+ 19 - 0
vendor/gitea.com/xorm/xorm/go.mod

@@ -0,0 +1,19 @@
+module github.com/go-xorm/xorm
+
+require (
+	github.com/cockroachdb/apd v1.1.0 // indirect
+	github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
+	github.com/go-sql-driver/mysql v1.4.1
+	github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
+	github.com/jackc/pgx v3.3.0+incompatible
+	github.com/kr/pretty v0.1.0 // indirect
+	github.com/lib/pq v1.0.0
+	github.com/mattn/go-sqlite3 v1.10.0
+	github.com/pkg/errors v0.8.1 // indirect
+	github.com/satori/go.uuid v1.2.0 // indirect
+	github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
+	github.com/stretchr/testify v1.3.0
+	github.com/ziutek/mymysql v1.5.4
+	xorm.io/builder v0.3.5
+	xorm.io/core v0.6.3
+)

+ 159 - 0
vendor/gitea.com/xorm/xorm/go.sum

@@ -0,0 +1,159 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
+cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
+github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
+github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
+github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90=
+github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
+github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
+xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
+xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M=
+xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo=

+ 311 - 0
vendor/gitea.com/xorm/xorm/helpers.go

@@ -0,0 +1,311 @@
+// 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"
+	"reflect"
+	"sort"
+	"strconv"
+	"strings"
+
+	"xorm.io/core"
+)
+
+// str2PK convert string value to primary key value according to tp
+func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
+	var err error
+	var result interface{}
+	var defReturn = reflect.Zero(tp)
+
+	switch tp.Kind() {
+	case reflect.Int:
+		result, err = strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
+		}
+	case reflect.Int8:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
+		}
+		result = int8(x)
+	case reflect.Int16:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
+		}
+		result = int16(x)
+	case reflect.Int32:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
+		}
+		result = int32(x)
+	case reflect.Int64:
+		result, err = strconv.ParseInt(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
+		}
+	case reflect.Uint:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
+		}
+		result = uint(x)
+	case reflect.Uint8:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
+		}
+		result = uint8(x)
+	case reflect.Uint16:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
+		}
+		result = uint16(x)
+	case reflect.Uint32:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
+		}
+		result = uint32(x)
+	case reflect.Uint64:
+		result, err = strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
+		}
+	case reflect.String:
+		result = s
+	default:
+		return defReturn, errors.New("unsupported convert type")
+	}
+	return reflect.ValueOf(result).Convert(tp), nil
+}
+
+func str2PK(s string, tp reflect.Type) (interface{}, error) {
+	v, err := str2PKValue(s, tp)
+	if err != nil {
+		return nil, err
+	}
+	return v.Interface(), nil
+}
+
+func splitTag(tag string) (tags []string) {
+	tag = strings.TrimSpace(tag)
+	var hasQuote = false
+	var lastIdx = 0
+	for i, t := range tag {
+		if t == '\'' {
+			hasQuote = !hasQuote
+		} else if t == ' ' {
+			if lastIdx < i && !hasQuote {
+				tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
+				lastIdx = i + 1
+			}
+		}
+	}
+	if lastIdx < len(tag) {
+		tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
+	}
+	return
+}
+
+type zeroable interface {
+	IsZero() bool
+}
+
+func isZero(k interface{}) bool {
+	switch k.(type) {
+	case int:
+		return k.(int) == 0
+	case int8:
+		return k.(int8) == 0
+	case int16:
+		return k.(int16) == 0
+	case int32:
+		return k.(int32) == 0
+	case int64:
+		return k.(int64) == 0
+	case uint:
+		return k.(uint) == 0
+	case uint8:
+		return k.(uint8) == 0
+	case uint16:
+		return k.(uint16) == 0
+	case uint32:
+		return k.(uint32) == 0
+	case uint64:
+		return k.(uint64) == 0
+	case float32:
+		return k.(float32) == 0
+	case float64:
+		return k.(float64) == 0
+	case bool:
+		return k.(bool) == false
+	case string:
+		return k.(string) == ""
+	case zeroable:
+		return k.(zeroable).IsZero()
+	}
+	return false
+}
+
+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{}
+	kind := tp.Kind()
+
+	if kind == reflect.Ptr {
+		kind = tp.Elem().Kind()
+	}
+
+	switch kind {
+	case reflect.Int16:
+		temp := int16(id)
+		v = &temp
+	case reflect.Int32:
+		temp := int32(id)
+		v = &temp
+	case reflect.Int:
+		temp := int(id)
+		v = &temp
+	case reflect.Int64:
+		temp := id
+		v = &temp
+	case reflect.Uint16:
+		temp := uint16(id)
+		v = &temp
+	case reflect.Uint32:
+		temp := uint32(id)
+		v = &temp
+	case reflect.Uint64:
+		temp := uint64(id)
+		v = &temp
+	case reflect.Uint:
+		temp := uint(id)
+		v = &temp
+	}
+
+	if tp.Kind() == reflect.Ptr {
+		return reflect.ValueOf(v).Convert(tp)
+	}
+	return reflect.ValueOf(v).Elem().Convert(tp)
+}
+
+func int64ToInt(id int64, tp reflect.Type) interface{} {
+	return int64ToIntValue(id, tp).Interface()
+}
+
+func isPKZero(pk core.PK) bool {
+	for _, k := range pk {
+		if isZero(k) {
+			return true
+		}
+	}
+	return false
+}
+
+func indexNoCase(s, sep string) int {
+	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
+}
+
+func splitNoCase(s, sep string) []string {
+	idx := indexNoCase(s, sep)
+	if idx < 0 {
+		return []string{s}
+	}
+	return strings.Split(s, s[idx:idx+len(sep)])
+}
+
+func splitNNoCase(s, sep string, n int) []string {
+	idx := indexNoCase(s, sep)
+	if idx < 0 {
+		return []string{s}
+	}
+	return strings.SplitN(s, s[idx:idx+len(sep)], n)
+}
+
+func makeArray(elem string, count int) []string {
+	res := make([]string, count)
+	for i := 0; i < count; i++ {
+		res[i] = elem
+	}
+	return res
+}
+
+func rValue(bean interface{}) reflect.Value {
+	return reflect.Indirect(reflect.ValueOf(bean))
+}
+
+func rType(bean interface{}) reflect.Type {
+	sliceValue := reflect.Indirect(reflect.ValueOf(bean))
+	//return reflect.TypeOf(sliceValue.Interface())
+	return sliceValue.Type()
+}
+
+func structName(v reflect.Type) string {
+	for v.Kind() == reflect.Ptr {
+		v = v.Elem()
+	}
+	return v.Name()
+}
+
+func sliceEq(left, right []string) bool {
+	if len(left) != len(right) {
+		return false
+	}
+	sort.Sort(sort.StringSlice(left))
+	sort.Sort(sort.StringSlice(right))
+	for i := 0; i < len(left); i++ {
+		if left[i] != right[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func indexName(tableName, idxName string) string {
+	return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
+}

+ 21 - 0
vendor/gitea.com/xorm/xorm/helpler_time.go

@@ -0,0 +1,21 @@
+// 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 "time"
+
+const (
+	zeroTime0 = "0000-00-00 00:00:00"
+	zeroTime1 = "0001-01-01 00:00:00"
+)
+
+func formatTime(t time.Time) string {
+	return t.Format("2006-01-02 15:04:05")
+}
+
+func isTimeZero(t time.Time) bool {
+	return t.IsZero() || formatTime(t) == zeroTime0 ||
+		formatTime(t) == zeroTime1
+}

+ 118 - 0
vendor/gitea.com/xorm/xorm/interface.go

@@ -0,0 +1,118 @@
+// 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 (
+	"context"
+	"database/sql"
+	"reflect"
+	"time"
+
+	"xorm.io/core"
+)
+
+// Interface defines the interface which Engine, EngineGroup and Session will implementate.
+type Interface interface {
+	AllCols() *Session
+	Alias(alias string) *Session
+	Asc(colNames ...string) *Session
+	BufferSize(size int) *Session
+	Cols(columns ...string) *Session
+	Count(...interface{}) (int64, error)
+	CreateIndexes(bean interface{}) error
+	CreateUniques(bean interface{}) error
+	Decr(column string, arg ...interface{}) *Session
+	Desc(...string) *Session
+	Delete(interface{}) (int64, error)
+	Distinct(columns ...string) *Session
+	DropIndexes(bean interface{}) error
+	Exec(sqlOrArgs ...interface{}) (sql.Result, error)
+	Exist(bean ...interface{}) (bool, error)
+	Find(interface{}, ...interface{}) error
+	FindAndCount(interface{}, ...interface{}) (int64, error)
+	Get(interface{}) (bool, error)
+	GroupBy(keys string) *Session
+	ID(interface{}) *Session
+	In(string, ...interface{}) *Session
+	Incr(column string, arg ...interface{}) *Session
+	Insert(...interface{}) (int64, error)
+	InsertOne(interface{}) (int64, error)
+	IsTableEmpty(bean interface{}) (bool, error)
+	IsTableExist(beanOrTableName interface{}) (bool, error)
+	Iterate(interface{}, IterFunc) error
+	Limit(int, ...int) *Session
+	MustCols(columns ...string) *Session
+	NoAutoCondition(...bool) *Session
+	NotIn(string, ...interface{}) *Session
+	Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
+	Omit(columns ...string) *Session
+	OrderBy(order string) *Session
+	Ping() error
+	Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error)
+	QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error)
+	QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error)
+	Rows(bean interface{}) (*Rows, error)
+	SetExpr(string, string) *Session
+	SQL(interface{}, ...interface{}) *Session
+	Sum(bean interface{}, colName string) (float64, error)
+	SumInt(bean interface{}, colName string) (int64, error)
+	Sums(bean interface{}, colNames ...string) ([]float64, error)
+	SumsInt(bean interface{}, colNames ...string) ([]int64, error)
+	Table(tableNameOrBean interface{}) *Session
+	Unscoped() *Session
+	Update(bean interface{}, condiBeans ...interface{}) (int64, error)
+	UseBool(...string) *Session
+	Where(interface{}, ...interface{}) *Session
+}
+
+// EngineInterface defines the interface which Engine, EngineGroup will implementate.
+type EngineInterface interface {
+	Interface
+
+	Before(func(interface{})) *Session
+	Charset(charset string) *Session
+	ClearCache(...interface{}) error
+	Context(context.Context) *Session
+	CreateTables(...interface{}) error
+	DBMetas() ([]*core.Table, error)
+	Dialect() core.Dialect
+	DropTables(...interface{}) error
+	DumpAllToFile(fp string, tp ...core.DbType) error
+	GetCacher(string) core.Cacher
+	GetColumnMapper() core.IMapper
+	GetDefaultCacher() core.Cacher
+	GetTableMapper() core.IMapper
+	GetTZDatabase() *time.Location
+	GetTZLocation() *time.Location
+	MapCacher(interface{}, core.Cacher) error
+	NewSession() *Session
+	NoAutoTime() *Session
+	Quote(string) string
+	SetCacher(string, core.Cacher)
+	SetConnMaxLifetime(time.Duration)
+	SetDefaultCacher(core.Cacher)
+	SetLogger(logger core.ILogger)
+	SetLogLevel(core.LogLevel)
+	SetMapper(core.IMapper)
+	SetMaxOpenConns(int)
+	SetMaxIdleConns(int)
+	SetSchema(string)
+	SetTZDatabase(tz *time.Location)
+	SetTZLocation(tz *time.Location)
+	ShowExecTime(...bool)
+	ShowSQL(show ...bool)
+	Sync(...interface{}) error
+	Sync2(...interface{}) error
+	StoreEngine(storeEngine string) *Session
+	TableInfo(bean interface{}) *Table
+	TableName(interface{}, ...bool) string
+	UnMapType(reflect.Type)
+}
+
+var (
+	_ Interface       = &Session{}
+	_ EngineInterface = &Engine{}
+	_ EngineInterface = &EngineGroup{}
+)

+ 31 - 0
vendor/gitea.com/xorm/xorm/json.go

@@ -0,0 +1,31 @@
+// Copyright 2019 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 "encoding/json"
+
+// JSONInterface represents an interface to handle json data
+type JSONInterface interface {
+	Marshal(v interface{}) ([]byte, error)
+	Unmarshal(data []byte, v interface{}) error
+}
+
+var (
+	// DefaultJSONHandler default json handler
+	DefaultJSONHandler JSONInterface = StdJSON{}
+)
+
+// StdJSON implements JSONInterface via encoding/json
+type StdJSON struct{}
+
+// Marshal implements JSONInterface
+func (StdJSON) Marshal(v interface{}) ([]byte, error) {
+	return json.Marshal(v)
+}
+
+// Unmarshal implements JSONInterface
+func (StdJSON) Unmarshal(data []byte, v interface{}) error {
+	return json.Unmarshal(data, v)
+}

+ 187 - 0
vendor/gitea.com/xorm/xorm/logger.go

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

+ 746 - 0
vendor/gitea.com/xorm/xorm/pg_reserved.txt

@@ -0,0 +1,746 @@
+A	 	non-reserved	non-reserved	 
+ABORT	non-reserved	 	 	 
+ABS	 	reserved	reserved	 
+ABSENT	 	non-reserved	non-reserved	 
+ABSOLUTE	non-reserved	non-reserved	non-reserved	reserved
+ACCESS	non-reserved	 	 	 
+ACCORDING	 	non-reserved	non-reserved	 
+ACTION	non-reserved	non-reserved	non-reserved	reserved
+ADA	 	non-reserved	non-reserved	non-reserved
+ADD	non-reserved	non-reserved	non-reserved	reserved
+ADMIN	non-reserved	non-reserved	non-reserved	 
+AFTER	non-reserved	non-reserved	non-reserved	 
+AGGREGATE	non-reserved	 	 	 
+ALL	reserved	reserved	reserved	reserved
+ALLOCATE	 	reserved	reserved	reserved
+ALSO	non-reserved	 	 	 
+ALTER	non-reserved	reserved	reserved	reserved
+ALWAYS	non-reserved	non-reserved	non-reserved	 
+ANALYSE	reserved	 	 	 
+ANALYZE	reserved	 	 	 
+AND	reserved	reserved	reserved	reserved
+ANY	reserved	reserved	reserved	reserved
+ARE	 	reserved	reserved	reserved
+ARRAY	reserved	reserved	reserved	 
+ARRAY_AGG	 	reserved	reserved	 
+ARRAY_MAX_CARDINALITY	 	reserved	 	 
+AS	reserved	reserved	reserved	reserved
+ASC	reserved	non-reserved	non-reserved	reserved
+ASENSITIVE	 	reserved	reserved	 
+ASSERTION	non-reserved	non-reserved	non-reserved	reserved
+ASSIGNMENT	non-reserved	non-reserved	non-reserved	 
+ASYMMETRIC	reserved	reserved	reserved	 
+AT	non-reserved	reserved	reserved	reserved
+ATOMIC	 	reserved	reserved	 
+ATTRIBUTE	non-reserved	non-reserved	non-reserved	 
+ATTRIBUTES	 	non-reserved	non-reserved	 
+AUTHORIZATION	reserved (can be function or type)	reserved	reserved	reserved
+AVG	 	reserved	reserved	reserved
+BACKWARD	non-reserved	 	 	 
+BASE64	 	non-reserved	non-reserved	 
+BEFORE	non-reserved	non-reserved	non-reserved	 
+BEGIN	non-reserved	reserved	reserved	reserved
+BEGIN_FRAME	 	reserved	 	 
+BEGIN_PARTITION	 	reserved	 	 
+BERNOULLI	 	non-reserved	non-reserved	 
+BETWEEN	non-reserved (cannot be function or type)	reserved	reserved	reserved
+BIGINT	non-reserved (cannot be function or type)	reserved	reserved	 
+BINARY	reserved (can be function or type)	reserved	reserved	 
+BIT	non-reserved (cannot be function or type)	 	 	reserved
+BIT_LENGTH	 	 	 	reserved
+BLOB	 	reserved	reserved	 
+BLOCKED	 	non-reserved	non-reserved	 
+BOM	 	non-reserved	non-reserved	 
+BOOLEAN	non-reserved (cannot be function or type)	reserved	reserved	 
+BOTH	reserved	reserved	reserved	reserved
+BREADTH	 	non-reserved	non-reserved	 
+BY	non-reserved	reserved	reserved	reserved
+C	 	non-reserved	non-reserved	non-reserved
+CACHE	non-reserved	 	 	 
+CALL	 	reserved	reserved	 
+CALLED	non-reserved	reserved	reserved	 
+CARDINALITY	 	reserved	reserved	 
+CASCADE	non-reserved	non-reserved	non-reserved	reserved
+CASCADED	non-reserved	reserved	reserved	reserved
+CASE	reserved	reserved	reserved	reserved
+CAST	reserved	reserved	reserved	reserved
+CATALOG	non-reserved	non-reserved	non-reserved	reserved
+CATALOG_NAME	 	non-reserved	non-reserved	non-reserved
+CEIL	 	reserved	reserved	 
+CEILING	 	reserved	reserved	 
+CHAIN	non-reserved	non-reserved	non-reserved	 
+CHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+CHARACTER	non-reserved (cannot be function or type)	reserved	reserved	reserved
+CHARACTERISTICS	non-reserved	non-reserved	non-reserved	 
+CHARACTERS	 	non-reserved	non-reserved	 
+CHARACTER_LENGTH	 	reserved	reserved	reserved
+CHARACTER_SET_CATALOG	 	non-reserved	non-reserved	non-reserved
+CHARACTER_SET_NAME	 	non-reserved	non-reserved	non-reserved
+CHARACTER_SET_SCHEMA	 	non-reserved	non-reserved	non-reserved
+CHAR_LENGTH	 	reserved	reserved	reserved
+CHECK	reserved	reserved	reserved	reserved
+CHECKPOINT	non-reserved	 	 	 
+CLASS	non-reserved	 	 	 
+CLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
+CLOB	 	reserved	reserved	 
+CLOSE	non-reserved	reserved	reserved	reserved
+CLUSTER	non-reserved	 	 	 
+COALESCE	non-reserved (cannot be function or type)	reserved	reserved	reserved
+COBOL	 	non-reserved	non-reserved	non-reserved
+COLLATE	reserved	reserved	reserved	reserved
+COLLATION	reserved (can be function or type)	non-reserved	non-reserved	reserved
+COLLATION_CATALOG	 	non-reserved	non-reserved	non-reserved
+COLLATION_NAME	 	non-reserved	non-reserved	non-reserved
+COLLATION_SCHEMA	 	non-reserved	non-reserved	non-reserved
+COLLECT	 	reserved	reserved	 
+COLUMN	reserved	reserved	reserved	reserved
+COLUMNS	 	non-reserved	non-reserved	 
+COLUMN_NAME	 	non-reserved	non-reserved	non-reserved
+COMMAND_FUNCTION	 	non-reserved	non-reserved	non-reserved
+COMMAND_FUNCTION_CODE	 	non-reserved	non-reserved	 
+COMMENT	non-reserved	 	 	 
+COMMENTS	non-reserved	 	 	 
+COMMIT	non-reserved	reserved	reserved	reserved
+COMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
+CONCURRENTLY	reserved (can be function or type)	 	 	 
+CONDITION	 	reserved	reserved	 
+CONDITION_NUMBER	 	non-reserved	non-reserved	non-reserved
+CONFIGURATION	non-reserved	 	 	 
+CONNECT	 	reserved	reserved	reserved
+CONNECTION	non-reserved	non-reserved	non-reserved	reserved
+CONNECTION_NAME	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT	reserved	reserved	reserved	reserved
+CONSTRAINTS	non-reserved	non-reserved	non-reserved	reserved
+CONSTRAINT_CATALOG	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT_NAME	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT_SCHEMA	 	non-reserved	non-reserved	non-reserved
+CONSTRUCTOR	 	non-reserved	non-reserved	 
+CONTAINS	 	reserved	non-reserved	 
+CONTENT	non-reserved	non-reserved	non-reserved	 
+CONTINUE	non-reserved	non-reserved	non-reserved	reserved
+CONTROL	 	non-reserved	non-reserved	 
+CONVERSION	non-reserved	 	 	 
+CONVERT	 	reserved	reserved	reserved
+COPY	non-reserved	 	 	 
+CORR	 	reserved	reserved	 
+CORRESPONDING	 	reserved	reserved	reserved
+COST	non-reserved	 	 	 
+COUNT	 	reserved	reserved	reserved
+COVAR_POP	 	reserved	reserved	 
+COVAR_SAMP	 	reserved	reserved	 
+CREATE	reserved	reserved	reserved	reserved
+CROSS	reserved (can be function or type)	reserved	reserved	reserved
+CSV	non-reserved	 	 	 
+CUBE	 	reserved	reserved	 
+CUME_DIST	 	reserved	reserved	 
+CURRENT	non-reserved	reserved	reserved	reserved
+CURRENT_CATALOG	reserved	reserved	reserved	 
+CURRENT_DATE	reserved	reserved	reserved	reserved
+CURRENT_DEFAULT_TRANSFORM_GROUP	 	reserved	reserved	 
+CURRENT_PATH	 	reserved	reserved	 
+CURRENT_ROLE	reserved	reserved	reserved	 
+CURRENT_ROW	 	reserved	 	 
+CURRENT_SCHEMA	reserved (can be function or type)	reserved	reserved	 
+CURRENT_TIME	reserved	reserved	reserved	reserved
+CURRENT_TIMESTAMP	reserved	reserved	reserved	reserved
+CURRENT_TRANSFORM_GROUP_FOR_TYPE	 	reserved	reserved	 
+CURRENT_USER	reserved	reserved	reserved	reserved
+CURSOR	non-reserved	reserved	reserved	reserved
+CURSOR_NAME	 	non-reserved	non-reserved	non-reserved
+CYCLE	non-reserved	reserved	reserved	 
+DATA	non-reserved	non-reserved	non-reserved	non-reserved
+DATABASE	non-reserved	 	 	 
+DATALINK	 	reserved	reserved	 
+DATE	 	reserved	reserved	reserved
+DATETIME_INTERVAL_CODE	 	non-reserved	non-reserved	non-reserved
+DATETIME_INTERVAL_PRECISION	 	non-reserved	non-reserved	non-reserved
+DAY	non-reserved	reserved	reserved	reserved
+DB	 	non-reserved	non-reserved	 
+DEALLOCATE	non-reserved	reserved	reserved	reserved
+DEC	non-reserved (cannot be function or type)	reserved	reserved	reserved
+DECIMAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+DECLARE	non-reserved	reserved	reserved	reserved
+DEFAULT	reserved	reserved	reserved	reserved
+DEFAULTS	non-reserved	non-reserved	non-reserved	 
+DEFERRABLE	reserved	non-reserved	non-reserved	reserved
+DEFERRED	non-reserved	non-reserved	non-reserved	reserved
+DEFINED	 	non-reserved	non-reserved	 
+DEFINER	non-reserved	non-reserved	non-reserved	 
+DEGREE	 	non-reserved	non-reserved	 
+DELETE	non-reserved	reserved	reserved	reserved
+DELIMITER	non-reserved	 	 	 
+DELIMITERS	non-reserved	 	 	 
+DENSE_RANK	 	reserved	reserved	 
+DEPTH	 	non-reserved	non-reserved	 
+DEREF	 	reserved	reserved	 
+DERIVED	 	non-reserved	non-reserved	 
+DESC	reserved	non-reserved	non-reserved	reserved
+DESCRIBE	 	reserved	reserved	reserved
+DESCRIPTOR	 	non-reserved	non-reserved	reserved
+DETERMINISTIC	 	reserved	reserved	 
+DIAGNOSTICS	 	non-reserved	non-reserved	reserved
+DICTIONARY	non-reserved	 	 	 
+DISABLE	non-reserved	 	 	 
+DISCARD	non-reserved	 	 	 
+DISCONNECT	 	reserved	reserved	reserved
+DISPATCH	 	non-reserved	non-reserved	 
+DISTINCT	reserved	reserved	reserved	reserved
+DLNEWCOPY	 	reserved	reserved	 
+DLPREVIOUSCOPY	 	reserved	reserved	 
+DLURLCOMPLETE	 	reserved	reserved	 
+DLURLCOMPLETEONLY	 	reserved	reserved	 
+DLURLCOMPLETEWRITE	 	reserved	reserved	 
+DLURLPATH	 	reserved	reserved	 
+DLURLPATHONLY	 	reserved	reserved	 
+DLURLPATHWRITE	 	reserved	reserved	 
+DLURLSCHEME	 	reserved	reserved	 
+DLURLSERVER	 	reserved	reserved	 
+DLVALUE	 	reserved	reserved	 
+DO	reserved	 	 	 
+DOCUMENT	non-reserved	non-reserved	non-reserved	 
+DOMAIN	non-reserved	non-reserved	non-reserved	reserved
+DOUBLE	non-reserved	reserved	reserved	reserved
+DROP	non-reserved	reserved	reserved	reserved
+DYNAMIC	 	reserved	reserved	 
+DYNAMIC_FUNCTION	 	non-reserved	non-reserved	non-reserved
+DYNAMIC_FUNCTION_CODE	 	non-reserved	non-reserved	 
+EACH	non-reserved	reserved	reserved	 
+ELEMENT	 	reserved	reserved	 
+ELSE	reserved	reserved	reserved	reserved
+EMPTY	 	non-reserved	non-reserved	 
+ENABLE	non-reserved	 	 	 
+ENCODING	non-reserved	non-reserved	non-reserved	 
+ENCRYPTED	non-reserved	 	 	 
+END	reserved	reserved	reserved	reserved
+END-EXEC	 	reserved	reserved	reserved
+END_FRAME	 	reserved	 	 
+END_PARTITION	 	reserved	 	 
+ENFORCED	 	non-reserved	 	 
+ENUM	non-reserved	 	 	 
+EQUALS	 	reserved	non-reserved	 
+ESCAPE	non-reserved	reserved	reserved	reserved
+EVENT	non-reserved	 	 	 
+EVERY	 	reserved	reserved	 
+EXCEPT	reserved	reserved	reserved	reserved
+EXCEPTION	 	 	 	reserved
+EXCLUDE	non-reserved	non-reserved	non-reserved	 
+EXCLUDING	non-reserved	non-reserved	non-reserved	 
+EXCLUSIVE	non-reserved	 	 	 
+EXEC	 	reserved	reserved	reserved
+EXECUTE	non-reserved	reserved	reserved	reserved
+EXISTS	non-reserved (cannot be function or type)	reserved	reserved	reserved
+EXP	 	reserved	reserved	 
+EXPLAIN	non-reserved	 	 	 
+EXPRESSION	 	non-reserved	 	 
+EXTENSION	non-reserved	 	 	 
+EXTERNAL	non-reserved	reserved	reserved	reserved
+EXTRACT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+FALSE	reserved	reserved	reserved	reserved
+FAMILY	non-reserved	 	 	 
+FETCH	reserved	reserved	reserved	reserved
+FILE	 	non-reserved	non-reserved	 
+FILTER	 	reserved	reserved	 
+FINAL	 	non-reserved	non-reserved	 
+FIRST	non-reserved	non-reserved	non-reserved	reserved
+FIRST_VALUE	 	reserved	reserved	 
+FLAG	 	non-reserved	non-reserved	 
+FLOAT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+FLOOR	 	reserved	reserved	 
+FOLLOWING	non-reserved	non-reserved	non-reserved	 
+FOR	reserved	reserved	reserved	reserved
+FORCE	non-reserved	 	 	 
+FOREIGN	reserved	reserved	reserved	reserved
+FORTRAN	 	non-reserved	non-reserved	non-reserved
+FORWARD	non-reserved	 	 	 
+FOUND	 	non-reserved	non-reserved	reserved
+FRAME_ROW	 	reserved	 	 
+FREE	 	reserved	reserved	 
+FREEZE	reserved (can be function or type)	 	 	 
+FROM	reserved	reserved	reserved	reserved
+FS	 	non-reserved	non-reserved	 
+FULL	reserved (can be function or type)	reserved	reserved	reserved
+FUNCTION	non-reserved	reserved	reserved	 
+FUNCTIONS	non-reserved	 	 	 
+FUSION	 	reserved	reserved	 
+G	 	non-reserved	non-reserved	 
+GENERAL	 	non-reserved	non-reserved	 
+GENERATED	 	non-reserved	non-reserved	 
+GET	 	reserved	reserved	reserved
+GLOBAL	non-reserved	reserved	reserved	reserved
+GO	 	non-reserved	non-reserved	reserved
+GOTO	 	non-reserved	non-reserved	reserved
+GRANT	reserved	reserved	reserved	reserved
+GRANTED	non-reserved	non-reserved	non-reserved	 
+GREATEST	non-reserved (cannot be function or type)	 	 	 
+GROUP	reserved	reserved	reserved	reserved
+GROUPING	 	reserved	reserved	 
+GROUPS	 	reserved	 	 
+HANDLER	non-reserved	 	 	 
+HAVING	reserved	reserved	reserved	reserved
+HEADER	non-reserved	 	 	 
+HEX	 	non-reserved	non-reserved	 
+HIERARCHY	 	non-reserved	non-reserved	 
+HOLD	non-reserved	reserved	reserved	 
+HOUR	non-reserved	reserved	reserved	reserved
+ID	 	non-reserved	non-reserved	 
+IDENTITY	non-reserved	reserved	reserved	reserved
+IF	non-reserved	 	 	 
+IGNORE	 	non-reserved	non-reserved	 
+ILIKE	reserved (can be function or type)	 	 	 
+IMMEDIATE	non-reserved	non-reserved	non-reserved	reserved
+IMMEDIATELY	 	non-reserved	 	 
+IMMUTABLE	non-reserved	 	 	 
+IMPLEMENTATION	 	non-reserved	non-reserved	 
+IMPLICIT	non-reserved	 	 	 
+IMPORT	 	reserved	reserved	 
+IN	reserved	reserved	reserved	reserved
+INCLUDING	non-reserved	non-reserved	non-reserved	 
+INCREMENT	non-reserved	non-reserved	non-reserved	 
+INDENT	 	non-reserved	non-reserved	 
+INDEX	non-reserved	 	 	 
+INDEXES	non-reserved	 	 	 
+INDICATOR	 	reserved	reserved	reserved
+INHERIT	non-reserved	 	 	 
+INHERITS	non-reserved	 	 	 
+INITIALLY	reserved	non-reserved	non-reserved	reserved
+INLINE	non-reserved	 	 	 
+INNER	reserved (can be function or type)	reserved	reserved	reserved
+INOUT	non-reserved (cannot be function or type)	reserved	reserved	 
+INPUT	non-reserved	non-reserved	non-reserved	reserved
+INSENSITIVE	non-reserved	reserved	reserved	reserved
+INSERT	non-reserved	reserved	reserved	reserved
+INSTANCE	 	non-reserved	non-reserved	 
+INSTANTIABLE	 	non-reserved	non-reserved	 
+INSTEAD	non-reserved	non-reserved	non-reserved	 
+INT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTEGER	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTEGRITY	 	non-reserved	non-reserved	 
+INTERSECT	reserved	reserved	reserved	reserved
+INTERSECTION	 	reserved	reserved	 
+INTERVAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTO	reserved	reserved	reserved	reserved
+INVOKER	non-reserved	non-reserved	non-reserved	 
+IS	reserved (can be function or type)	reserved	reserved	reserved
+ISNULL	reserved (can be function or type)	 	 	 
+ISOLATION	non-reserved	non-reserved	non-reserved	reserved
+JOIN	reserved (can be function or type)	reserved	reserved	reserved
+K	 	non-reserved	non-reserved	 
+KEY	non-reserved	non-reserved	non-reserved	reserved
+KEY_MEMBER	 	non-reserved	non-reserved	 
+KEY_TYPE	 	non-reserved	non-reserved	 
+LABEL	non-reserved	 	 	 
+LAG	 	reserved	reserved	 
+LANGUAGE	non-reserved	reserved	reserved	reserved
+LARGE	non-reserved	reserved	reserved	 
+LAST	non-reserved	non-reserved	non-reserved	reserved
+LAST_VALUE	 	reserved	reserved	 
+LATERAL	reserved	reserved	reserved	 
+LC_COLLATE	non-reserved	 	 	 
+LC_CTYPE	non-reserved	 	 	 
+LEAD	 	reserved	reserved	 
+LEADING	reserved	reserved	reserved	reserved
+LEAKPROOF	non-reserved	 	 	 
+LEAST	non-reserved (cannot be function or type)	 	 	 
+LEFT	reserved (can be function or type)	reserved	reserved	reserved
+LENGTH	 	non-reserved	non-reserved	non-reserved
+LEVEL	non-reserved	non-reserved	non-reserved	reserved
+LIBRARY	 	non-reserved	non-reserved	 
+LIKE	reserved (can be function or type)	reserved	reserved	reserved
+LIKE_REGEX	 	reserved	reserved	 
+LIMIT	reserved	non-reserved	non-reserved	 
+LINK	 	non-reserved	non-reserved	 
+LISTEN	non-reserved	 	 	 
+LN	 	reserved	reserved	 
+LOAD	non-reserved	 	 	 
+LOCAL	non-reserved	reserved	reserved	reserved
+LOCALTIME	reserved	reserved	reserved	 
+LOCALTIMESTAMP	reserved	reserved	reserved	 
+LOCATION	non-reserved	non-reserved	non-reserved	 
+LOCATOR	 	non-reserved	non-reserved	 
+LOCK	non-reserved	 	 	 
+LOWER	 	reserved	reserved	reserved
+M	 	non-reserved	non-reserved	 
+MAP	 	non-reserved	non-reserved	 
+MAPPING	non-reserved	non-reserved	non-reserved	 
+MATCH	non-reserved	reserved	reserved	reserved
+MATCHED	 	non-reserved	non-reserved	 
+MATERIALIZED	non-reserved	 	 	 
+MAX	 	reserved	reserved	reserved
+MAXVALUE	non-reserved	non-reserved	non-reserved	 
+MAX_CARDINALITY	 	 	reserved	 
+MEMBER	 	reserved	reserved	 
+MERGE	 	reserved	reserved	 
+MESSAGE_LENGTH	 	non-reserved	non-reserved	non-reserved
+MESSAGE_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
+MESSAGE_TEXT	 	non-reserved	non-reserved	non-reserved
+METHOD	 	reserved	reserved	 
+MIN	 	reserved	reserved	reserved
+MINUTE	non-reserved	reserved	reserved	reserved
+MINVALUE	non-reserved	non-reserved	non-reserved	 
+MOD	 	reserved	reserved	 
+MODE	non-reserved	 	 	 
+MODIFIES	 	reserved	reserved	 
+MODULE	 	reserved	reserved	reserved
+MONTH	non-reserved	reserved	reserved	reserved
+MORE	 	non-reserved	non-reserved	non-reserved
+MOVE	non-reserved	 	 	 
+MULTISET	 	reserved	reserved	 
+MUMPS	 	non-reserved	non-reserved	non-reserved
+NAME	non-reserved	non-reserved	non-reserved	non-reserved
+NAMES	non-reserved	non-reserved	non-reserved	reserved
+NAMESPACE	 	non-reserved	non-reserved	 
+NATIONAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NATURAL	reserved (can be function or type)	reserved	reserved	reserved
+NCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NCLOB	 	reserved	reserved	 
+NESTING	 	non-reserved	non-reserved	 
+NEW	 	reserved	reserved	 
+NEXT	non-reserved	non-reserved	non-reserved	reserved
+NFC	 	non-reserved	non-reserved	 
+NFD	 	non-reserved	non-reserved	 
+NFKC	 	non-reserved	non-reserved	 
+NFKD	 	non-reserved	non-reserved	 
+NIL	 	non-reserved	non-reserved	 
+NO	non-reserved	reserved	reserved	reserved
+NONE	non-reserved (cannot be function or type)	reserved	reserved	 
+NORMALIZE	 	reserved	reserved	 
+NORMALIZED	 	non-reserved	non-reserved	 
+NOT	reserved	reserved	reserved	reserved
+NOTHING	non-reserved	 	 	 
+NOTIFY	non-reserved	 	 	 
+NOTNULL	reserved (can be function or type)	 	 	 
+NOWAIT	non-reserved	 	 	 
+NTH_VALUE	 	reserved	reserved	 
+NTILE	 	reserved	reserved	 
+NULL	reserved	reserved	reserved	reserved
+NULLABLE	 	non-reserved	non-reserved	non-reserved
+NULLIF	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NULLS	non-reserved	non-reserved	non-reserved	 
+NUMBER	 	non-reserved	non-reserved	non-reserved
+NUMERIC	non-reserved (cannot be function or type)	reserved	reserved	reserved
+OBJECT	non-reserved	non-reserved	non-reserved	 
+OCCURRENCES_REGEX	 	reserved	reserved	 
+OCTETS	 	non-reserved	non-reserved	 
+OCTET_LENGTH	 	reserved	reserved	reserved
+OF	non-reserved	reserved	reserved	reserved
+OFF	non-reserved	non-reserved	non-reserved	 
+OFFSET	reserved	reserved	reserved	 
+OIDS	non-reserved	 	 	 
+OLD	 	reserved	reserved	 
+ON	reserved	reserved	reserved	reserved
+ONLY	reserved	reserved	reserved	reserved
+OPEN	 	reserved	reserved	reserved
+OPERATOR	non-reserved	 	 	 
+OPTION	non-reserved	non-reserved	non-reserved	reserved
+OPTIONS	non-reserved	non-reserved	non-reserved	 
+OR	reserved	reserved	reserved	reserved
+ORDER	reserved	reserved	reserved	reserved
+ORDERING	 	non-reserved	non-reserved	 
+ORDINALITY	 	non-reserved	non-reserved	 
+OTHERS	 	non-reserved	non-reserved	 
+OUT	non-reserved (cannot be function or type)	reserved	reserved	 
+OUTER	reserved (can be function or type)	reserved	reserved	reserved
+OUTPUT	 	non-reserved	non-reserved	reserved
+OVER	reserved (can be function or type)	reserved	reserved	 
+OVERLAPS	reserved (can be function or type)	reserved	reserved	reserved
+OVERLAY	non-reserved (cannot be function or type)	reserved	reserved	 
+OVERRIDING	 	non-reserved	non-reserved	 
+OWNED	non-reserved	 	 	 
+OWNER	non-reserved	 	 	 
+P	 	non-reserved	non-reserved	 
+PAD	 	non-reserved	non-reserved	reserved
+PARAMETER	 	reserved	reserved	 
+PARAMETER_MODE	 	non-reserved	non-reserved	 
+PARAMETER_NAME	 	non-reserved	non-reserved	 
+PARAMETER_ORDINAL_POSITION	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_CATALOG	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_NAME	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_SCHEMA	 	non-reserved	non-reserved	 
+PARSER	non-reserved	 	 	 
+PARTIAL	non-reserved	non-reserved	non-reserved	reserved
+PARTITION	non-reserved	reserved	reserved	 
+PASCAL	 	non-reserved	non-reserved	non-reserved
+PASSING	non-reserved	non-reserved	non-reserved	 
+PASSTHROUGH	 	non-reserved	non-reserved	 
+PASSWORD	non-reserved	 	 	 
+PATH	 	non-reserved	non-reserved	 
+PERCENT	 	reserved	 	 
+PERCENTILE_CONT	 	reserved	reserved	 
+PERCENTILE_DISC	 	reserved	reserved	 
+PERCENT_RANK	 	reserved	reserved	 
+PERIOD	 	reserved	 	 
+PERMISSION	 	non-reserved	non-reserved	 
+PLACING	reserved	non-reserved	non-reserved	 
+PLANS	non-reserved	 	 	 
+PLI	 	non-reserved	non-reserved	non-reserved
+PORTION	 	reserved	 	 
+POSITION	non-reserved (cannot be function or type)	reserved	reserved	reserved
+POSITION_REGEX	 	reserved	reserved	 
+POWER	 	reserved	reserved	 
+PRECEDES	 	reserved	 	 
+PRECEDING	non-reserved	non-reserved	non-reserved	 
+PRECISION	non-reserved (cannot be function or type)	reserved	reserved	reserved
+PREPARE	non-reserved	reserved	reserved	reserved
+PREPARED	non-reserved	 	 	 
+PRESERVE	non-reserved	non-reserved	non-reserved	reserved
+PRIMARY	reserved	reserved	reserved	reserved
+PRIOR	non-reserved	non-reserved	non-reserved	reserved
+PRIVILEGES	non-reserved	non-reserved	non-reserved	reserved
+PROCEDURAL	non-reserved	 	 	 
+PROCEDURE	non-reserved	reserved	reserved	reserved
+PROGRAM	non-reserved	 	 	 
+PUBLIC	 	non-reserved	non-reserved	reserved
+QUOTE	non-reserved	 	 	 
+RANGE	non-reserved	reserved	reserved	 
+RANK	 	reserved	reserved	 
+READ	non-reserved	non-reserved	non-reserved	reserved
+READS	 	reserved	reserved	 
+REAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+REASSIGN	non-reserved	 	 	 
+RECHECK	non-reserved	 	 	 
+RECOVERY	 	non-reserved	non-reserved	 
+RECURSIVE	non-reserved	reserved	reserved	 
+REF	non-reserved	reserved	reserved	 
+REFERENCES	reserved	reserved	reserved	reserved
+REFERENCING	 	reserved	reserved	 
+REFRESH	non-reserved	 	 	 
+REGR_AVGX	 	reserved	reserved	 
+REGR_AVGY	 	reserved	reserved	 
+REGR_COUNT	 	reserved	reserved	 
+REGR_INTERCEPT	 	reserved	reserved	 
+REGR_R2	 	reserved	reserved	 
+REGR_SLOPE	 	reserved	reserved	 
+REGR_SXX	 	reserved	reserved	 
+REGR_SXY	 	reserved	reserved	 
+REGR_SYY	 	reserved	reserved	 
+REINDEX	non-reserved	 	 	 
+RELATIVE	non-reserved	non-reserved	non-reserved	reserved
+RELEASE	non-reserved	reserved	reserved	 
+RENAME	non-reserved	 	 	 
+REPEATABLE	non-reserved	non-reserved	non-reserved	non-reserved
+REPLACE	non-reserved	 	 	 
+REPLICA	non-reserved	 	 	 
+REQUIRING	 	non-reserved	non-reserved	 
+RESET	non-reserved	 	 	 
+RESPECT	 	non-reserved	non-reserved	 
+RESTART	non-reserved	non-reserved	non-reserved	 
+RESTORE	 	non-reserved	non-reserved	 
+RESTRICT	non-reserved	non-reserved	non-reserved	reserved
+RESULT	 	reserved	reserved	 
+RETURN	 	reserved	reserved	 
+RETURNED_CARDINALITY	 	non-reserved	non-reserved	 
+RETURNED_LENGTH	 	non-reserved	non-reserved	non-reserved
+RETURNED_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
+RETURNED_SQLSTATE	 	non-reserved	non-reserved	non-reserved
+RETURNING	reserved	non-reserved	non-reserved	 
+RETURNS	non-reserved	reserved	reserved	 
+REVOKE	non-reserved	reserved	reserved	reserved
+RIGHT	reserved (can be function or type)	reserved	reserved	reserved
+ROLE	non-reserved	non-reserved	non-reserved	 
+ROLLBACK	non-reserved	reserved	reserved	reserved
+ROLLUP	 	reserved	reserved	 
+ROUTINE	 	non-reserved	non-reserved	 
+ROUTINE_CATALOG	 	non-reserved	non-reserved	 
+ROUTINE_NAME	 	non-reserved	non-reserved	 
+ROUTINE_SCHEMA	 	non-reserved	non-reserved	 
+ROW	non-reserved (cannot be function or type)	reserved	reserved	 
+ROWS	non-reserved	reserved	reserved	reserved
+ROW_COUNT	 	non-reserved	non-reserved	non-reserved
+ROW_NUMBER	 	reserved	reserved	 
+RULE	non-reserved	 	 	 
+SAVEPOINT	non-reserved	reserved	reserved	 
+SCALE	 	non-reserved	non-reserved	non-reserved
+SCHEMA	non-reserved	non-reserved	non-reserved	reserved
+SCHEMA_NAME	 	non-reserved	non-reserved	non-reserved
+SCOPE	 	reserved	reserved	 
+SCOPE_CATALOG	 	non-reserved	non-reserved	 
+SCOPE_NAME	 	non-reserved	non-reserved	 
+SCOPE_SCHEMA	 	non-reserved	non-reserved	 
+SCROLL	non-reserved	reserved	reserved	reserved
+SEARCH	non-reserved	reserved	reserved	 
+SECOND	non-reserved	reserved	reserved	reserved
+SECTION	 	non-reserved	non-reserved	reserved
+SECURITY	non-reserved	non-reserved	non-reserved	 
+SELECT	reserved	reserved	reserved	reserved
+SELECTIVE	 	non-reserved	non-reserved	 
+SELF	 	non-reserved	non-reserved	 
+SENSITIVE	 	reserved	reserved	 
+SEQUENCE	non-reserved	non-reserved	non-reserved	 
+SEQUENCES	non-reserved	 	 	 
+SERIALIZABLE	non-reserved	non-reserved	non-reserved	non-reserved
+SERVER	non-reserved	non-reserved	non-reserved	 
+SERVER_NAME	 	non-reserved	non-reserved	non-reserved
+SESSION	non-reserved	non-reserved	non-reserved	reserved
+SESSION_USER	reserved	reserved	reserved	reserved
+SET	non-reserved	reserved	reserved	reserved
+SETOF	non-reserved (cannot be function or type)	 	 	 
+SETS	 	non-reserved	non-reserved	 
+SHARE	non-reserved	 	 	 
+SHOW	non-reserved	 	 	 
+SIMILAR	reserved (can be function or type)	reserved	reserved	 
+SIMPLE	non-reserved	non-reserved	non-reserved	 
+SIZE	 	non-reserved	non-reserved	reserved
+SMALLINT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+SNAPSHOT	non-reserved	 	 	 
+SOME	reserved	reserved	reserved	reserved
+SOURCE	 	non-reserved	non-reserved	 
+SPACE	 	non-reserved	non-reserved	reserved
+SPECIFIC	 	reserved	reserved	 
+SPECIFICTYPE	 	reserved	reserved	 
+SPECIFIC_NAME	 	non-reserved	non-reserved	 
+SQL	 	reserved	reserved	reserved
+SQLCODE	 	 	 	reserved
+SQLERROR	 	 	 	reserved
+SQLEXCEPTION	 	reserved	reserved	 
+SQLSTATE	 	reserved	reserved	reserved
+SQLWARNING	 	reserved	reserved	 
+SQRT	 	reserved	reserved	 
+STABLE	non-reserved	 	 	 
+STANDALONE	non-reserved	non-reserved	non-reserved	 
+START	non-reserved	reserved	reserved	 
+STATE	 	non-reserved	non-reserved	 
+STATEMENT	non-reserved	non-reserved	non-reserved	 
+STATIC	 	reserved	reserved	 
+STATISTICS	non-reserved	 	 	 
+STDDEV_POP	 	reserved	reserved	 
+STDDEV_SAMP	 	reserved	reserved	 
+STDIN	non-reserved	 	 	 
+STDOUT	non-reserved	 	 	 
+STORAGE	non-reserved	 	 	 
+STRICT	non-reserved	 	 	 
+STRIP	non-reserved	non-reserved	non-reserved	 
+STRUCTURE	 	non-reserved	non-reserved	 
+STYLE	 	non-reserved	non-reserved	 
+SUBCLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
+SUBMULTISET	 	reserved	reserved	 
+SUBSTRING	non-reserved (cannot be function or type)	reserved	reserved	reserved
+SUBSTRING_REGEX	 	reserved	reserved	 
+SUCCEEDS	 	reserved	 	 
+SUM	 	reserved	reserved	reserved
+SYMMETRIC	reserved	reserved	reserved	 
+SYSID	non-reserved	 	 	 
+SYSTEM	non-reserved	reserved	reserved	 
+SYSTEM_TIME	 	reserved	 	 
+SYSTEM_USER	 	reserved	reserved	reserved
+T	 	non-reserved	non-reserved	 
+TABLE	reserved	reserved	reserved	reserved
+TABLES	non-reserved	 	 	 
+TABLESAMPLE	 	reserved	reserved	 
+TABLESPACE	non-reserved	 	 	 
+TABLE_NAME	 	non-reserved	non-reserved	non-reserved
+TEMP	non-reserved	 	 	 
+TEMPLATE	non-reserved	 	 	 
+TEMPORARY	non-reserved	non-reserved	non-reserved	reserved
+TEXT	non-reserved	 	 	 
+THEN	reserved	reserved	reserved	reserved
+TIES	 	non-reserved	non-reserved	 
+TIME	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TIMESTAMP	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TIMEZONE_HOUR	 	reserved	reserved	reserved
+TIMEZONE_MINUTE	 	reserved	reserved	reserved
+TO	reserved	reserved	reserved	reserved
+TOKEN	 	non-reserved	non-reserved	 
+TOP_LEVEL_COUNT	 	non-reserved	non-reserved	 
+TRAILING	reserved	reserved	reserved	reserved
+TRANSACTION	non-reserved	non-reserved	non-reserved	reserved
+TRANSACTIONS_COMMITTED	 	non-reserved	non-reserved	 
+TRANSACTIONS_ROLLED_BACK	 	non-reserved	non-reserved	 
+TRANSACTION_ACTIVE	 	non-reserved	non-reserved	 
+TRANSFORM	 	non-reserved	non-reserved	 
+TRANSFORMS	 	non-reserved	non-reserved	 
+TRANSLATE	 	reserved	reserved	reserved
+TRANSLATE_REGEX	 	reserved	reserved	 
+TRANSLATION	 	reserved	reserved	reserved
+TREAT	non-reserved (cannot be function or type)	reserved	reserved	 
+TRIGGER	non-reserved	reserved	reserved	 
+TRIGGER_CATALOG	 	non-reserved	non-reserved	 
+TRIGGER_NAME	 	non-reserved	non-reserved	 
+TRIGGER_SCHEMA	 	non-reserved	non-reserved	 
+TRIM	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TRIM_ARRAY	 	reserved	reserved	 
+TRUE	reserved	reserved	reserved	reserved
+TRUNCATE	non-reserved	reserved	reserved	 
+TRUSTED	non-reserved	 	 	 
+TYPE	non-reserved	non-reserved	non-reserved	non-reserved
+TYPES	non-reserved	 	 	 
+UESCAPE	 	reserved	reserved	 
+UNBOUNDED	non-reserved	non-reserved	non-reserved	 
+UNCOMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
+UNDER	 	non-reserved	non-reserved	 
+UNENCRYPTED	non-reserved	 	 	 
+UNION	reserved	reserved	reserved	reserved
+UNIQUE	reserved	reserved	reserved	reserved
+UNKNOWN	non-reserved	reserved	reserved	reserved
+UNLINK	 	non-reserved	non-reserved	 
+UNLISTEN	non-reserved	 	 	 
+UNLOGGED	non-reserved	 	 	 
+UNNAMED	 	non-reserved	non-reserved	non-reserved
+UNNEST	 	reserved	reserved	 
+UNTIL	non-reserved	 	 	 
+UNTYPED	 	non-reserved	non-reserved	 
+UPDATE	non-reserved	reserved	reserved	reserved
+UPPER	 	reserved	reserved	reserved
+URI	 	non-reserved	non-reserved	 
+USAGE	 	non-reserved	non-reserved	reserved
+USER	reserved	reserved	reserved	reserved
+USER_DEFINED_TYPE_CATALOG	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_CODE	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_NAME	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_SCHEMA	 	non-reserved	non-reserved	 
+USING	reserved	reserved	reserved	reserved
+VACUUM	non-reserved	 	 	 
+VALID	non-reserved	non-reserved	non-reserved	 
+VALIDATE	non-reserved	 	 	 
+VALIDATOR	non-reserved	 	 	 
+VALUE	non-reserved	reserved	reserved	reserved
+VALUES	non-reserved (cannot be function or type)	reserved	reserved	reserved
+VALUE_OF	 	reserved	 	 
+VARBINARY	 	reserved	reserved	 
+VARCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+VARIADIC	reserved	 	 	 
+VARYING	non-reserved	reserved	reserved	reserved
+VAR_POP	 	reserved	reserved	 
+VAR_SAMP	 	reserved	reserved	 
+VERBOSE	reserved (can be function or type)	 	 	 
+VERSION	non-reserved	non-reserved	non-reserved	 
+VERSIONING	 	reserved	 	 
+VIEW	non-reserved	non-reserved	non-reserved	reserved
+VOLATILE	non-reserved	 	 	 
+WHEN	reserved	reserved	reserved	reserved
+WHENEVER	 	reserved	reserved	reserved
+WHERE	reserved	reserved	reserved	reserved
+WHITESPACE	non-reserved	non-reserved	non-reserved	 
+WIDTH_BUCKET	 	reserved	reserved	 
+WINDOW	reserved	reserved	reserved	 
+WITH	reserved	reserved	reserved	reserved
+WITHIN	 	reserved	reserved	 
+WITHOUT	non-reserved	reserved	reserved	 
+WORK	non-reserved	non-reserved	non-reserved	reserved
+WRAPPER	non-reserved	non-reserved	non-reserved	 
+WRITE	non-reserved	non-reserved	non-reserved	reserved
+XML	non-reserved	reserved	reserved	 
+XMLAGG	 	reserved	reserved	 
+XMLATTRIBUTES	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLBINARY	 	reserved	reserved	 
+XMLCAST	 	reserved	reserved	 
+XMLCOMMENT	 	reserved	reserved	 
+XMLCONCAT	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLDECLARATION	 	non-reserved	non-reserved	 
+XMLDOCUMENT	 	reserved	reserved	 
+XMLELEMENT	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLEXISTS	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLFOREST	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLITERATE	 	reserved	reserved	 
+XMLNAMESPACES	 	reserved	reserved	 
+XMLPARSE	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLPI	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLQUERY	 	reserved	reserved	 
+XMLROOT	non-reserved (cannot be function or type)	 	 	 
+XMLSCHEMA	 	non-reserved	non-reserved	 
+XMLSERIALIZE	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLTABLE	 	reserved	reserved	 
+XMLTEXT	 	reserved	reserved	 
+XMLVALIDATE	 	reserved	reserved	 
+YEAR	non-reserved	reserved	reserved	reserved
+YES	non-reserved	non-reserved	non-reserved	 
+ZONE	non-reserved	non-reserved	non-reserved	reserved

+ 78 - 0
vendor/gitea.com/xorm/xorm/processors.go

@@ -0,0 +1,78 @@
+// 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
+
+// BeforeInsertProcessor executed before an object is initially persisted to the database
+type BeforeInsertProcessor interface {
+	BeforeInsert()
+}
+
+// BeforeUpdateProcessor executed before an object is updated
+type BeforeUpdateProcessor interface {
+	BeforeUpdate()
+}
+
+// BeforeDeleteProcessor executed before an object is deleted
+type BeforeDeleteProcessor interface {
+	BeforeDelete()
+}
+
+// BeforeSetProcessor executed before data set to the struct fields
+type BeforeSetProcessor interface {
+	BeforeSet(string, Cell)
+}
+
+// AfterSetProcessor executed after data set to the struct fields
+type AfterSetProcessor interface {
+	AfterSet(string, Cell)
+}
+
+// AfterInsertProcessor executed after an object is persisted to the database
+type AfterInsertProcessor interface {
+	AfterInsert()
+}
+
+// AfterUpdateProcessor executed after an object has been updated
+type AfterUpdateProcessor interface {
+	AfterUpdate()
+}
+
+// AfterDeleteProcessor executed after an object has been deleted
+type AfterDeleteProcessor interface {
+	AfterDelete()
+}
+
+// AfterLoadProcessor executed after an ojbect has been loaded from database
+type AfterLoadProcessor interface {
+	AfterLoad()
+}
+
+// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter
+type AfterLoadSessionProcessor interface {
+	AfterLoad(*Session)
+}
+
+type executedProcessorFunc func(*Session, interface{}) error
+
+type executedProcessor struct {
+	fun     executedProcessorFunc
+	session *Session
+	bean    interface{}
+}
+
+func (executor *executedProcessor) execute() error {
+	return executor.fun(executor.session, executor.bean)
+}
+
+func (session *Session) executeProcessors() error {
+	processors := session.afterProcessors
+	session.afterProcessors = make([]executedProcessor, 0)
+	for _, processor := range processors {
+		if err := processor.execute(); err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 121 - 0
vendor/gitea.com/xorm/xorm/rows.go

@@ -0,0 +1,121 @@
+// 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 (
+	"database/sql"
+	"fmt"
+	"reflect"
+
+	"xorm.io/core"
+)
+
+// Rows rows wrapper a rows to
+type Rows struct {
+	session   *Session
+	rows      *core.Rows
+	beanType  reflect.Type
+	lastError error
+}
+
+func newRows(session *Session, bean interface{}) (*Rows, error) {
+	rows := new(Rows)
+	rows.session = session
+	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
+
+	var sqlStr string
+	var args []interface{}
+	var err error
+
+	if err = rows.session.statement.setRefBean(bean); err != nil {
+		return nil, err
+	}
+
+	if len(session.statement.TableName()) <= 0 {
+		return nil, ErrTableNotFound
+	}
+
+	if rows.session.statement.RawSQL == "" {
+		sqlStr, args, err = rows.session.statement.genGetSQL(bean)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		sqlStr = rows.session.statement.RawSQL
+		args = rows.session.statement.RawParams
+	}
+
+	rows.rows, err = rows.session.queryRows(sqlStr, args...)
+	if err != nil {
+		rows.lastError = err
+		rows.Close()
+		return nil, err
+	}
+
+	return rows, nil
+}
+
+// Next move cursor to next record, return false if end has reached
+func (rows *Rows) Next() bool {
+	if rows.lastError == nil && rows.rows != nil {
+		hasNext := rows.rows.Next()
+		if !hasNext {
+			rows.lastError = sql.ErrNoRows
+		}
+		return hasNext
+	}
+	return false
+}
+
+// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
+func (rows *Rows) Err() error {
+	return rows.lastError
+}
+
+// Scan row record to bean properties
+func (rows *Rows) Scan(bean interface{}) error {
+	if rows.lastError != nil {
+		return rows.lastError
+	}
+
+	if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
+		return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
+	}
+
+	if err := rows.session.statement.setRefBean(bean); err != nil {
+		return err
+	}
+
+	fields, err := rows.rows.Columns()
+	if err != nil {
+		return err
+	}
+
+	scanResults, err := rows.session.row2Slice(rows.rows, fields, bean)
+	if err != nil {
+		return err
+	}
+
+	dataStruct := rValue(bean)
+	_, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
+	if err != nil {
+		return err
+	}
+
+	return rows.session.executeProcessors()
+}
+
+// Close session if session.IsAutoClose is true, and claimed any opened resources
+func (rows *Rows) Close() error {
+	if rows.session.isAutoClose {
+		defer rows.session.Close()
+	}
+
+	if rows.rows != nil {
+		return rows.rows.Close()
+	}
+
+	return rows.lastError
+}

+ 866 - 0
vendor/gitea.com/xorm/xorm/session.go

@@ -0,0 +1,866 @@
+// 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 (
+	"context"
+	"database/sql"
+	"errors"
+	"fmt"
+	"hash/crc32"
+	"reflect"
+	"strings"
+	"time"
+
+	"xorm.io/core"
+)
+
+type sessionType int
+
+const (
+	engineSession sessionType = iota
+	groupSession
+)
+
+// Session keep a pointer to sql.DB and provides all execution of all
+// kind of database operations.
+type Session struct {
+	db                     *core.DB
+	engine                 *Engine
+	tx                     *core.Tx
+	statement              Statement
+	isAutoCommit           bool
+	isCommitedOrRollbacked bool
+	isAutoClose            bool
+
+	// Automatically reset the statement after operations that execute a SQL
+	// query such as Count(), Find(), Get(), ...
+	autoResetStatement bool
+
+	// !nashtsai! storing these beans due to yet committed tx
+	afterInsertBeans map[interface{}]*[]func(interface{})
+	afterUpdateBeans map[interface{}]*[]func(interface{})
+	afterDeleteBeans map[interface{}]*[]func(interface{})
+	// --
+
+	beforeClosures []func(interface{})
+	afterClosures  []func(interface{})
+
+	afterProcessors []executedProcessor
+
+	prepareStmt bool
+	stmtCache   map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
+
+	// !evalphobia! stored the last executed query on this session
+	//beforeSQLExec func(string, ...interface{})
+	lastSQL     string
+	lastSQLArgs []interface{}
+
+	ctx         context.Context
+	sessionType sessionType
+}
+
+// Clone copy all the session's content and return a new session
+func (session *Session) Clone() *Session {
+	var sess = *session
+	return &sess
+}
+
+// Init reset the session as the init status.
+func (session *Session) Init() {
+	session.statement.Init()
+	session.statement.Engine = session.engine
+	session.isAutoCommit = true
+	session.isCommitedOrRollbacked = false
+	session.isAutoClose = false
+	session.autoResetStatement = true
+	session.prepareStmt = false
+
+	// !nashtsai! is lazy init better?
+	session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.beforeClosures = make([]func(interface{}), 0)
+	session.afterClosures = make([]func(interface{}), 0)
+	session.stmtCache = make(map[uint32]*core.Stmt)
+
+	session.afterProcessors = make([]executedProcessor, 0)
+
+	session.lastSQL = ""
+	session.lastSQLArgs = []interface{}{}
+
+	session.ctx = session.engine.defaultContext
+}
+
+// Close release the connection from pool
+func (session *Session) Close() {
+	for _, v := range session.stmtCache {
+		v.Close()
+	}
+
+	if session.db != nil {
+		// When Close be called, if session is a transaction and do not call
+		// Commit or Rollback, then call Rollback.
+		if session.tx != nil && !session.isCommitedOrRollbacked {
+			session.Rollback()
+		}
+		session.tx = nil
+		session.stmtCache = nil
+		session.db = nil
+	}
+}
+
+// ContextCache enable context cache or not
+func (session *Session) ContextCache(context ContextCache) *Session {
+	session.statement.context = context
+	return session
+}
+
+// IsClosed returns if session is closed
+func (session *Session) IsClosed() bool {
+	return session.db == nil
+}
+
+func (session *Session) resetStatement() {
+	if session.autoResetStatement {
+		session.statement.Init()
+	}
+}
+
+// Prepare set a flag to session that should be prepare statement before execute query
+func (session *Session) Prepare() *Session {
+	session.prepareStmt = true
+	return session
+}
+
+// Before Apply before Processor, affected bean is passed to closure arg
+func (session *Session) Before(closures func(interface{})) *Session {
+	if closures != nil {
+		session.beforeClosures = append(session.beforeClosures, closures)
+	}
+	return session
+}
+
+// After Apply after Processor, affected bean is passed to closure arg
+func (session *Session) After(closures func(interface{})) *Session {
+	if closures != nil {
+		session.afterClosures = append(session.afterClosures, closures)
+	}
+	return session
+}
+
+// Table can input a string or pointer to struct for special a table to operate.
+func (session *Session) Table(tableNameOrBean interface{}) *Session {
+	session.statement.Table(tableNameOrBean)
+	return session
+}
+
+// Alias set the table alias
+func (session *Session) Alias(alias string) *Session {
+	session.statement.Alias(alias)
+	return session
+}
+
+// NoCascade indicate that no cascade load child object
+func (session *Session) NoCascade() *Session {
+	session.statement.UseCascade = false
+	return session
+}
+
+// ForUpdate Set Read/Write locking for UPDATE
+func (session *Session) ForUpdate() *Session {
+	session.statement.IsForUpdate = true
+	return session
+}
+
+// NoAutoCondition disable generate SQL condition from beans
+func (session *Session) NoAutoCondition(no ...bool) *Session {
+	session.statement.NoAutoCondition(no...)
+	return session
+}
+
+// Limit provide limit and offset query condition
+func (session *Session) Limit(limit int, start ...int) *Session {
+	session.statement.Limit(limit, start...)
+	return session
+}
+
+// OrderBy provide order by query condition, the input parameter is the content
+// after order by on a sql statement.
+func (session *Session) OrderBy(order string) *Session {
+	session.statement.OrderBy(order)
+	return session
+}
+
+// Desc provide desc order by query condition, the input parameters are columns.
+func (session *Session) Desc(colNames ...string) *Session {
+	session.statement.Desc(colNames...)
+	return session
+}
+
+// Asc provide asc order by query condition, the input parameters are columns.
+func (session *Session) Asc(colNames ...string) *Session {
+	session.statement.Asc(colNames...)
+	return session
+}
+
+// StoreEngine is only avialble mysql dialect currently
+func (session *Session) StoreEngine(storeEngine string) *Session {
+	session.statement.StoreEngine = storeEngine
+	return session
+}
+
+// Charset is only avialble mysql dialect currently
+func (session *Session) Charset(charset string) *Session {
+	session.statement.Charset = charset
+	return session
+}
+
+// Cascade indicates if loading sub Struct
+func (session *Session) Cascade(trueOrFalse ...bool) *Session {
+	if len(trueOrFalse) >= 1 {
+		session.statement.UseCascade = trueOrFalse[0]
+	}
+	return session
+}
+
+// NoCache ask this session do not retrieve data from cache system and
+// get data from database directly.
+func (session *Session) NoCache() *Session {
+	session.statement.UseCache = false
+	return session
+}
+
+// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
+func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
+	session.statement.Join(joinOperator, tablename, condition, args...)
+	return session
+}
+
+// GroupBy Generate Group By statement
+func (session *Session) GroupBy(keys string) *Session {
+	session.statement.GroupBy(keys)
+	return session
+}
+
+// Having Generate Having statement
+func (session *Session) Having(conditions string) *Session {
+	session.statement.Having(conditions)
+	return session
+}
+
+// DB db return the wrapper of sql.DB
+func (session *Session) DB() *core.DB {
+	if session.db == nil {
+		session.db = session.engine.db
+		session.stmtCache = make(map[uint32]*core.Stmt, 0)
+	}
+	return session.db
+}
+
+func cleanupProcessorsClosures(slices *[]func(interface{})) {
+	if len(*slices) > 0 {
+		*slices = make([]func(interface{}), 0)
+	}
+}
+
+func (session *Session) canCache() bool {
+	if session.statement.RefTable == nil ||
+		session.statement.JoinStr != "" ||
+		session.statement.RawSQL != "" ||
+		!session.statement.UseCache ||
+		session.statement.IsForUpdate ||
+		session.tx != nil ||
+		len(session.statement.selectStr) > 0 {
+		return false
+	}
+	return true
+}
+
+func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
+	crc := crc32.ChecksumIEEE([]byte(sqlStr))
+	// TODO try hash(sqlStr+len(sqlStr))
+	var has bool
+	stmt, has = session.stmtCache[crc]
+	if !has {
+		stmt, err = db.PrepareContext(session.ctx, sqlStr)
+		if err != nil {
+			return nil, err
+		}
+		session.stmtCache[crc] = stmt
+	}
+	return
+}
+
+func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
+	var col *core.Column
+	if col = table.GetColumnIdx(key, idx); col == nil {
+		return nil, ErrFieldIsNotExist{key, table.Name}
+	}
+
+	fieldValue, err := col.ValueOfV(dataStruct)
+	if err != nil {
+		return nil, err
+	}
+
+	if !fieldValue.IsValid() || !fieldValue.CanSet() {
+		return nil, ErrFieldIsNotValid{key, table.Name}
+	}
+
+	return fieldValue, nil
+}
+
+// Cell cell is a result of one column field
+type Cell *interface{}
+
+func (session *Session) rows2Beans(rows *core.Rows, fields []string,
+	table *core.Table, newElemFunc func([]string) reflect.Value,
+	sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
+	for rows.Next() {
+		var newValue = newElemFunc(fields)
+		bean := newValue.Interface()
+		dataStruct := newValue.Elem()
+
+		// handle beforeClosures
+		scanResults, err := session.row2Slice(rows, fields, bean)
+		if err != nil {
+			return err
+		}
+		pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
+		if err != nil {
+			return err
+		}
+		session.afterProcessors = append(session.afterProcessors, executedProcessor{
+			fun: func(*Session, interface{}) error {
+				return sliceValueSetFunc(&newValue, pk)
+			},
+			session: session,
+			bean:    bean,
+		})
+	}
+	return nil
+}
+
+func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) {
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+
+	scanResults := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var cell interface{}
+		scanResults[i] = &cell
+	}
+	if err := rows.Scan(scanResults...); err != nil {
+		return nil, err
+	}
+
+	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
+		for ii, key := range fields {
+			b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
+		}
+	}
+	return scanResults, nil
+}
+
+func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
+	defer func() {
+		if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
+			for ii, key := range fields {
+				b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
+			}
+		}
+	}()
+
+	// handle afterClosures
+	for _, closure := range session.afterClosures {
+		session.afterProcessors = append(session.afterProcessors, executedProcessor{
+			fun: func(sess *Session, bean interface{}) error {
+				closure(bean)
+				return nil
+			},
+			session: session,
+			bean:    bean,
+		})
+	}
+
+	if a, has := bean.(AfterLoadProcessor); has {
+		session.afterProcessors = append(session.afterProcessors, executedProcessor{
+			fun: func(sess *Session, bean interface{}) error {
+				a.AfterLoad()
+				return nil
+			},
+			session: session,
+			bean:    bean,
+		})
+	}
+
+	if a, has := bean.(AfterLoadSessionProcessor); has {
+		session.afterProcessors = append(session.afterProcessors, executedProcessor{
+			fun: func(sess *Session, bean interface{}) error {
+				a.AfterLoad(sess)
+				return nil
+			},
+			session: session,
+			bean:    bean,
+		})
+	}
+
+	var tempMap = make(map[string]int)
+	var pk core.PK
+	for ii, key := range fields {
+		var idx int
+		var ok bool
+		var lKey = strings.ToLower(key)
+		if idx, ok = tempMap[lKey]; !ok {
+			idx = 0
+		} else {
+			idx = idx + 1
+		}
+		tempMap[lKey] = idx
+
+		fieldValue, err := session.getField(dataStruct, key, table, idx)
+		if err != nil {
+			if !strings.Contains(err.Error(), "is not valid") {
+				session.engine.logger.Warn(err)
+			}
+			continue
+		}
+		if fieldValue == nil {
+			continue
+		}
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
+
+		// if row is null then ignore
+		if rawValue.Interface() == nil {
+			continue
+		}
+
+		if fieldValue.CanAddr() {
+			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+				if data, err := value2Bytes(&rawValue); err == nil {
+					if err := structConvert.FromDB(data); err != nil {
+						return nil, err
+					}
+				} else {
+					return nil, err
+				}
+				continue
+			}
+		}
+
+		if _, ok := fieldValue.Interface().(core.Conversion); ok {
+			if data, err := value2Bytes(&rawValue); err == nil {
+				if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
+					fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+				}
+				fieldValue.Interface().(core.Conversion).FromDB(data)
+			} else {
+				return nil, err
+			}
+			continue
+		}
+
+		rawValueType := reflect.TypeOf(rawValue.Interface())
+		vv := reflect.ValueOf(rawValue.Interface())
+		col := table.GetColumnIdx(key, idx)
+		if col.IsPrimaryKey {
+			pk = append(pk, rawValue.Interface())
+		}
+		fieldType := fieldValue.Type()
+		hasAssigned := false
+
+		if col.SQLType.IsJson() {
+			var bs []byte
+			if rawValueType.Kind() == reflect.String {
+				bs = []byte(vv.String())
+			} else if rawValueType.ConvertibleTo(core.BytesType) {
+				bs = vv.Bytes()
+			} else {
+				return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
+			}
+
+			hasAssigned = true
+
+			if len(bs) > 0 {
+				if fieldType.Kind() == reflect.String {
+					fieldValue.SetString(string(bs))
+					continue
+				}
+				if fieldValue.CanAddr() {
+					err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						return nil, err
+					}
+				} else {
+					x := reflect.New(fieldType)
+					err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(x.Elem())
+				}
+			}
+
+			continue
+		}
+
+		switch fieldType.Kind() {
+		case reflect.Complex64, reflect.Complex128:
+			// TODO: reimplement this
+			var bs []byte
+			if rawValueType.Kind() == reflect.String {
+				bs = []byte(vv.String())
+			} else if rawValueType.ConvertibleTo(core.BytesType) {
+				bs = vv.Bytes()
+			}
+
+			hasAssigned = true
+			if len(bs) > 0 {
+				if fieldValue.CanAddr() {
+					err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						return nil, err
+					}
+				} else {
+					x := reflect.New(fieldType)
+					err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(x.Elem())
+				}
+			}
+		case reflect.Slice, reflect.Array:
+			switch rawValueType.Kind() {
+			case reflect.Slice, reflect.Array:
+				switch rawValueType.Elem().Kind() {
+				case reflect.Uint8:
+					if fieldType.Elem().Kind() == reflect.Uint8 {
+						hasAssigned = true
+						if col.SQLType.IsText() {
+							x := reflect.New(fieldType)
+							err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
+							if err != nil {
+								return nil, err
+							}
+							fieldValue.Set(x.Elem())
+						} else {
+							if fieldValue.Len() > 0 {
+								for i := 0; i < fieldValue.Len(); i++ {
+									if i < vv.Len() {
+										fieldValue.Index(i).Set(vv.Index(i))
+									}
+								}
+							} else {
+								for i := 0; i < vv.Len(); i++ {
+									fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
+								}
+							}
+						}
+					}
+				}
+			}
+		case reflect.String:
+			if rawValueType.Kind() == reflect.String {
+				hasAssigned = true
+				fieldValue.SetString(vv.String())
+			}
+		case reflect.Bool:
+			if rawValueType.Kind() == reflect.Bool {
+				hasAssigned = true
+				fieldValue.SetBool(vv.Bool())
+			}
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			switch rawValueType.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				hasAssigned = true
+				fieldValue.SetInt(vv.Int())
+			}
+		case reflect.Float32, reflect.Float64:
+			switch rawValueType.Kind() {
+			case reflect.Float32, reflect.Float64:
+				hasAssigned = true
+				fieldValue.SetFloat(vv.Float())
+			}
+		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+			switch rawValueType.Kind() {
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+				hasAssigned = true
+				fieldValue.SetUint(vv.Uint())
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				hasAssigned = true
+				fieldValue.SetUint(uint64(vv.Int()))
+			}
+		case reflect.Struct:
+			if fieldType.ConvertibleTo(core.TimeType) {
+				dbTZ := session.engine.DatabaseTZ
+				if col.TimeZone != nil {
+					dbTZ = col.TimeZone
+				}
+
+				if rawValueType == core.TimeType {
+					hasAssigned = true
+
+					t := vv.Convert(core.TimeType).Interface().(time.Time)
+
+					z, _ := t.Zone()
+					// set new location if database don't save timezone or give an incorrect timezone
+					if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
+						session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+						t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
+							t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
+					}
+
+					t = t.In(session.engine.TZLocation)
+					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+				} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
+					rawValueType == core.Int32Type {
+					hasAssigned = true
+
+					t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
+					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+				} else {
+					if d, ok := vv.Interface().([]uint8); ok {
+						hasAssigned = true
+						t, err := session.byte2Time(col, d)
+						if err != nil {
+							session.engine.logger.Error("byte2Time error:", err.Error())
+							hasAssigned = false
+						} else {
+							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+						}
+					} else if d, ok := vv.Interface().(string); ok {
+						hasAssigned = true
+						t, err := session.str2Time(col, d)
+						if err != nil {
+							session.engine.logger.Error("byte2Time error:", err.Error())
+							hasAssigned = false
+						} else {
+							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+						}
+					} else {
+						return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
+					}
+				}
+			} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
+				// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
+				hasAssigned = true
+				if err := nulVal.Scan(vv.Interface()); err != nil {
+					session.engine.logger.Error("sql.Sanner error:", err.Error())
+					hasAssigned = false
+				}
+			} else if col.SQLType.IsJson() {
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					x := reflect.New(fieldType)
+					if len([]byte(vv.String())) > 0 {
+						err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), x.Interface())
+						if err != nil {
+							return nil, err
+						}
+						fieldValue.Set(x.Elem())
+					}
+				} else if rawValueType.Kind() == reflect.Slice {
+					hasAssigned = true
+					x := reflect.New(fieldType)
+					if len(vv.Bytes()) > 0 {
+						err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
+						if err != nil {
+							return nil, err
+						}
+						fieldValue.Set(x.Elem())
+					}
+				}
+			} else if session.statement.UseCascade {
+				table, err := session.engine.autoMapType(*fieldValue)
+				if err != nil {
+					return nil, err
+				}
+
+				hasAssigned = true
+				if len(table.PrimaryKeys) != 1 {
+					return nil, errors.New("unsupported non or composited primary key cascade")
+				}
+				var pk = make(core.PK, len(table.PrimaryKeys))
+				pk[0], err = asKind(vv, rawValueType)
+				if err != nil {
+					return nil, err
+				}
+
+				if !isPKZero(pk) {
+					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+					// property to be fetched lazily
+					structInter := reflect.New(fieldValue.Type())
+					has, err := session.ID(pk).NoCascade().get(structInter.Interface())
+					if err != nil {
+						return nil, err
+					}
+					if has {
+						fieldValue.Set(structInter.Elem())
+					} else {
+						return nil, errors.New("cascade obj is not exist")
+					}
+				}
+			}
+		case reflect.Ptr:
+			// !nashtsai! TODO merge duplicated codes above
+			switch fieldType {
+			// following types case matching ptr's native type, therefore assign ptr directly
+			case core.PtrStringType:
+				if rawValueType.Kind() == reflect.String {
+					x := vv.String()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrBoolType:
+				if rawValueType.Kind() == reflect.Bool {
+					x := vv.Bool()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrTimeType:
+				if rawValueType == core.PtrTimeType {
+					hasAssigned = true
+					var x = rawValue.Interface().(time.Time)
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrFloat64Type:
+				if rawValueType.Kind() == reflect.Float64 {
+					x := vv.Float()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUint64Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint64(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt64Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					x := vv.Int()
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrFloat32Type:
+				if rawValueType.Kind() == reflect.Float64 {
+					var x = float32(vv.Float())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrIntType:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt32Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int32(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt8Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int8(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrInt16Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = int16(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUintType:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.PtrUint32Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint32(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Uint8Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint8(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Uint16Type:
+				if rawValueType.Kind() == reflect.Int64 {
+					var x = uint16(vv.Int())
+					hasAssigned = true
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+			case core.Complex64Type:
+				var x complex64
+				if len([]byte(vv.String())) > 0 {
+					err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+				hasAssigned = true
+			case core.Complex128Type:
+				var x complex128
+				if len([]byte(vv.String())) > 0 {
+					err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						return nil, err
+					}
+					fieldValue.Set(reflect.ValueOf(&x))
+				}
+				hasAssigned = true
+			} // switch fieldType
+		} // switch fieldType.Kind()
+
+		// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
+		if !hasAssigned {
+			data, err := value2Bytes(&rawValue)
+			if err != nil {
+				return nil, err
+			}
+
+			if err = session.bytes2Value(col, fieldValue, data); err != nil {
+				return nil, err
+			}
+		}
+	}
+	return pk, nil
+}
+
+// saveLastSQL stores executed query information
+func (session *Session) saveLastSQL(sql string, args ...interface{}) {
+	session.lastSQL = sql
+	session.lastSQLArgs = args
+	session.engine.logSQL(sql, args...)
+}
+
+// LastSQL returns last query information
+func (session *Session) LastSQL() (string, []interface{}) {
+	return session.lastSQL, session.lastSQLArgs
+}
+
+// Unscoped always disable struct tag "deleted"
+func (session *Session) Unscoped() *Session {
+	session.statement.Unscoped()
+	return session
+}
+
+func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
+	switch fieldValue.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		fieldValue.SetInt(fieldValue.Int() + 1)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		fieldValue.SetUint(fieldValue.Uint() + 1)
+	}
+}

+ 199 - 0
vendor/gitea.com/xorm/xorm/session_cols.go

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

+ 23 - 0
vendor/gitea.com/xorm/xorm/session_context.go

@@ -0,0 +1,23 @@
+// Copyright 2019 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 "context"
+
+// Context sets the context on this session
+func (session *Session) Context(ctx context.Context) *Session {
+	session.ctx = ctx
+	return session
+}
+
+// PingContext test if database is ok
+func (session *Session) PingContext(ctx context.Context) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
+	return session.DB().PingContext(ctx)
+}

+ 661 - 0
vendor/gitea.com/xorm/xorm/session_convert.go

@@ -0,0 +1,661 @@
+// 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"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"xorm.io/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
+
+	var parseLoc = session.engine.DatabaseTZ
+	if col.TimeZone != nil {
+		parseLoc = col.TimeZone
+	}
+
+	if sdata == zeroTime0 || sdata == zeroTime1 {
+	} 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)
+			//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, parseLoc)
+		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, parseLoc)
+			//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, parseLoc)
+			//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, parseLoc)
+		//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, parseLoc)
+		//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, parseLoc)
+		//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.In(session.engine.TZLocation)
+	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 := DefaultJSONHandler.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 := DefaultJSONHandler.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 := DefaultJSONHandler.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:
+		v, err := asBool(data)
+		if err != nil {
+			return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+		}
+		fieldValue.Set(reflect.ValueOf(v))
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		sdata := string(data)
+		var x int64
+		var err error
+		// for mysql, when use bit, it returned \x01
+		if col.SQLType.Name == core.Bit &&
+			session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
+			if len(data) == 1 {
+				x = int64(data[0])
+			} else {
+				x = 0
+			}
+		} else if strings.HasPrefix(sdata, "0x") {
+			x, err = strconv.ParseInt(sdata, 16, 64)
+		} else if strings.HasPrefix(sdata, "0") {
+			x, err = strconv.ParseInt(sdata, 8, 64)
+		} else if strings.EqualFold(sdata, "true") {
+			x = 1
+		} else if strings.EqualFold(sdata, "false") {
+			x = 0
+		} else {
+			x, err = strconv.ParseInt(sdata, 10, 64)
+		}
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetInt(x)
+	case reflect.Float32, reflect.Float64:
+		x, err := strconv.ParseFloat(string(data), 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+		}
+		fieldValue.SetFloat(x)
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+		x, err := strconv.ParseUint(string(data), 10, 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetUint(x)
+	//Currently only support Time type
+	case reflect.Struct:
+		// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
+		if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
+			if err := nulVal.Scan(data); err != nil {
+				return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
+			}
+		} else {
+			if fieldType.ConvertibleTo(core.TimeType) {
+				x, err := session.byte2Time(col, data)
+				if err != nil {
+					return err
+				}
+				v = x
+				fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
+			} else if session.statement.UseCascade {
+				table, err := session.engine.autoMapType(*fieldValue)
+				if err != nil {
+					return err
+				}
+
+				// TODO: current only support 1 primary key
+				if len(table.PrimaryKeys) > 1 {
+					return errors.New("unsupported composited primary key cascade")
+				}
+
+				var pk = make(core.PK, len(table.PrimaryKeys))
+				rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+				pk[0], err = str2PK(string(data), rawValueType)
+				if err != nil {
+					return err
+				}
+
+				if !isPKZero(pk) {
+					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+					// property to be fetched lazily
+					structInter := reflect.New(fieldValue.Type())
+					has, err := session.ID(pk).NoCascade().get(structInter.Interface())
+					if err != nil {
+						return err
+					}
+					if has {
+						v = structInter.Elem().Interface()
+						fieldValue.Set(reflect.ValueOf(v))
+					} else {
+						return errors.New("cascade obj is not exist")
+					}
+				}
+			}
+		}
+	case reflect.Ptr:
+		// !nashtsai! TODO merge duplicated codes above
+		//typeStr := fieldType.String()
+		switch fieldType.Elem().Kind() {
+		// case "*string":
+		case core.StringType.Kind():
+			x := string(data)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*bool":
+		case core.BoolType.Kind():
+			d := string(data)
+			v, err := strconv.ParseBool(d)
+			if err != nil {
+				return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
+		// case "*complex64":
+		case core.Complex64Type.Kind():
+			var x complex64
+			if len(data) > 0 {
+				err := DefaultJSONHandler.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 := DefaultJSONHandler.Unmarshal(data, &x)
+				if err != nil {
+					session.engine.logger.Error(err)
+					return err
+				}
+				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+			}
+		// case "*float64":
+		case core.Float64Type.Kind():
+			x, err := strconv.ParseFloat(string(data), 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*float32":
+		case core.Float32Type.Kind():
+			var x float32
+			x1, err := strconv.ParseFloat(string(data), 32)
+			if err != nil {
+				return fmt.Errorf("arg %v as float32: %s", key, err.Error())
+			}
+			x = float32(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint64":
+		case core.Uint64Type.Kind():
+			var x uint64
+			x, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint":
+		case core.UintType.Kind():
+			var x uint
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint32":
+		case core.Uint32Type.Kind():
+			var x uint32
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint32(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint8":
+		case core.Uint8Type.Kind():
+			var x uint8
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint8(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*uint16":
+		case core.Uint16Type.Kind():
+			var x uint16
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint16(x1)
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int64":
+		case core.Int64Type.Kind():
+			sdata := string(data)
+			var x int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int64(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x, err = strconv.ParseInt(sdata, 16, 64)
+			} else if strings.HasPrefix(sdata, "0") {
+				x, err = strconv.ParseInt(sdata, 8, 64)
+			} else {
+				x, err = strconv.ParseInt(sdata, 10, 64)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int":
+		case core.IntType.Kind():
+			sdata := string(data)
+			var x int
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int32":
+		case core.Int32Type.Kind():
+			sdata := string(data)
+			var x int32
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				session.engine.dialect.DBType() == core.MYSQL {
+				if len(data) == 1 {
+					x = int32(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int32(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int32(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int32(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int8":
+		case core.Int8Type.Kind():
+			sdata := string(data)
+			var x int8
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int8(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int8(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int8(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int8(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*int16":
+		case core.Int16Type.Kind():
+			sdata := string(data)
+			var x int16
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int16(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int16(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int16(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int16(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
+		// case "*SomeStruct":
+		case reflect.Struct:
+			switch fieldType {
+			// case "*.time.Time":
+			case core.PtrTimeType:
+				x, err := session.byte2Time(col, data)
+				if err != nil {
+					return err
+				}
+				v = x
+				fieldValue.Set(reflect.ValueOf(&x))
+			default:
+				if session.statement.UseCascade {
+					structInter := reflect.New(fieldType.Elem())
+					table, err := session.engine.autoMapType(structInter.Elem())
+					if err != nil {
+						return err
+					}
+
+					if len(table.PrimaryKeys) > 1 {
+						return errors.New("unsupported composited primary key cascade")
+					}
+
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+					pk[0], err = str2PK(string(data), rawValueType)
+					if err != nil {
+						return err
+					}
+
+					if !isPKZero(pk) {
+						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+						// property to be fetched lazily
+						has, err := session.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)
+			tf := session.engine.formatColTime(col, t)
+			return tf, nil
+		}
+
+		if !col.SQLType.IsJson() {
+			// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
+			if v, ok := fieldValue.Interface().(driver.Valuer); ok {
+				return v.Value()
+			}
+
+			fieldTable, err := session.engine.autoMapType(fieldValue)
+			if err != nil {
+				return nil, err
+			}
+			if len(fieldTable.PrimaryKeys) == 1 {
+				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
+				return pkField.Interface(), nil
+			}
+			return 0, fmt.Errorf("no primary key for col %v", col.Name)
+		}
+
+		if col.SQLType.IsText() {
+			bytes, err := DefaultJSONHandler.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 := DefaultJSONHandler.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 := DefaultJSONHandler.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 := DefaultJSONHandler.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.Slice) &&
+				(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
+				bytes = fieldValue.Bytes()
+			} else {
+				bytes, err = DefaultJSONHandler.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
+	}
+}

+ 244 - 0
vendor/gitea.com/xorm/xorm/session_delete.go

@@ -0,0 +1,244 @@
+// 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"
+
+	"xorm.io/core"
+)
+
+func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
+	if table == nil ||
+		session.tx != nil {
+		return ErrCacheFailed
+	}
+
+	for _, filter := range session.engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.engine.dialect, table)
+	}
+
+	newsql := session.statement.convertIDSQL(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+
+	cacher := session.engine.getCacher(tableName)
+	pkColumns := table.PKColumns()
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	if err != nil {
+		resultsSlice, err := session.queryBytes(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 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)
+			}
+		}
+	}
+
+	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 table:", tableName)
+	cacher.ClearIds(tableName)
+	return nil
+}
+
+// Delete records, bean's non-empty fields are conditions
+func (session *Session) Delete(bean interface{}) (int64, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	if session.statement.lastError != nil {
+		return 0, session.statement.lastError
+	}
+
+	if err := session.statement.setRefBean(bean); err != nil {
+		return 0, err
+	}
+
+	// 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, err := session.statement.genConds(bean)
+	if err != nil {
+		return 0, err
+	}
+	if len(condSQL) == 0 && session.statement.LimitN == 0 {
+		return 0, ErrNeedDeletedCond
+	}
+
+	var tableNameNoQuote = session.statement.TableName()
+	var tableName = session.engine.Quote(tableNameNoQuote)
+	var table = session.statement.RefTable
+	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.nowTime(deletedColumn)
+		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.getCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
+		session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
+	}
+
+	session.statement.RefTable = table
+	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()
+}

+ 96 - 0
vendor/gitea.com/xorm/xorm/session_exist.go

@@ -0,0 +1,96 @@
+// 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 (
+	"errors"
+	"fmt"
+	"reflect"
+
+	"xorm.io/builder"
+	"xorm.io/core"
+)
+
+// Exist returns true if the record exist otherwise return false
+func (session *Session) Exist(bean ...interface{}) (bool, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	if session.statement.lastError != nil {
+		return false, session.statement.lastError
+	}
+
+	var sqlStr string
+	var args []interface{}
+	var err error
+
+	if session.statement.RawSQL == "" {
+		if len(bean) == 0 {
+			tableName := session.statement.TableName()
+			if len(tableName) <= 0 {
+				return false, ErrTableNotFound
+			}
+
+			tableName = session.statement.Engine.Quote(tableName)
+
+			if session.statement.cond.IsValid() {
+				condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
+				if err != nil {
+					return false, err
+				}
+
+				if session.engine.dialect.DBType() == core.MSSQL {
+					sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s WHERE %s", tableName, condSQL)
+				} else if session.engine.dialect.DBType() == core.ORACLE {
+					sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) AND ROWNUM=1", tableName, condSQL)
+				} else {
+					sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
+				}
+				args = condArgs
+			} else {
+				if session.engine.dialect.DBType() == core.MSSQL {
+					sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s", tableName)
+				} else if session.engine.dialect.DBType() == core.ORACLE {
+					sqlStr = fmt.Sprintf("SELECT * FROM  %s WHERE ROWNUM=1", tableName)
+				} else {
+					sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
+				}
+				args = []interface{}{}
+			}
+		} else {
+			beanValue := reflect.ValueOf(bean[0])
+			if beanValue.Kind() != reflect.Ptr {
+				return false, errors.New("needs a pointer")
+			}
+
+			if beanValue.Elem().Kind() == reflect.Struct {
+				if err := session.statement.setRefBean(bean[0]); err != nil {
+					return false, err
+				}
+			}
+
+			if len(session.statement.TableName()) <= 0 {
+				return false, ErrTableNotFound
+			}
+			session.statement.Limit(1)
+			sqlStr, args, err = session.statement.genGetSQL(bean[0])
+			if err != nil {
+				return false, err
+			}
+		}
+	} else {
+		sqlStr = session.statement.RawSQL
+		args = session.statement.RawParams
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	return rows.Next(), nil
+}

+ 503 - 0
vendor/gitea.com/xorm/xorm/session_find.go

@@ -0,0 +1,503 @@
+// 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"
+	"strings"
+
+	"xorm.io/builder"
+	"xorm.io/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 {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+	return session.find(rowsSlicePtr, condiBean...)
+}
+
+// FindAndCount find the results and also return the counts
+func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	session.autoResetStatement = false
+	err := session.find(rowsSlicePtr, condiBean...)
+	if err != nil {
+		return 0, err
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
+		return 0, errors.New("needs a pointer to a slice or a map")
+	}
+
+	sliceElementType := sliceValue.Type().Elem()
+	if sliceElementType.Kind() == reflect.Ptr {
+		sliceElementType = sliceElementType.Elem()
+	}
+	session.autoResetStatement = true
+
+	if session.statement.selectStr != "" {
+		session.statement.selectStr = ""
+	}
+	if session.statement.OrderStr != "" {
+		session.statement.OrderStr = ""
+	}
+
+	return session.Count(reflect.New(sliceElementType).Interface())
+}
+
+func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
+	if session.statement.lastError != nil {
+		return session.statement.lastError
+	}
+
+	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())
+				if err := session.statement.setRefValue(pv); err != nil {
+					return err
+				}
+			} else {
+				tp = tpNonStruct
+			}
+		} else if sliceElementType.Kind() == reflect.Struct {
+			pv := reflect.New(sliceElementType)
+			if err := session.statement.setRefValue(pv); err != nil {
+				return err
+			}
+		} 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 {
+				return 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
+				}
+
+				autoCond = session.engine.CondDeleted(colName)
+			}
+		}
+	}
+
+	var sqlStr string
+	var args []interface{}
+	var err error
+	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.engine.quoteColumns(session.statement.GroupByStr)
+					} else {
+						columnStr = session.statement.genColumnStr()
+					}
+				}
+			} else {
+				if columnStr == "" {
+					if session.statement.GroupByStr != "" {
+						columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
+					} else {
+						columnStr = "*"
+					}
+				}
+			}
+			if columnStr == "" {
+				columnStr = "*"
+			}
+		}
+
+		session.statement.cond = session.statement.cond.And(autoCond)
+		condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
+		if err != nil {
+			return err
+		}
+
+		args = append(session.statement.joinArgs, condArgs...)
+		sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
+		if err != nil {
+			return err
+		}
+		// 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
+	}
+
+	if session.canCache() {
+		if cacher := session.engine.getCacher(session.statement.TableName()); 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 {
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	fields, err := rows.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())
+		tb, err := session.engine.autoMapType(dataStruct)
+		if err != nil {
+			return err
+		}
+		err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
+		rows.Close()
+		if err != nil {
+			return err
+		}
+		return session.executeProcessors()
+	}
+
+	for rows.Next() {
+		var newValue = newElemFunc(fields)
+		bean := newValue.Interface()
+
+		switch elemType.Kind() {
+		case reflect.Slice:
+			err = rows.ScanSlice(bean)
+		case reflect.Map:
+			err = rows.ScanMap(bean)
+		default:
+			err = rows.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
+	}
+
+	tableName := session.statement.TableName()
+	cacher := session.engine.getCacher(tableName)
+	if cacher == nil {
+		return nil
+	}
+
+	for _, filter := range session.engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
+	}
+
+	newsql := session.statement.convertIDSQL(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+
+	table := session.statement.RefTable
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	if err != nil {
+		rows, err := session.queryRows(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() {
+				pk[i], err = session.engine.idTypeAssertion(col, res[i])
+				if err != nil {
+					return err
+				}
+			}
+
+			ids = append(ids, pk)
+		}
+
+		session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args)
+		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
+		if err != nil {
+			return err
+		}
+	} else {
+		session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, 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 || reflect.ValueOf(bean).Elem().Type() != t {
+			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 {
+		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])
+			}
+
+			session.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]})
+				}
+				session.Or(cond)
+			}
+		}
+
+		err = session.NoCache().Table(tableName).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, err := session.engine.idOfV(rv)
+			if err != nil {
+				return err
+			}
+			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
+}

+ 241 - 0
vendor/gitea.com/xorm/xorm/session_get.go

@@ -0,0 +1,241 @@
+// 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"
+	"strconv"
+
+	"xorm.io/core"
+)
+
+// Get retrieve one record from database, bean's non-empty fields
+// will be as conditions
+func (session *Session) Get(bean interface{}) (bool, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+	return session.get(bean)
+}
+
+func (session *Session) get(bean interface{}) (bool, error) {
+	if session.statement.lastError != nil {
+		return false, session.statement.lastError
+	}
+
+	beanValue := reflect.ValueOf(bean)
+	if beanValue.Kind() != reflect.Ptr {
+		return false, errors.New("needs a pointer to a value")
+	} else if beanValue.Elem().Kind() == reflect.Ptr {
+		return false, errors.New("a pointer to a pointer is not allowed")
+	}
+
+	if beanValue.Elem().Kind() == reflect.Struct {
+		if err := session.statement.setRefBean(bean); err != nil {
+			return false, err
+		}
+	}
+
+	var sqlStr string
+	var args []interface{}
+	var err error
+
+	if session.statement.RawSQL == "" {
+		if len(session.statement.TableName()) <= 0 {
+			return false, ErrTableNotFound
+		}
+		session.statement.Limit(1)
+		sqlStr, args, err = session.statement.genGetSQL(bean)
+		if err != nil {
+			return false, err
+		}
+	} else {
+		sqlStr = session.statement.RawSQL
+		args = session.statement.RawParams
+	}
+
+	table := session.statement.RefTable
+
+	if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
+		if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil &&
+			!session.statement.unscoped {
+			has, err := session.cacheGet(bean, sqlStr, args...)
+			if err != ErrCacheFailed {
+				return has, err
+			}
+		}
+	}
+
+	context := session.statement.context
+	if context != nil {
+		res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
+		if res != nil {
+			structValue := reflect.Indirect(reflect.ValueOf(bean))
+			structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
+			session.lastSQL = ""
+			session.lastSQLArgs = nil
+			return true, nil
+		}
+	}
+
+	has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
+	if err != nil || !has {
+		return has, err
+	}
+
+	if context != nil {
+		context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
+	}
+
+	return true, nil
+}
+
+func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if !rows.Next() {
+		if rows.Err() != nil {
+			return false, rows.Err()
+		}
+		return false, nil
+	}
+
+	switch bean.(type) {
+	case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
+		return true, rows.Scan(&bean)
+	case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
+		return true, rows.Scan(bean)
+	}
+
+	switch beanKind {
+	case reflect.Struct:
+		fields, err := rows.Columns()
+		if err != nil {
+			// WARN: Alougth rows return true, but get fields failed
+			return true, err
+		}
+
+		scanResults, err := session.row2Slice(rows, fields, bean)
+		if err != nil {
+			return false, err
+		}
+		// close it before covert data
+		rows.Close()
+
+		dataStruct := rValue(bean)
+		_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
+		if err != nil {
+			return true, err
+		}
+
+		return true, session.executeProcessors()
+	case reflect.Slice:
+		err = rows.ScanSlice(bean)
+	case reflect.Map:
+		err = rows.ScanMap(bean)
+	default:
+		err = rows.Scan(bean)
+	}
+
+	return true, err
+}
+
+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
+	}
+
+	tableName := session.statement.TableName()
+	cacher := session.engine.getCacher(tableName)
+
+	session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
+	table := session.statement.RefTable
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	if err != nil {
+		var res = make([]string, len(table.PrimaryKeys))
+		rows, err := session.NoCache().queryRows(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, ids)
+	}
+
+	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, table, 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
+}

+ 747 - 0
vendor/gitea.com/xorm/xorm/session_insert.go

@@ -0,0 +1,747 @@
+// 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"
+	"sort"
+	"strconv"
+	"strings"
+
+	"xorm.io/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()
+	}
+
+	for _, bean := range beans {
+		switch bean.(type) {
+		case map[string]interface{}:
+			cnt, err := session.insertMapInterface(bean.(map[string]interface{}))
+			if err != nil {
+				return affected, err
+			}
+			affected += cnt
+		case []map[string]interface{}:
+			s := bean.([]map[string]interface{})
+			session.autoResetStatement = false
+			for i := 0; i < len(s); i++ {
+				cnt, err := session.insertMapInterface(s[i])
+				if err != nil {
+					return affected, err
+				}
+				affected += cnt
+			}
+		case map[string]string:
+			cnt, err := session.insertMapString(bean.(map[string]string))
+			if err != nil {
+				return affected, err
+			}
+			affected += cnt
+		case []map[string]string:
+			s := bean.([]map[string]string)
+			session.autoResetStatement = false
+			for i := 0; i < len(s); i++ {
+				cnt, err := session.insertMapString(s[i])
+				if err != nil {
+					return affected, err
+				}
+				affected += cnt
+			}
+		default:
+			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")
+	}
+
+	if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
+		return 0, err
+	}
+
+	tableName := session.statement.TableName()
+	if len(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.omitColumnMap.contain(col.Name) {
+					continue
+				}
+				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+					continue
+				}
+				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
+					val, t := session.engine.nowTime(col)
+					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.omitColumnMap.contain(col.Name) {
+					continue
+				}
+				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+					continue
+				}
+				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
+					val, t := session.engine.nowTime(col)
+					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 string
+	if session.engine.dialect.DBType() == core.ORACLE {
+		temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
+			session.engine.Quote(tableName),
+			session.engine.QuoteStr(),
+			strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
+			session.engine.QuoteStr())
+		sql = fmt.Sprintf("INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL",
+			session.engine.Quote(tableName),
+			session.engine.QuoteStr(),
+			strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
+			session.engine.QuoteStr(),
+			strings.Join(colMultiPlaces, temp))
+	} else {
+		sql = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
+			session.engine.Quote(tableName),
+			session.engine.QuoteStr(),
+			strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
+			session.engine.QuoteStr(),
+			strings.Join(colMultiPlaces, "),("))
+	}
+	res, err := session.exec(sql, args...)
+	if err != nil {
+		return 0, err
+	}
+
+	session.cacheInsert(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) {
+	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) {
+	if err := session.statement.setRefBean(bean); err != nil {
+		return 0, err
+	}
+	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 := session.genInsertColumns(bean)
+	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 {
+		if len(colPlaces) > 0 {
+			colPlaces = colPlaces[0 : len(colPlaces)-2]
+		}
+	}
+
+	var sqlStr string
+	var tableName = session.statement.TableName()
+	var output string
+	if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
+		output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
+	}
+	if len(colPlaces) > 0 {
+		sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v)%s VALUES (%v)",
+			session.engine.Quote(tableName),
+			session.engine.QuoteStr(),
+			strings.Join(colNames, session.engine.Quote(", ")),
+			session.engine.QuoteStr(),
+			output,
+			colPlaces)
+	} else {
+		if session.engine.dialect.DBType() == core.MYSQL {
+			sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName))
+		} else {
+			sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output)
+		}
+	}
+
+	if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
+		sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement)
+	}
+
+	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 {
+		res, err := session.queryBytes("select seq_atable.currval from dual", args...)
+		if err != nil {
+			return 0, err
+		}
+
+		defer handleAfterInsertProcessorFunc(bean)
+
+		session.cacheInsert(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() {
+				session.incrVersionFieldValue(verValue)
+			}
+		}
+
+		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 len(table.AutoIncrement) > 0 && (session.engine.dialect.DBType() == core.POSTGRES || session.engine.dialect.DBType() == core.MSSQL) {
+		res, err := session.queryBytes(sqlStr, args...)
+
+		if err != nil {
+			return 0, err
+		}
+		defer handleAfterInsertProcessorFunc(bean)
+
+		session.cacheInsert(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() {
+				session.incrVersionFieldValue(verValue)
+			}
+		}
+
+		if len(res) < 1 {
+			return 0, errors.New("insert successfully 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)
+
+		session.cacheInsert(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() {
+				session.incrVersionFieldValue(verValue)
+			}
+		}
+
+		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) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.innerInsert(bean)
+}
+
+func (session *Session) cacheInsert(table string) error {
+	if !session.statement.UseCache {
+		return nil
+	}
+	cacher := session.engine.getCacher(table)
+	if cacher == nil {
+		return nil
+	}
+	session.engine.logger.Debug("[cache] clear sql:", table)
+	cacher.ClearIds(table)
+	return nil
+}
+
+// genInsertColumns generates insert needed columns
+func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
+	table := session.statement.RefTable
+	colNames := make([]string, 0, len(table.ColumnsSeq()))
+	args := make([]interface{}, 0, len(table.ColumnsSeq()))
+
+	for _, col := range table.Columns() {
+		if col.MapType == core.ONLYFROMDB {
+			continue
+		}
+
+		if col.IsDeleted {
+			continue
+		}
+
+		if session.statement.omitColumnMap.contain(col.Name) {
+			continue
+		}
+
+		if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
+			continue
+		}
+
+		if _, ok := session.statement.incrColumns[col.Name]; ok {
+			continue
+		} else if _, ok := session.statement.decrColumns[col.Name]; ok {
+			continue
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			return nil, nil, err
+		}
+		fieldValue := *fieldValuePtr
+
+		if col.IsAutoIncrement {
+			switch fieldValue.Type().Kind() {
+			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
+				if fieldValue.Int() == 0 {
+					continue
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
+				if fieldValue.Uint() == 0 {
+					continue
+				}
+			case reflect.String:
+				if len(fieldValue.String()) == 0 {
+					continue
+				}
+			case reflect.Ptr:
+				if fieldValue.Pointer() == 0 {
+					continue
+				}
+			}
+		}
+
+		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
+		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
+			if col.Nullable && isZero(fieldValue.Interface()) {
+				var nilValue *int
+				fieldValue = reflect.ValueOf(nilValue)
+			}
+		}
+
+		if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
+			// if time is non-empty, then set to auto time
+			val, t := session.engine.nowTime(col)
+			args = append(args, val)
+
+			var colName = col.Name
+			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+				col := table.GetColumn(colName)
+				setColumnTime(bean, col, t)
+			})
+		} else if col.IsVersion && session.statement.checkVersion {
+			args = append(args, 1)
+		} else {
+			arg, err := session.value2Interface(col, fieldValue)
+			if err != nil {
+				return colNames, args, err
+			}
+			args = append(args, arg)
+		}
+
+		colNames = append(colNames, col.Name)
+	}
+	return colNames, args, nil
+}
+
+func (session *Session) insertMapInterface(m map[string]interface{}) (int64, error) {
+	if len(m) == 0 {
+		return 0, ErrParamsType
+	}
+
+	var columns = make([]string, 0, len(m))
+	for k := range m {
+		columns = append(columns, k)
+	}
+	sort.Strings(columns)
+
+	qm := strings.Repeat("?,", len(columns))
+	qm = "(" + qm[:len(qm)-1] + ")"
+
+	tableName := session.statement.TableName()
+	if len(tableName) <= 0 {
+		return 0, ErrTableNotFound
+	}
+
+	var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)
+	var args = make([]interface{}, 0, len(m))
+	for _, colName := range columns {
+		args = append(args, m[colName])
+	}
+
+	if err := session.cacheInsert(tableName); err != nil {
+		return 0, err
+	}
+
+	res, err := session.exec(sql, args...)
+	if err != nil {
+		return 0, err
+	}
+	affected, err := res.RowsAffected()
+	if err != nil {
+		return 0, err
+	}
+	return affected, nil
+}
+
+func (session *Session) insertMapString(m map[string]string) (int64, error) {
+	if len(m) == 0 {
+		return 0, ErrParamsType
+	}
+
+	var columns = make([]string, 0, len(m))
+	for k := range m {
+		columns = append(columns, k)
+	}
+	sort.Strings(columns)
+
+	qm := strings.Repeat("?,", len(columns))
+	qm = "(" + qm[:len(qm)-1] + ")"
+
+	tableName := session.statement.TableName()
+	if len(tableName) <= 0 {
+		return 0, ErrTableNotFound
+	}
+
+	var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)
+	var args = make([]interface{}, 0, len(m))
+	for _, colName := range columns {
+		args = append(args, m[colName])
+	}
+
+	if err := session.cacheInsert(tableName); err != nil {
+		return 0, err
+	}
+
+	res, err := session.exec(sql, args...)
+	if err != nil {
+		return 0, err
+	}
+	affected, err := res.RowsAffected()
+	if err != nil {
+		return 0, err
+	}
+	return affected, nil
+}

+ 100 - 0
vendor/gitea.com/xorm/xorm/session_iterate.go

@@ -0,0 +1,100 @@
+// 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 {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	if session.statement.lastError != nil {
+		return session.statement.lastError
+	}
+
+	if session.statement.bufferSize > 0 {
+		return session.bufferIterate(bean, fun)
+	}
+
+	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
+}
+
+// BufferSize sets the buffersize for iterate
+func (session *Session) BufferSize(size int) *Session {
+	session.statement.bufferSize = size
+	return session
+}
+
+func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	var bufferSize = session.statement.bufferSize
+	var limit = session.statement.LimitN
+	if limit > 0 && bufferSize > limit {
+		bufferSize = limit
+	}
+	var start = session.statement.Start
+	v := rValue(bean)
+	sliceType := reflect.SliceOf(v.Type())
+	var idx = 0
+	for {
+		slice := reflect.New(sliceType)
+		if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil {
+			return err
+		}
+
+		for i := 0; i < slice.Elem().Len(); i++ {
+			if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil {
+				return err
+			}
+			idx++
+		}
+
+		start = start + slice.Elem().Len()
+		if limit > 0 && idx+bufferSize > limit {
+			bufferSize = limit - idx
+		}
+
+		if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit {
+			break
+		}
+	}
+
+	return nil
+}

+ 320 - 0
vendor/gitea.com/xorm/xorm/session_query.go

@@ -0,0 +1,320 @@
+// 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"
+
+	"xorm.io/builder"
+	"xorm.io/core"
+)
+
+func (session *Session) genQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
+	if len(sqlOrArgs) > 0 {
+		return convertSQLOrArgs(sqlOrArgs...)
+	}
+
+	if session.statement.RawSQL != "" {
+		return session.statement.RawSQL, session.statement.RawParams, nil
+	}
+
+	if len(session.statement.TableName()) <= 0 {
+		return "", nil, 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.engine.quoteColumns(session.statement.GroupByStr)
+				} else {
+					columnStr = session.statement.genColumnStr()
+				}
+			}
+		} else {
+			if columnStr == "" {
+				if session.statement.GroupByStr != "" {
+					columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
+				} else {
+					columnStr = "*"
+				}
+			}
+		}
+		if columnStr == "" {
+			columnStr = "*"
+		}
+	}
+
+	if err := session.statement.processIDParam(); err != nil {
+		return "", nil, err
+	}
+
+	condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
+	if err != nil {
+		return "", nil, err
+	}
+
+	args := append(session.statement.joinArgs, condArgs...)
+	sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
+	if err != nil {
+		return "", nil, err
+	}
+	// for mssql and use limit
+	qs := strings.Count(sqlStr, "?")
+	if len(args)*2 == qs {
+		args = append(args, args...)
+	}
+
+	return sqlStr, args, nil
+}
+
+// Query runs a raw sql and return records as []map[string][]byte
+func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	return session.queryBytes(sqlStr, args...)
+}
+
+func value2String(rawValue *reflect.Value) (str string, err error) {
+	aa := reflect.TypeOf((*rawValue).Interface())
+	vv := reflect.ValueOf((*rawValue).Interface())
+	switch aa.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		str = strconv.FormatInt(vv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		str = strconv.FormatUint(vv.Uint(), 10)
+	case reflect.Float32, reflect.Float64:
+		str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
+	case reflect.String:
+		str = vv.String()
+	case reflect.Array, reflect.Slice:
+		switch aa.Elem().Kind() {
+		case reflect.Uint8:
+			data := rawValue.Interface().([]byte)
+			str = string(data)
+			if str == "\x00" {
+				str = "0"
+			}
+		default:
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	// time type
+	case reflect.Struct:
+		if aa.ConvertibleTo(core.TimeType) {
+			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
+		} else {
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	case reflect.Bool:
+		str = strconv.FormatBool(vv.Bool())
+	case reflect.Complex128, reflect.Complex64:
+		str = fmt.Sprintf("%v", vv.Complex())
+	/* TODO: unsupported types below
+	   case reflect.Map:
+	   case reflect.Ptr:
+	   case reflect.Uintptr:
+	   case reflect.UnsafePointer:
+	   case reflect.Chan, reflect.Func, reflect.Interface:
+	*/
+	default:
+		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+	}
+	return
+}
+
+func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
+	result := make(map[string]string)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		// if row is null then as empty string
+		if rawValue.Interface() == nil {
+			result[key] = ""
+			continue
+		}
+
+		if data, err := value2String(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err
+		}
+	}
+	return result, nil
+}
+
+func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) {
+	result := make([]string, 0, len(fields))
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for i := 0; i < len(fields); i++ {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i]))
+		// if row is null then as empty string
+		if rawValue.Interface() == nil {
+			result = append(result, "")
+			continue
+		}
+
+		if data, err := value2String(&rawValue); err == nil {
+			result = append(result, data)
+		} else {
+			return nil, err
+		}
+	}
+	return result, nil
+}
+
+func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapStr(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		record, err := row2sliceStr(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, record)
+	}
+
+	return resultsSlice, nil
+}
+
+// QueryString runs a raw sql and return records as []map[string]string
+func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2Strings(rows)
+}
+
+// QuerySliceString runs a raw sql and return records as [][]string
+func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2SliceString(rows)
+}
+
+func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
+	resultsMap = make(map[string]interface{}, len(fields))
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface()
+	}
+	return
+}
+
+func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapInterface(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+// QueryInterface runs a raw sql and return records as []map[string]interface{}
+func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2Interfaces(rows)
+}

+ 227 - 0
vendor/gitea.com/xorm/xorm/session_raw.go

@@ -0,0 +1,227 @@
+// 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"
+	"reflect"
+	"time"
+
+	"xorm.io/builder"
+	"xorm.io/core"
+)
+
+func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
+	for _, filter := range session.engine.dialect.Filters() {
+		*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
+	}
+
+	session.lastSQL = *sqlStr
+	session.lastSQLArgs = paramStr
+}
+
+func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
+	defer session.resetStatement()
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	if session.engine.showSQL {
+		if session.engine.showExecTime {
+			b4ExecTime := time.Now()
+			defer func() {
+				execDuration := time.Since(b4ExecTime)
+				if len(args) > 0 {
+					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
+				} else {
+					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
+				}
+			}()
+		} else {
+			if len(args) > 0 {
+				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
+			} else {
+				session.engine.logger.Infof("[SQL] %v", sqlStr)
+			}
+		}
+	}
+
+	if session.isAutoCommit {
+		var db *core.DB
+		if session.sessionType == groupSession {
+			db = session.engine.engineGroup.Slave().DB()
+		} else {
+			db = session.DB()
+		}
+
+		if session.prepareStmt {
+			// don't clear stmt since session will cache them
+			stmt, err := session.doPrepare(db, sqlStr)
+			if err != nil {
+				return nil, err
+			}
+
+			rows, err := stmt.QueryContext(session.ctx, args...)
+			if err != nil {
+				return nil, err
+			}
+			return rows, nil
+		}
+
+		rows, err := db.QueryContext(session.ctx, sqlStr, args...)
+		if err != nil {
+			return nil, err
+		}
+		return rows, nil
+	}
+
+	rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	return rows, nil
+}
+
+func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
+	return core.NewRow(session.queryRows(sqlStr, args...))
+}
+
+func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
+	str, err := value2String(rawValue)
+	if err != nil {
+		return nil, err
+	}
+	return []byte(str), nil
+}
+
+func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
+	result := make(map[string][]byte)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			result[key] = []byte{}
+			continue
+		}
+
+		if data, err := value2Bytes(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+	}
+	return result, nil
+}
+
+func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2map(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2maps(rows)
+}
+
+func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	defer session.resetStatement()
+
+	session.queryPreprocess(&sqlStr, args...)
+
+	if session.engine.showSQL {
+		if session.engine.showExecTime {
+			b4ExecTime := time.Now()
+			defer func() {
+				execDuration := time.Since(b4ExecTime)
+				if len(args) > 0 {
+					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
+				} else {
+					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
+				}
+			}()
+		} else {
+			if len(args) > 0 {
+				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
+			} else {
+				session.engine.logger.Infof("[SQL] %v", sqlStr)
+			}
+		}
+	}
+
+	if !session.isAutoCommit {
+		return session.tx.ExecContext(session.ctx, sqlStr, args...)
+	}
+
+	if session.prepareStmt {
+		stmt, err := session.doPrepare(session.DB(), sqlStr)
+		if err != nil {
+			return nil, err
+		}
+
+		res, err := stmt.ExecContext(session.ctx, args...)
+		if err != nil {
+			return nil, err
+		}
+		return res, nil
+	}
+
+	return session.DB().ExecContext(session.ctx, sqlStr, args...)
+}
+
+func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
+	switch sqlOrArgs[0].(type) {
+	case string:
+		return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
+	case *builder.Builder:
+		return sqlOrArgs[0].(*builder.Builder).ToSQL()
+	case builder.Builder:
+		bd := sqlOrArgs[0].(builder.Builder)
+		return bd.ToSQL()
+	}
+
+	return "", nil, ErrUnSupportedType
+}
+
+// Exec raw sql
+func (session *Session) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	if len(sqlOrArgs) == 0 {
+		return nil, ErrUnSupportedType
+	}
+
+	sqlStr, args, err := convertSQLOrArgs(sqlOrArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	return session.exec(sqlStr, args...)
+}

+ 421 - 0
vendor/gitea.com/xorm/xorm/session_schema.go

@@ -0,0 +1,421 @@
+// 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"
+	"fmt"
+	"strings"
+
+	"xorm.io/core"
+)
+
+// Ping test if database is ok
+func (session *Session) Ping() error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
+	return session.DB().PingContext(session.ctx)
+}
+
+// CreateTable create a table according a bean
+func (session *Session) CreateTable(bean interface{}) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.createTable(bean)
+}
+
+func (session *Session) createTable(bean interface{}) error {
+	if err := session.statement.setRefBean(bean); err != nil {
+		return err
+	}
+
+	sqlStr := session.statement.genCreateTableSQL()
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// CreateIndexes create indexes
+func (session *Session) CreateIndexes(bean interface{}) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.createIndexes(bean)
+}
+
+func (session *Session) createIndexes(bean interface{}) error {
+	if err := session.statement.setRefBean(bean); err != nil {
+		return err
+	}
+
+	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 {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+	return session.createUniques(bean)
+}
+
+func (session *Session) createUniques(bean interface{}) error {
+	if err := session.statement.setRefBean(bean); err != nil {
+		return err
+	}
+
+	sqls := session.statement.genUniqueSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// DropIndexes drop indexes
+func (session *Session) DropIndexes(bean interface{}) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.dropIndexes(bean)
+}
+
+func (session *Session) dropIndexes(bean interface{}) error {
+	if err := session.statement.setRefBean(bean); err != nil {
+		return err
+	}
+
+	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 {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.dropTable(beanOrTableName)
+}
+
+func (session *Session) dropTable(beanOrTableName interface{}) error {
+	tableName := session.engine.TableName(beanOrTableName)
+	var needDrop = true
+	if !session.engine.dialect.SupportDropIfExists() {
+		sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
+		results, err := session.queryBytes(sqlStr, args...)
+		if err != nil {
+			return err
+		}
+		needDrop = len(results) > 0
+	}
+
+	if needDrop {
+		sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
+		_, err := session.exec(sqlStr)
+		return err
+	}
+	return nil
+}
+
+// IsTableExist if a table is exist
+func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	tableName := session.engine.TableName(beanOrTableName)
+
+	return session.isTableExist(tableName)
+}
+
+func (session *Session) isTableExist(tableName string) (bool, error) {
+	sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
+	results, err := session.queryBytes(sqlStr, args...)
+	return len(results) > 0, err
+}
+
+// IsTableEmpty if table have any records
+func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+	return session.isTableEmpty(session.engine.TableName(bean))
+}
+
+func (session *Session) isTableEmpty(tableName string) (bool, error) {
+	var total int64
+	sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
+	err := session.queryRow(sqlStr).Scan(&total)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			err = nil
+		}
+		return true, err
+	}
+
+	return total == 0, nil
+}
+
+// find if index is exist according cols
+func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
+	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 {
+	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 {
+	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 {
+	index := session.statement.RefTable.Indexes[uqeName]
+	sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// Sync2 synchronize structs to database tables
+func (session *Session) Sync2(beans ...interface{}) error {
+	engine := session.engine
+
+	if session.isAutoClose {
+		session.isAutoClose = false
+		defer session.Close()
+	}
+
+	tables, err := engine.DBMetas()
+	if err != nil {
+		return err
+	}
+
+	session.autoResetStatement = false
+	defer func() {
+		session.autoResetStatement = true
+		session.resetStatement()
+	}()
+
+	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)
+		tbName := engine.TableName(bean)
+		tbNameWithSchema := engine.TableName(tbName, true)
+
+		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",
+									tbNameWithSchema, col.Name, curType, expectedType)
+								_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
+							} else {
+								engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
+									tbNameWithSchema, col.Name, curType, expectedType)
+							}
+						} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
+							if engine.dialect.DBType() == core.MYSQL {
+								if oriCol.Length < col.Length {
+									engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
+										tbNameWithSchema, col.Name, oriCol.Length, col.Length)
+									_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
+								}
+							}
+						} else {
+							if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
+								engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
+									tbNameWithSchema, col.Name, curType, expectedType)
+							}
+						}
+					} else if expectedType == core.Varchar {
+						if engine.dialect.DBType() == core.MYSQL {
+							if oriCol.Length < col.Length {
+								engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
+									tbNameWithSchema, col.Name, oriCol.Length, col.Length)
+								_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, 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.statement.RefTable = table
+					session.statement.tableName = tbNameWithSchema
+					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(tbNameWithSchema, oriIndex)
+						_, err = session.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(tbNameWithSchema, index2)
+					_, err = session.exec(sql)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			for name, index := range addedNames {
+				if index.Type == core.UniqueType {
+					session.statement.RefTable = table
+					session.statement.tableName = tbNameWithSchema
+					err = session.addUnique(tbNameWithSchema, name)
+				} else if index.Type == core.IndexType {
+					session.statement.RefTable = table
+					session.statement.tableName = tbNameWithSchema
+					err = session.addIndex(tbNameWithSchema, 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", engine.TableName(table.Name, true), colName)
+			}
+		}
+	}
+	return nil
+}

+ 98 - 0
vendor/gitea.com/xorm/xorm/session_stats.go

@@ -0,0 +1,98 @@
+// 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"
+	"reflect"
+)
+
+// Count counts the records. bean's non-empty fields
+// are conditions.
+func (session *Session) Count(bean ...interface{}) (int64, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	var err error
+	if session.statement.RawSQL == "" {
+		sqlStr, args, err = session.statement.genCountSQL(bean...)
+		if err != nil {
+			return 0, err
+		}
+	} else {
+		sqlStr = session.statement.RawSQL
+		args = session.statement.RawParams
+	}
+
+	var total int64
+	err = session.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(res interface{}, bean interface{}, columnNames ...string) error {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	v := reflect.ValueOf(res)
+	if v.Kind() != reflect.Ptr {
+		return errors.New("need a pointer to a variable")
+	}
+
+	var isSlice = v.Elem().Kind() == reflect.Slice
+	var sqlStr string
+	var args []interface{}
+	var err error
+	if len(session.statement.RawSQL) == 0 {
+		sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...)
+		if err != nil {
+			return err
+		}
+	} else {
+		sqlStr = session.statement.RawSQL
+		args = session.statement.RawParams
+	}
+
+	if isSlice {
+		err = session.queryRow(sqlStr, args...).ScanSlice(res)
+	} else {
+		err = session.queryRow(sqlStr, args...).Scan(res)
+	}
+	if err == sql.ErrNoRows || err == nil {
+		return nil
+	}
+	return err
+}
+
+// Sum call sum some column. bean's non-empty fields are conditions.
+func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) {
+	return res, session.sum(&res, bean, columnName)
+}
+
+// SumInt call sum some column. bean's non-empty fields are conditions.
+func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) {
+	return res, session.sum(&res, bean, columnName)
+}
+
+// Sums call sum some columns. bean's non-empty fields are conditions.
+func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
+	var res = make([]float64, len(columnNames), len(columnNames))
+	return res, session.sum(&res, bean, columnNames...)
+}
+
+// SumsInt sum specify columns and return as []int64 instead of []float64
+func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
+	var res = make([]int64, len(columnNames), len(columnNames))
+	return res, session.sum(&res, bean, columnNames...)
+}

+ 83 - 0
vendor/gitea.com/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().BeginTx(session.ctx, nil)
+		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
+		session.isAutoCommit = 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
+		session.isAutoCommit = 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
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä