double.huang преди 5 години
родител
ревизия
8c8af94991
променени са 29 файла, в които са добавени 1183 реда и са изтрити 297 реда
  1. 4 0
      demo/go.sum
  2. 31 2
      packages/xormplus/xorm/core/tx.go
  3. 1 1
      packages/xormplus/xorm/dialects/dialect.go
  4. 6 0
      packages/xormplus/xorm/dialects/gen_reserved.sh
  5. 64 3
      packages/xormplus/xorm/dialects/mssql.go
  6. 15 6
      packages/xormplus/xorm/dialects/mysql.go
  7. 2 2
      packages/xormplus/xorm/dialects/oracle.go
  8. 746 0
      packages/xormplus/xorm/dialects/pg_reserved.txt
  9. 6 2
      packages/xormplus/xorm/dialects/postgres.go
  10. 1 1
      packages/xormplus/xorm/dialects/sqlite3.go
  11. 88 127
      packages/xormplus/xorm/engine.go
  12. 52 52
      packages/xormplus/xorm/engine_group.go
  13. 23 23
      packages/xormplus/xorm/engine_group_policy.go
  14. 8 1
      packages/xormplus/xorm/integrations/tests.go
  15. 1 0
      packages/xormplus/xorm/interface.go
  16. 21 1
      packages/xormplus/xorm/internal/statements/pk.go
  17. 1 1
      packages/xormplus/xorm/internal/statements/update.go
  18. 14 11
      packages/xormplus/xorm/internal/statements/values.go
  19. 1 0
      packages/xormplus/xorm/log/logger_context.go
  20. 16 0
      packages/xormplus/xorm/schemas/column.go
  21. 3 5
      packages/xormplus/xorm/schemas/quote.go
  22. 50 6
      packages/xormplus/xorm/schemas/table.go
  23. 9 1
      packages/xormplus/xorm/session.go
  24. 13 4
      packages/xormplus/xorm/session_find.go
  25. 2 2
      packages/xormplus/xorm/session_plus.go
  26. 1 1
      packages/xormplus/xorm/session_raw.go
  27. 2 43
      packages/xormplus/xorm/session_tx.go
  28. 1 1
      packages/xormplus/xorm/xorm.go
  29. 1 1
      packages/xormplus/xorm/xormplus.go

+ 4 - 0
demo/go.sum

@@ -1,6 +1,7 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Chronokeeper/anyxml v0.0.0-20160530174208-54457d8e98c6/go.mod h1:YzuYAe2hrrwKXkM9kqjbkTLlkbA+/xw2MA46f1+ENxc=
 github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
@@ -138,6 +139,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/memcachier/mc v2.0.1+incompatible h1:s8EDz0xrJLP8goitwZOoq1vA/sm0fPS4X3KAF0nyhWQ=
 github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
@@ -219,6 +221,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xormplus/builder v0.0.0-20200331055651-240ff40009be/go.mod h1:PgBA7NoHtnttVkWModa/qpvIWkX6MpOKgyRCWsSKSB0=
+github.com/xormplus/xorm v0.0.0-20200912034818-5d90dcd4e3d6/go.mod h1:+v6b10b4x5IcQmp1/Cbo9IqaknxVeuhQng+fhya6bdI=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=

+ 31 - 2
packages/xormplus/xorm/core/tx.go

@@ -18,7 +18,8 @@ var (
 // Tx represents a transaction
 type Tx struct {
 	*sql.Tx
-	db *DB
+	db  *DB
+	ctx context.Context
 }
 
 func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
@@ -32,13 +33,41 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
 	if err := db.afterProcess(hookCtx); err != nil {
 		return nil, err
 	}
-	return &Tx{tx, db}, nil
+	return &Tx{tx, db, ctx}, nil
 }
 
 func (db *DB) Begin() (*Tx, error) {
 	return db.BeginTx(context.Background(), nil)
 }
 
+func (tx *Tx) Commit() error {
+	hookCtx := contexts.NewContextHook(tx.ctx, "COMMIT", nil)
+	ctx, err := tx.db.beforeProcess(hookCtx)
+	if err != nil {
+		return err
+	}
+	err = tx.Tx.Commit()
+	hookCtx.End(ctx, nil, err)
+	if err := tx.db.afterProcess(hookCtx); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (tx *Tx) Rollback() error {
+	hookCtx := contexts.NewContextHook(tx.ctx, "ROLLBACK", nil)
+	ctx, err := tx.db.beforeProcess(hookCtx)
+	if err != nil {
+		return err
+	}
+	err = tx.Tx.Rollback()
+	hookCtx.End(ctx, nil, err)
+	if err := tx.db.afterProcess(hookCtx); err != nil {
+		return err
+	}
+	return nil
+}
+
 func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
 	names := make(map[string]int)
 	var i int

+ 1 - 1
packages/xormplus/xorm/dialects/dialect.go

@@ -207,7 +207,7 @@ func regDrvsNDialects() bool {
 		"pgx":      {"postgres", func() Driver { return &pqDriverPgx{} }, func() Dialect { return &postgres{} }},
 		"sqlite3":  {"sqlite3", func() Driver { return &sqlite3Driver{} }, func() Dialect { return &sqlite3{} }},
 		"oci8":     {"oracle", func() Driver { return &oci8Driver{} }, func() Dialect { return &oracle{} }},
-		"goracle":  {"oracle", func() Driver { return &goracleDriver{} }, func() Dialect { return &oracle{} }},
+		"godror":   {"oracle", func() Driver { return &godrorDriver{} }, func() Dialect { return &oracle{} }},
 	}
 
 	for driverName, v := range providedDrvsNDialects {

+ 6 - 0
packages/xormplus/xorm/dialects/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

+ 64 - 3
packages/xormplus/xorm/dialects/mssql.go

@@ -214,6 +214,8 @@ var (
 
 type mssql struct {
 	Base
+	defaultVarchar string
+	defaultChar    string
 }
 
 func (db *mssql) Init(uri *URI) error {
@@ -221,6 +223,34 @@ func (db *mssql) Init(uri *URI) error {
 	return db.Base.Init(db, uri)
 }
 
+func (db *mssql) SetParams(params map[string]string) {
+	defaultVarchar, ok := params["DEFAULT_VARCHAR"]
+	if ok {
+		var t = strings.ToUpper(defaultVarchar)
+		switch t {
+		case "NVARCHAR", "VARCHAR":
+			db.defaultVarchar = t
+		default:
+			db.defaultVarchar = "VARCHAR"
+		}
+	} else {
+		db.defaultVarchar = "VARCHAR"
+	}
+
+	defaultChar, ok := params["DEFAULT_CHAR"]
+	if ok {
+		var t = strings.ToUpper(defaultChar)
+		switch t {
+		case "NCHAR", "CHAR":
+			db.defaultChar = t
+		default:
+			db.defaultChar = "CHAR"
+		}
+	} else {
+		db.defaultChar = "CHAR"
+	}
+}
+
 func (db *mssql) SQLType(c *schemas.Column) string {
 	var res string
 	switch t := c.SQLType.Name; t {
@@ -231,6 +261,7 @@ func (db *mssql) SQLType(c *schemas.Column) string {
 		} else if strings.EqualFold(c.Default, "false") {
 			c.Default = "0"
 		}
+		return res
 	case schemas.Serial:
 		c.IsAutoIncrement = true
 		c.IsPrimaryKey = true
@@ -254,7 +285,7 @@ func (db *mssql) SQLType(c *schemas.Column) string {
 	case schemas.MediumInt:
 		res = schemas.Int
 	case schemas.Text, schemas.MediumText, schemas.TinyText, schemas.LongText, schemas.Json:
-		res = schemas.Varchar + "(MAX)"
+		res = db.defaultVarchar + "(MAX)"
 	case schemas.Double:
 		res = schemas.Real
 	case schemas.Uuid:
@@ -266,12 +297,32 @@ func (db *mssql) SQLType(c *schemas.Column) string {
 	case schemas.BigInt:
 		res = schemas.BigInt
 		c.Length = 0
+	case schemas.NVarchar:
+		res = t
+		if c.Length == -1 {
+			res += "(MAX)"
+		}
+	case schemas.Varchar:
+		res = db.defaultVarchar
+		if c.Length == -1 {
+			res += "(MAX)"
+		}
+	case schemas.Char:
+		res = db.defaultChar
+		if c.Length == -1 {
+			res += "(MAX)"
+		}
+	case schemas.NChar:
+		res = t
+		if c.Length == -1 {
+			res += "(MAX)"
+		}
 	default:
 		res = t
 	}
 
-	if res == schemas.Int {
-		return schemas.Int
+	if res == schemas.Int || res == schemas.Bit || res == schemas.DateTime {
+		return res
 	}
 
 	hasLen1 := (c.Length > 0)
@@ -389,8 +440,18 @@ func (db *mssql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
 			col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 		case "NVARCHAR":
 			col.SQLType = schemas.SQLType{Name: schemas.NVarchar, DefaultLength: 0, DefaultLength2: 0}
+			if col.Length > 0 {
+				col.Length /= 2
+				col.Length2 /= 2
+			}
 		case "IMAGE":
 			col.SQLType = schemas.SQLType{Name: schemas.VarBinary, DefaultLength: 0, DefaultLength2: 0}
+		case "NCHAR":
+			if col.Length > 0 {
+				col.Length /= 2
+				col.Length2 /= 2
+			}
+			fallthrough
 		default:
 			if _, ok := schemas.SqlTypes[ct]; ok {
 				col.SQLType = schemas.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}

+ 15 - 6
packages/xormplus/xorm/dialects/mysql.go

@@ -307,9 +307,17 @@ func (db *mysql) AddColumnSQL(tableName string, col *schemas.Column) string {
 
 func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
 	args := []interface{}{db.uri.DBName, tableName}
+	alreadyQuoted := "(INSTR(VERSION(), 'maria') > 0 && " +
+		"(SUBSTRING_INDEX(VERSION(), '.', 1) > 10 || " +
+		"(SUBSTRING_INDEX(VERSION(), '.', 1) = 10 && " +
+		"(SUBSTRING_INDEX(SUBSTRING(VERSION(), 4), '.', 1) > 2 || " +
+		"(SUBSTRING_INDEX(SUBSTRING(VERSION(), 4), '.', 1) = 2 && " +
+		"SUBSTRING_INDEX(SUBSTRING(VERSION(), 6), '-', 1) >= 7)))))"
 	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` = ?" +
-		" ORDER BY `INFORMATION_SCHEMA`.`COLUMNS`.ORDINAL_POSITION"
+		" `COLUMN_KEY`, `EXTRA`, `COLUMN_COMMENT`, " +
+		alreadyQuoted + " AS NEEDS_QUOTE " +
+		"FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" +
+		" ORDER BY `COLUMNS`.ORDINAL_POSITION"
 
 	rows, err := queryer.QueryContext(ctx, s, args...)
 	if err != nil {
@@ -324,8 +332,9 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
 		col.Indexes = make(map[string]int)
 
 		var columnName, isNullable, colType, colKey, extra, comment string
+		var alreadyQuoted bool
 		var colDefault *string
-		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
+		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment, &alreadyQuoted)
 		if err != nil {
 			return nil, nil, err
 		}
@@ -335,7 +344,7 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
 			col.Nullable = true
 		}
 
-		if colDefault != nil {
+		if colDefault != nil && (!alreadyQuoted || *colDefault != "NULL") {
 			col.Default = *colDefault
 			col.DefaultIsEmpty = false
 		} else {
@@ -404,9 +413,9 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
 		}
 
 		if !col.DefaultIsEmpty {
-			if col.SQLType.IsText() {
+			if !alreadyQuoted && col.SQLType.IsText() {
 				col.Default = "'" + col.Default + "'"
-			} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
+			} else if col.SQLType.IsTime() && !alreadyQuoted && col.Default != "CURRENT_TIMESTAMP" {
 				col.Default = "'" + col.Default + "'"
 			}
 		}

+ 2 - 2
packages/xormplus/xorm/dialects/oracle.go

@@ -802,10 +802,10 @@ func (db *oracle) Filters() []Filter {
 	}
 }
 
-type goracleDriver struct {
+type godrorDriver struct {
 }
 
-func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*URI, error) {
+func (cfg *godrorDriver) Parse(driverName, dataSourceName string) (*URI, error) {
 	db := &URI{DBType: schemas.ORACLE}
 	dsnPattern := regexp.MustCompile(
 		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]

+ 746 - 0
packages/xormplus/xorm/dialects/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

+ 6 - 2
packages/xormplus/xorm/dialects/postgres.go

@@ -857,6 +857,8 @@ func (db *postgres) SQLType(c *schemas.Column) string {
 		res = schemas.Real
 	case schemas.TinyText, schemas.MediumText, schemas.LongText:
 		res = schemas.Text
+	case schemas.NChar:
+		res = schemas.Char
 	case schemas.NVarchar:
 		res = schemas.Varchar
 	case schemas.Uuid:
@@ -1015,7 +1017,7 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
 
 	schema := db.getSchema()
 	if schema != "" {
-		s = fmt.Sprintf(s, "AND s.table_schema = $2")
+		s = fmt.Sprintf(s, " AND s.table_schema = $2")
 		args = append(args, schema)
 	} else {
 		s = fmt.Sprintf(s, "")
@@ -1086,8 +1088,10 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
 		col.Nullable = (isNullable == "YES")
 
 		switch strings.ToLower(dataType) {
-		case "character varying", "character", "string":
+		case "character varying", "string":
 			col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 0, DefaultLength2: 0}
+		case "character":
+			col.SQLType = schemas.SQLType{Name: schemas.Char, DefaultLength: 0, DefaultLength2: 0}
 		case "timestamp without time zone":
 			col.SQLType = schemas.SQLType{Name: schemas.DateTime, DefaultLength: 0, DefaultLength2: 0}
 		case "timestamp with time zone":

+ 1 - 1
packages/xormplus/xorm/dialects/sqlite3.go

@@ -483,7 +483,7 @@ func (db *sqlite3) GetIndexes(queryer core.Queryer, ctx context.Context, tableNa
 			continue
 		}
 
-		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
+		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []'\"")
 		var isRegular bool
 		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 			index.Name = indexName[5+len(tableName):]

+ 88 - 127
packages/xormplus/xorm/engine.go

@@ -12,6 +12,8 @@ import (
 	"io"
 	"os"
 	"reflect"
+
+	//"runtime"
 	"strconv"
 	"strings"
 	"time"
@@ -95,10 +97,10 @@ func (engine *Engine) Logger() log.ContextLogger {
 func (engine *Engine) SetLogger(logger interface{}) {
 	var realLogger log.ContextLogger
 	switch t := logger.(type) {
-	case log.Logger:
-		realLogger = log.NewLoggerAdapter(t)
 	case log.ContextLogger:
 		realLogger = t
+	case log.Logger:
+		realLogger = log.NewLoggerAdapter(t)
 	}
 	engine.logger = realLogger
 	engine.DB().Logger = realLogger
@@ -370,6 +372,82 @@ func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
 	return engine.dumpTables(tables, w, tp...)
 }
 
+func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.Column) string {
+	if d == nil {
+		return "NULL"
+	}
+
+	if dq, ok := d.(bool); ok && (dstDialect.URI().DBType == schemas.SQLITE ||
+		dstDialect.URI().DBType == schemas.MSSQL) {
+		if dq {
+			return "1"
+		}
+		return "0"
+	}
+
+	if col.SQLType.IsText() {
+		var v = fmt.Sprintf("%s", d)
+		return "'" + strings.Replace(v, "'", "''", -1) + "'"
+	} else if col.SQLType.IsTime() {
+		var v = fmt.Sprintf("%s", d)
+		if strings.HasSuffix(v, " +0000 UTC") {
+			return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")])
+		} else if strings.HasSuffix(v, " +0000 +0000") {
+			return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 +0000")])
+		}
+		return "'" + strings.Replace(v, "'", "''", -1) + "'"
+	} else if col.SQLType.IsBlob() {
+		if reflect.TypeOf(d).Kind() == reflect.Slice {
+			return fmt.Sprintf("%s", dstDialect.FormatBytes(d.([]byte)))
+		} else if reflect.TypeOf(d).Kind() == reflect.String {
+			return fmt.Sprintf("'%s'", d.(string))
+		}
+	} else if col.SQLType.IsNumeric() {
+		switch reflect.TypeOf(d).Kind() {
+		case reflect.Slice:
+			if col.SQLType.Name == schemas.Bool {
+				return fmt.Sprintf("%v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
+			}
+			return fmt.Sprintf("%s", string(d.([]byte)))
+		case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
+			if col.SQLType.Name == schemas.Bool {
+				v := reflect.ValueOf(d).Int() > 0
+				if dstDialect.URI().DBType == schemas.SQLITE {
+					if v {
+						return "1"
+					}
+					return "0"
+				}
+				return fmt.Sprintf("%v", strconv.FormatBool(v))
+			}
+			return fmt.Sprintf("%v", d)
+		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			if col.SQLType.Name == schemas.Bool {
+				v := reflect.ValueOf(d).Uint() > 0
+				if dstDialect.URI().DBType == schemas.SQLITE {
+					if v {
+						return "1"
+					}
+					return "0"
+				}
+				return fmt.Sprintf("%v", strconv.FormatBool(v))
+			}
+			return fmt.Sprintf("%v", d)
+		default:
+			return fmt.Sprintf("%v", d)
+		}
+	}
+
+	s := fmt.Sprintf("%v", d)
+	if strings.Contains(s, ":") || strings.Contains(s, "-") {
+		if strings.HasSuffix(s, " +0000 UTC") {
+			return fmt.Sprintf("'%s'", s[0:len(s)-len(" +0000 UTC")])
+		}
+		return fmt.Sprintf("'%s'", s)
+	}
+	return s
+}
+
 // dumpTables dump database all table structs and data to w with specify db type
 func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
 	var dstDialect dialects.Dialect
@@ -382,7 +460,10 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
 		}
 
 		uri := engine.dialect.URI()
-		destURI := *uri
+		destURI := dialects.URI{
+			DBType: tp[0],
+			DBName: uri.DBName,
+		}
 		dstDialect.Init(&destURI)
 	}
 
@@ -453,59 +534,9 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
 				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", dstDialect.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 == schemas.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 == schemas.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 == schemas.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)
-					}
-				}
+				temp += "," + formatColumnValue(dstDialect, d, col)
 			}
-			_, err = io.WriteString(w, temp[2:]+");\n")
+			_, err = io.WriteString(w, temp[1:]+");\n")
 			if err != nil {
 				return err
 			}
@@ -774,81 +805,11 @@ func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
 	return session.IsTableExist(beanOrTableName)
 }
 
-// IDOf get id from one struct
-func (engine *Engine) IDOf(bean interface{}) (schemas.PK, error) {
-	return engine.IDOfV(reflect.ValueOf(bean))
-}
-
 // TableName returns table name with schema prefix if has
 func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
 	return dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean, includeSchema...)
 }
 
-// IDOfV get id from one value of struct
-func (engine *Engine) IDOfV(rv reflect.Value) (schemas.PK, error) {
-	return engine.idOfV(rv)
-}
-
-func (engine *Engine) idOfV(rv reflect.Value) (schemas.PK, error) {
-	v := reflect.Indirect(rv)
-	table, err := engine.tagParser.ParseWithCache(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 schemas.PK(pk), nil
-}
-
-func (engine *Engine) idTypeAssertion(col *schemas.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()
@@ -1305,11 +1266,11 @@ func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interf
 
 	result, err := f(session)
 	if err != nil {
-		return nil, err
+		return result, err
 	}
 
 	if err := session.Commit(); err != nil {
-		return nil, err
+		return result, err
 	}
 
 	return result, nil

+ 52 - 52
packages/xormplus/xorm/engine_group.go

@@ -18,8 +18,8 @@ import (
 // EngineGroup defines an engine group
 type EngineGroup struct {
 	*Engine
-	slaves []*Engine
-	policy GroupPolicy
+	subordinates []*Engine
+	policy       GroupPolicy
 }
 
 // NewEngineGroup creates a new engine group
@@ -45,19 +45,19 @@ func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolic
 		}
 
 		eg.Engine = engines[0]
-		eg.slaves = engines[1:]
+		eg.subordinates = engines[1:]
 		return &eg, nil
 	}
 
-	master, ok3 := args1.(*Engine)
-	slaves, ok4 := args2.([]*Engine)
+	main, ok3 := args1.(*Engine)
+	subordinates, ok4 := args2.([]*Engine)
 	if ok3 && ok4 {
-		master.engineGroup = &eg
-		for i := 0; i < len(slaves); i++ {
-			slaves[i].engineGroup = &eg
+		main.engineGroup = &eg
+		for i := 0; i < len(subordinates); i++ {
+			subordinates[i].engineGroup = &eg
 		}
-		eg.Engine = master
-		eg.slaves = slaves
+		eg.Engine = main
+		eg.subordinates = subordinates
 		return &eg, nil
 	}
 	return nil, ErrParamsType
@@ -70,8 +70,8 @@ func (eg *EngineGroup) Close() error {
 		return err
 	}
 
-	for i := 0; i < len(eg.slaves); i++ {
-		err := eg.slaves[i].Close()
+	for i := 0; i < len(eg.subordinates); i++ {
+		err := eg.subordinates[i].Close()
 		if err != nil {
 			return err
 		}
@@ -93,8 +93,8 @@ func (eg *EngineGroup) NewSession() *Session {
 	return sess
 }
 
-// Master returns the master engine
-func (eg *EngineGroup) Master() *Engine {
+// Main returns the main engine
+func (eg *EngineGroup) Main() *Engine {
 	return eg.Engine
 }
 
@@ -104,8 +104,8 @@ func (eg *EngineGroup) Ping() error {
 		return err
 	}
 
-	for _, slave := range eg.slaves {
-		if err := slave.Ping(); err != nil {
+	for _, subordinate := range eg.subordinates {
+		if err := subordinate.Ping(); err != nil {
 			return err
 		}
 	}
@@ -115,71 +115,71 @@ func (eg *EngineGroup) Ping() error {
 // SetColumnMapper set the column name mapping rule
 func (eg *EngineGroup) SetColumnMapper(mapper names.Mapper) {
 	eg.Engine.SetColumnMapper(mapper)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetColumnMapper(mapper)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetColumnMapper(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)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetConnMaxLifetime(d)
 	}
 }
 
 // SetDefaultCacher set the default cacher
 func (eg *EngineGroup) SetDefaultCacher(cacher caches.Cacher) {
 	eg.Engine.SetDefaultCacher(cacher)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetDefaultCacher(cacher)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetDefaultCacher(cacher)
 	}
 }
 
 // SetLogger set the new logger
 func (eg *EngineGroup) SetLogger(logger interface{}) {
 	eg.Engine.SetLogger(logger)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetLogger(logger)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetLogger(logger)
 	}
 }
 
 func (eg *EngineGroup) AddHook(hook contexts.Hook) {
 	eg.Engine.AddHook(hook)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].AddHook(hook)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].AddHook(hook)
 	}
 }
 
 // SetLogLevel sets the logger level
 func (eg *EngineGroup) SetLogLevel(level log.LogLevel) {
 	eg.Engine.SetLogLevel(level)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetLogLevel(level)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetLogLevel(level)
 	}
 }
 
 // SetMapper set the name mapping rules
 func (eg *EngineGroup) SetMapper(mapper names.Mapper) {
 	eg.Engine.SetMapper(mapper)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetMapper(mapper)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[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)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[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)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].DB().SetMaxOpenConns(conns)
 	}
 }
 
@@ -192,41 +192,41 @@ func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
 // SetQuotePolicy sets the special quote policy
 func (eg *EngineGroup) SetQuotePolicy(quotePolicy dialects.QuotePolicy) {
 	eg.Engine.SetQuotePolicy(quotePolicy)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetQuotePolicy(quotePolicy)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetQuotePolicy(quotePolicy)
 	}
 }
 
 // SetTableMapper set the table name mapping rule
 func (eg *EngineGroup) SetTableMapper(mapper names.Mapper) {
 	eg.Engine.SetTableMapper(mapper)
-	for i := 0; i < len(eg.slaves); i++ {
-		eg.slaves[i].SetTableMapper(mapper)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[i].SetTableMapper(mapper)
 	}
 }
 
 // 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...)
+	for i := 0; i < len(eg.subordinates); i++ {
+		eg.subordinates[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) {
+// Subordinate returns one of the physical databases which is a subordinate according the policy
+func (eg *EngineGroup) Subordinate() *Engine {
+	switch len(eg.subordinates) {
 	case 0:
 		return eg.Engine
 	case 1:
-		return eg.slaves[0]
+		return eg.subordinates[0]
 	}
-	return eg.policy.Slave(eg)
+	return eg.policy.Subordinate(eg)
 }
 
-// Slaves returns all the slaves
-func (eg *EngineGroup) Slaves() []*Engine {
-	return eg.slaves
+// Subordinates returns all the subordinates
+func (eg *EngineGroup) Subordinates() []*Engine {
+	return eg.subordinates
 }
 
 func (eg *EngineGroup) RegisterSqlTemplate(sqlt SqlTemplate, Cipher ...Cipher) error {
@@ -234,8 +234,8 @@ func (eg *EngineGroup) RegisterSqlTemplate(sqlt SqlTemplate, Cipher ...Cipher) e
 	if err != nil {
 		return err
 	}
-	for i := 0; i < len(eg.slaves); i++ {
-		err = eg.slaves[i].RegisterSqlTemplate(sqlt, Cipher...)
+	for i := 0; i < len(eg.subordinates); i++ {
+		err = eg.subordinates[i].RegisterSqlTemplate(sqlt, Cipher...)
 		if err != nil {
 			return err
 		}
@@ -248,8 +248,8 @@ func (eg *EngineGroup) RegisterSqlMap(sqlm SqlM, Cipher ...Cipher) error {
 	if err != nil {
 		return err
 	}
-	for i := 0; i < len(eg.slaves); i++ {
-		err = eg.slaves[i].RegisterSqlMap(sqlm, Cipher...)
+	for i := 0; i < len(eg.subordinates); i++ {
+		err = eg.subordinates[i].RegisterSqlMap(sqlm, Cipher...)
 		if err != nil {
 			return err
 		}

+ 23 - 23
packages/xormplus/xorm/engine_group_policy.go

@@ -10,28 +10,28 @@ import (
 	"time"
 )
 
-// GroupPolicy is be used by chosing the current slave from slaves
+// GroupPolicy is be used by chosing the current subordinate from subordinates
 type GroupPolicy interface {
-	Slave(*EngineGroup) *Engine
+	Subordinate(*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 {
+// Subordinate implements the chosen of subordinates
+func (h GroupPolicyHandler) Subordinate(eg *EngineGroup) *Engine {
 	return h(eg)
 }
 
-// RandomPolicy implmentes randomly chose the slave of slaves
+// RandomPolicy implmentes randomly chose the subordinate of subordinates
 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()))]
+		return g.Subordinates()[r.Intn(len(g.Subordinates()))]
 	}
 }
 
-// WeightRandomPolicy implmentes randomly chose the slave of slaves
+// WeightRandomPolicy implmentes randomly chose the subordinate of subordinates
 func WeightRandomPolicy(weights []int) GroupPolicyHandler {
 	var rands = make([]int, 0, len(weights))
 	for i := 0; i < len(weights); i++ {
@@ -42,12 +42,12 @@ func WeightRandomPolicy(weights []int) GroupPolicyHandler {
 	var r = rand.New(rand.NewSource(time.Now().UnixNano()))
 
 	return func(g *EngineGroup) *Engine {
-		var slaves = g.Slaves()
+		var subordinates = g.Subordinates()
 		idx := rands[r.Intn(len(rands))]
-		if idx >= len(slaves) {
-			idx = len(slaves) - 1
+		if idx >= len(subordinates) {
+			idx = len(subordinates) - 1
 		}
-		return slaves[idx]
+		return subordinates[idx]
 	}
 }
 
@@ -56,16 +56,16 @@ func RoundRobinPolicy() GroupPolicyHandler {
 	var pos = -1
 	var lock sync.Mutex
 	return func(g *EngineGroup) *Engine {
-		var slaves = g.Slaves()
+		var subordinates = g.Subordinates()
 
 		lock.Lock()
 		defer lock.Unlock()
 		pos++
-		if pos >= len(slaves) {
+		if pos >= len(subordinates) {
 			pos = 0
 		}
 
-		return slaves[pos]
+		return subordinates[pos]
 	}
 }
 
@@ -81,7 +81,7 @@ func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
 	var lock sync.Mutex
 
 	return func(g *EngineGroup) *Engine {
-		var slaves = g.Slaves()
+		var subordinates = g.Subordinates()
 		lock.Lock()
 		defer lock.Unlock()
 		pos++
@@ -90,21 +90,21 @@ func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
 		}
 
 		idx := rands[pos]
-		if idx >= len(slaves) {
-			idx = len(slaves) - 1
+		if idx >= len(subordinates) {
+			idx = len(subordinates) - 1
 		}
-		return slaves[idx]
+		return subordinates[idx]
 	}
 }
 
-// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
+// LeastConnPolicy implements GroupPolicy, every time will get the least connections subordinate
 func LeastConnPolicy() GroupPolicyHandler {
 	return func(g *EngineGroup) *Engine {
-		var slaves = g.Slaves()
+		var subordinates = g.Subordinates()
 		connections := 0
 		idx := 0
-		for i := 0; i < len(slaves); i++ {
-			openConnections := slaves[i].DB().Stats().OpenConnections
+		for i := 0; i < len(subordinates); i++ {
+			openConnections := subordinates[i].DB().Stats().OpenConnections
 			if i == 0 {
 				connections = openConnections
 				idx = i
@@ -113,6 +113,6 @@ func LeastConnPolicy() GroupPolicyHandler {
 				idx = i
 			}
 		}
-		return slaves[idx]
+		return subordinates[idx]
 	}
 }

+ 8 - 1
packages/xormplus/xorm/integrations/tests.go

@@ -36,6 +36,8 @@ var (
 	ignoreSelectUpdate = flag.Bool("ignore_select_update", false, "ignore select update if implementation difference, only for tidb")
 	ingoreUpdateLimit  = flag.Bool("ignore_update_limit", false, "ignore update limit if implementation difference, only for cockroach")
 	quotePolicyStr     = flag.String("quote", "always", "quote could be always, none, reversed")
+	defaultVarchar     = flag.String("default_varchar", "varchar", "default varchar type, mssql only, could be varchar or nvarchar, default is varchar")
+	defaultChar        = flag.String("default_char", "char", "default char type, mssql only, could be char or nchar, default is char")
 	tableMapper        names.Mapper
 	colMapper          names.Mapper
 )
@@ -47,7 +49,7 @@ func createEngine(dbType, connStr string) error {
 		if !*cluster {
 			switch schemas.DBType(strings.ToLower(dbType)) {
 			case schemas.MSSQL:
-				db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "master", -1))
+				db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "main", -1))
 				if err != nil {
 					return err
 				}
@@ -137,6 +139,11 @@ func createEngine(dbType, connStr string) error {
 		} else {
 			testEngine.SetQuotePolicy(dialects.QuotePolicyAlways)
 		}
+
+		testEngine.Dialect().SetParams(map[string]string{
+			"DEFAULT_VARCHAR": *defaultVarchar,
+			"DEFAULT_CHAR":    *defaultChar,
+		})
 	}
 
 	tableMapper = testEngine.GetTableMapper()

+ 1 - 0
packages/xormplus/xorm/interface.go

@@ -122,6 +122,7 @@ type EngineInterface interface {
 	TableInfo(bean interface{}) (*schemas.Table, error)
 	TableName(interface{}, ...bool) string
 	UnMapType(reflect.Type)
+	EnableSessionID(bool)
 }
 
 var (

+ 21 - 1
packages/xormplus/xorm/internal/statements/pk.go

@@ -20,6 +20,21 @@ var (
 	uintType   = reflect.TypeOf(uint64(0))
 )
 
+// ErrIDConditionWithNoTable represents an error there is no reference table with an ID condition
+type ErrIDConditionWithNoTable struct {
+	ID schemas.PK
+}
+
+func (err ErrIDConditionWithNoTable) Error() string {
+	return fmt.Sprintf("ID condition %#v need reference table", err.ID)
+}
+
+// IsIDConditionWithNoTableErr return true if the err is ErrIDConditionWithNoTable
+func IsIDConditionWithNoTableErr(err error) bool {
+	_, ok := err.(ErrIDConditionWithNoTable)
+	return ok
+}
+
 // ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
 func (statement *Statement) ID(id interface{}) *Statement {
 	switch t := id.(type) {
@@ -58,11 +73,16 @@ func (statement *Statement) ID(id interface{}) *Statement {
 	return statement
 }
 
+// ProcessIDParam handles the process of id condition
 func (statement *Statement) ProcessIDParam() error {
-	if statement.idParam == nil || statement.RefTable == nil {
+	if statement.idParam == nil {
 		return nil
 	}
 
+	if statement.RefTable == nil {
+		return ErrIDConditionWithNoTable{statement.idParam}
+	}
+
 	if len(statement.RefTable.PrimaryKeys) != len(statement.idParam) {
 		return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d",
 			len(statement.RefTable.PrimaryKeys),

+ 1 - 1
packages/xormplus/xorm/internal/statements/update.go

@@ -130,7 +130,7 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
 			}
 		}
 
-		if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
+		if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok && !fieldValue.IsNil() {
 			data, err := structConvert.ToDB()
 			if err != nil {
 				return nil, nil, err

+ 14 - 11
packages/xormplus/xorm/internal/statements/values.go

@@ -36,18 +36,21 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
 		}
 	}
 
-	if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
-		data, err := fieldConvert.ToDB()
-		if err != nil {
-			return nil, err
-		}
-		if col.SQLType.IsBlob() {
-			return data, nil
-		}
-		if nil == data {
-			return nil, nil
+	isNil := fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil()
+	if !isNil {
+		if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
+			data, err := fieldConvert.ToDB()
+			if err != nil {
+				return nil, err
+			}
+			if col.SQLType.IsBlob() {
+				return data, nil
+			}
+			if nil == data {
+				return nil, nil
+			}
+			return string(data), nil
 		}
-		return string(data), nil
 	}
 
 	fieldType := fieldValue.Type()

+ 1 - 0
packages/xormplus/xorm/log/logger_context.go

@@ -42,6 +42,7 @@ var (
 // enumerate all the context keys
 var (
 	SessionIDKey      = "__xorm_session_id"
+	SessionKey        = "__xorm_session_key"
 	SessionShowSQLKey = "__xorm_show_sql"
 )
 

+ 16 - 0
packages/xormplus/xorm/schemas/column.go

@@ -5,8 +5,10 @@
 package schemas
 
 import (
+	"errors"
 	"fmt"
 	"reflect"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -115,3 +117,17 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 
 	return &fieldValue, nil
 }
+
+// ConvertID converts id content to suitable type according column type
+func (col *Column) ConvertID(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
+	}
+	return nil, errors.New("not supported")
+}

+ 3 - 5
packages/xormplus/xorm/schemas/quote.go

@@ -82,9 +82,7 @@ func (q Quoter) JoinWrite(b *strings.Builder, a []string, sep string) error {
 				return err
 			}
 		}
-		if s != "*" {
-			q.QuoteTo(b, strings.TrimSpace(s))
-		}
+		q.QuoteTo(b, strings.TrimSpace(s))
 	}
 	return nil
 }
@@ -143,7 +141,7 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
 	}
 
 	isReserved := q.IsReserved(realWord)
-	if isReserved {
+	if isReserved && realWord != "*" {
 		if err := buf.WriteByte(q.Prefix); err != nil {
 			return err
 		}
@@ -151,7 +149,7 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
 	if _, err := buf.WriteString(realWord); err != nil {
 		return err
 	}
-	if isReserved {
+	if isReserved && realWord != "*" {
 		return buf.WriteByte(q.Suffix)
 	}
 

+ 50 - 6
packages/xormplus/xorm/schemas/table.go

@@ -5,7 +5,9 @@
 package schemas
 
 import (
+	"fmt"
 	"reflect"
+	"strconv"
 	"strings"
 )
 
@@ -28,6 +30,7 @@ type Table struct {
 	Comment       string
 }
 
+// NewEmptyTable creates an empty table
 func NewEmptyTable() *Table {
 	return NewTable("", nil)
 }
@@ -44,23 +47,21 @@ func NewTable(name string, t reflect.Type) *Table {
 	}
 }
 
+// Columns returns table's columns
 func (table *Table) Columns() []*Column {
 	return table.columns
 }
 
+// ColumnsSeq returns table's column names according sequence
 func (table *Table) ColumnsSeq() []string {
 	return table.columnsSeq
 }
 
 func (table *Table) columnsByName(name string) []*Column {
-	for k, cols := range table.columnsMap {
-		if strings.EqualFold(k, name) {
-			return cols
-		}
-	}
-	return nil
+	return table.columnsMap[strings.ToLower(name)]
 }
 
+// GetColumn returns column according column name, if column not found, return nil
 func (table *Table) GetColumn(name string) *Column {
 	cols := table.columnsByName(name)
 	if cols != nil {
@@ -70,6 +71,7 @@ func (table *Table) GetColumn(name string) *Column {
 	return nil
 }
 
+// GetColumnIdx returns column according name and idx
 func (table *Table) GetColumnIdx(name string, idx int) *Column {
 	cols := table.columnsByName(name)
 	if cols != nil && idx < len(cols) {
@@ -144,3 +146,45 @@ func (table *Table) AddColumn(col *Column) {
 func (table *Table) AddIndex(index *Index) {
 	table.Indexes[index.Name] = index
 }
+
+// IDOfV get id from one value of struct
+func (table *Table) IDOfV(rv reflect.Value) (PK, error) {
+	v := reflect.Indirect(rv)
+	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, fmt.Errorf("Unsupported read value of column %s from field %s", col.Name, col.FieldName)
+			}
+			fieldName = parts[1]
+		}
+
+		pkField := v.FieldByName(fieldName)
+		switch pkField.Kind() {
+		case reflect.String:
+			pk[i], err = col.ConvertID(pkField.String())
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			pk[i], err = col.ConvertID(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 = col.ConvertID(strconv.FormatUint(pkField.Uint(), 10))
+		}
+
+		if err != nil {
+			return nil, err
+		}
+	}
+	return PK(pk), nil
+}

+ 9 - 1
packages/xormplus/xorm/session.go

@@ -94,7 +94,7 @@ func newSession(engine *Engine) *Session {
 		ctx = engine.defaultContext
 	}
 
-	return &Session{
+	session := &Session{
 		ctx:    ctx,
 		engine: engine,
 		tx:     nil,
@@ -124,6 +124,10 @@ func newSession(engine *Engine) *Session {
 
 		sessionType: engineSession,
 	}
+	if engine.logSessionID {
+		session.ctx = context.WithValue(session.ctx, log.SessionKey, session)
+	}
+	return session
 }
 
 // Close release the connection from pool
@@ -153,6 +157,10 @@ func (session *Session) db() *core.DB {
 	return session.engine.db
 }
 
+func (session *Session) Engine() *Engine {
+	return session.engine
+}
+
 func (session *Session) getQueryer() core.Queryer {
 	if session.tx != nil {
 		return session.tx

+ 13 - 4
packages/xormplus/xorm/session_find.go

@@ -81,7 +81,15 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
 			session.statement.OrderStr = ""
 		}
 
-		return session.Count(reflect.New(sliceElementType).Interface())
+		if session.statement.LimitN != nil {
+			session.statement.LimitN = nil
+		}
+		if session.statement.Start > 0 {
+			session.statement.Start = 0
+		}
+
+		// session has stored the conditions so we use `unscoped` to avoid duplicated condition.
+		return session.Unscoped().Count(reflect.New(sliceElementType).Interface())
 	}
 
 }
@@ -368,7 +376,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 			}
 			var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys))
 			for i, col := range table.PKColumns() {
-				pk[i], err = session.engine.idTypeAssertion(col, res[i])
+				pk[i], err = col.ConvertID(res[i])
 				if err != nil {
 					return err
 				}
@@ -398,6 +406,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 			return err
 		}
 		bean := cacher.GetBean(tableName, sid)
+
 		isHit := func() (ht bool) {
 			if bean == nil {
 				ht = false
@@ -416,7 +425,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 		} else {
 			session.engine.logger.Debugf("[cache] cache hit bean: %v, %v, %v", tableName, id, bean)
 
-			pk, err := session.engine.IDOf(bean)
+			pk, err := table.IDOfV(reflect.ValueOf(bean))
 			if err != nil {
 				return err
 			}
@@ -474,7 +483,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 			if rv.Kind() != reflect.Ptr {
 				rv = rv.Addr()
 			}
-			id, err := session.engine.idOfV(rv)
+			id, err := table.IDOfV(rv)
 			if err != nil {
 				return err
 			}

+ 2 - 2
packages/xormplus/xorm/session_plus.go

@@ -13,11 +13,11 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/Chronokeeper/anyxml"
 	"github.com/2637309949/dolphin/packages/xormplus/xorm/core"
 	"github.com/2637309949/dolphin/packages/xormplus/xorm/dialects"
 	"github.com/2637309949/dolphin/packages/xormplus/xorm/internal/utils"
 	"github.com/2637309949/dolphin/packages/xormplus/xorm/schemas"
+	"github.com/Chronokeeper/anyxml"
 )
 
 type Record map[string]Value
@@ -463,7 +463,7 @@ func (session *Session) genSelectSql(dialect dialects.Dialect, rownumber string)
 				sql = fmt.Sprintf("%v LIMIT 0 OFFSET %v", sql, *pLimitN)
 			}
 		} else if pLimitN != nil {
-			sql = fmt.Sprintf("%v LIMIT %v", sql, session.statement.LimitN)
+			sql = fmt.Sprintf("%v LIMIT %v", sql, *pLimitN)
 		}
 	} else if dialect.URI().DBType == schemas.ORACLE {
 		if session.statement.Start != 0 || pLimitN != nil {

+ 1 - 1
packages/xormplus/xorm/session_raw.go

@@ -43,7 +43,7 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
 	if session.isAutoCommit {
 		var db *core.DB
 		if session.sessionType == groupSession {
-			db = session.engine.engineGroup.Slave().DB()
+			db = session.engine.engineGroup.Subordinate().DB()
 		} else {
 			db = session.DB()
 		}

+ 2 - 43
packages/xormplus/xorm/session_tx.go

@@ -4,12 +4,6 @@
 
 package xorm
 
-import (
-	"time"
-
-	"github.com/2637309949/dolphin/packages/xormplus/xorm/log"
-)
-
 // Begin a transaction
 func (session *Session) Begin() error {
 	if session.isAutoCommit {
@@ -33,24 +27,7 @@ func (session *Session) Rollback() error {
 		session.isCommitedOrRollbacked = true
 		session.isAutoCommit = true
 
-		start := time.Now()
-		needSQL := session.DB().NeedLogSQL(session.ctx)
-		if needSQL {
-			session.engine.logger.BeforeSQL(log.LogContext{
-				Ctx: session.ctx,
-				SQL: "ROLL BACK",
-			})
-		}
-		err := session.tx.Rollback()
-		if needSQL {
-			session.engine.logger.AfterSQL(log.LogContext{
-				Ctx:         session.ctx,
-				SQL:         "ROLL BACK",
-				ExecuteTime: time.Now().Sub(start),
-				Err:         err,
-			})
-		}
-		return err
+		return session.tx.Rollback()
 	}
 	return nil
 }
@@ -62,25 +39,7 @@ func (session *Session) Commit() error {
 		session.isCommitedOrRollbacked = true
 		session.isAutoCommit = true
 
-		start := time.Now()
-		needSQL := session.DB().NeedLogSQL(session.ctx)
-		if needSQL {
-			session.engine.logger.BeforeSQL(log.LogContext{
-				Ctx: session.ctx,
-				SQL: "COMMIT",
-			})
-		}
-		err := session.tx.Commit()
-		if needSQL {
-			session.engine.logger.AfterSQL(log.LogContext{
-				Ctx:         session.ctx,
-				SQL:         "COMMIT",
-				ExecuteTime: time.Now().Sub(start),
-				Err:         err,
-			})
-		}
-
-		if err != nil {
+		if err := session.tx.Commit(); err != nil {
 			return err
 		}
 

+ 1 - 1
packages/xormplus/xorm/xorm.go

@@ -23,7 +23,7 @@ import (
 
 const (
 	// Version show the xorm's version
-	Version string = "1.0.1.0515"
+	Version string = "1.0.5.0912"
 )
 
 func close(engine *Engine) {

+ 1 - 1
packages/xormplus/xorm/xormplus.go

@@ -9,7 +9,7 @@ const (
 	MYMYSQL_DRIVER    string = "mymysql"
 	POSTGRESQL_DRIVER string = "postgres"
 	OCI8_DRIVER       string = "oci8"
-	GORACLE_DRIVER    string = "goracle"
+	GORACLE_DRIVER    string = "godror"
 	SQLITE3_DRIVER    string = "sqlite3"
 )