From 10ee2e0dad6471e8912cc833faf33db7eaa55fa8 Mon Sep 17 00:00:00 2001 From: peter zhang Date: Thu, 27 Apr 2017 07:47:16 +0800 Subject: vendor: update xorm version for fix git clone error build with golang 1.8.1 (#4460) --- vendor/github.com/go-xorm/xorm/README.md | 33 +- vendor/github.com/go-xorm/xorm/README_CN.md | 29 +- vendor/github.com/go-xorm/xorm/VERSION | 1 - vendor/github.com/go-xorm/xorm/convert.go | 336 ++++++ vendor/github.com/go-xorm/xorm/dialect_mssql.go | 553 +++++++++ vendor/github.com/go-xorm/xorm/dialect_mysql.go | 580 ++++++++++ vendor/github.com/go-xorm/xorm/dialect_oracle.go | 906 +++++++++++++++ vendor/github.com/go-xorm/xorm/dialect_postgres.go | 1206 ++++++++++++++++++++ vendor/github.com/go-xorm/xorm/dialect_sqlite3.go | 446 ++++++++ vendor/github.com/go-xorm/xorm/doc.go | 43 +- vendor/github.com/go-xorm/xorm/engine.go | 335 +++--- vendor/github.com/go-xorm/xorm/goracle_driver.go | 42 - vendor/github.com/go-xorm/xorm/helpers.go | 63 +- vendor/github.com/go-xorm/xorm/mssql_dialect.go | 528 --------- vendor/github.com/go-xorm/xorm/mymysql_driver.go | 65 -- vendor/github.com/go-xorm/xorm/mysql_dialect.go | 488 -------- vendor/github.com/go-xorm/xorm/mysql_driver.go | 50 - vendor/github.com/go-xorm/xorm/oci8_driver.go | 37 - vendor/github.com/go-xorm/xorm/odbc_driver.go | 34 - vendor/github.com/go-xorm/xorm/oracle_dialect.go | 846 -------------- vendor/github.com/go-xorm/xorm/postgres_dialect.go | 1097 ------------------ vendor/github.com/go-xorm/xorm/pq_driver.go | 119 -- vendor/github.com/go-xorm/xorm/rows.go | 27 +- vendor/github.com/go-xorm/xorm/session.go | 1088 ++---------------- vendor/github.com/go-xorm/xorm/session_cols.go | 84 ++ vendor/github.com/go-xorm/xorm/session_cond.go | 70 ++ vendor/github.com/go-xorm/xorm/session_convert.go | 673 +++++++++++ vendor/github.com/go-xorm/xorm/session_delete.go | 4 +- vendor/github.com/go-xorm/xorm/session_find.go | 180 +-- vendor/github.com/go-xorm/xorm/session_get.go | 56 +- vendor/github.com/go-xorm/xorm/session_insert.go | 38 +- vendor/github.com/go-xorm/xorm/session_raw.go | 25 +- vendor/github.com/go-xorm/xorm/session_schema.go | 21 +- vendor/github.com/go-xorm/xorm/session_sum.go | 2 +- vendor/github.com/go-xorm/xorm/session_update.go | 71 +- vendor/github.com/go-xorm/xorm/sqlite3_dialect.go | 436 ------- vendor/github.com/go-xorm/xorm/sqlite3_driver.go | 20 - vendor/github.com/go-xorm/xorm/statement.go | 106 +- vendor/github.com/go-xorm/xorm/tag.go | 281 +++++ vendor/github.com/go-xorm/xorm/xorm.go | 3 +- vendor/vendor.json | 6 +- 41 files changed, 5830 insertions(+), 5198 deletions(-) delete mode 100644 vendor/github.com/go-xorm/xorm/VERSION create mode 100644 vendor/github.com/go-xorm/xorm/convert.go create mode 100644 vendor/github.com/go-xorm/xorm/dialect_mssql.go create mode 100644 vendor/github.com/go-xorm/xorm/dialect_mysql.go create mode 100644 vendor/github.com/go-xorm/xorm/dialect_oracle.go create mode 100644 vendor/github.com/go-xorm/xorm/dialect_postgres.go create mode 100644 vendor/github.com/go-xorm/xorm/dialect_sqlite3.go delete mode 100644 vendor/github.com/go-xorm/xorm/goracle_driver.go delete mode 100644 vendor/github.com/go-xorm/xorm/mssql_dialect.go delete mode 100644 vendor/github.com/go-xorm/xorm/mymysql_driver.go delete mode 100644 vendor/github.com/go-xorm/xorm/mysql_dialect.go delete mode 100644 vendor/github.com/go-xorm/xorm/mysql_driver.go delete mode 100644 vendor/github.com/go-xorm/xorm/oci8_driver.go delete mode 100644 vendor/github.com/go-xorm/xorm/odbc_driver.go delete mode 100644 vendor/github.com/go-xorm/xorm/oracle_dialect.go delete mode 100644 vendor/github.com/go-xorm/xorm/postgres_dialect.go delete mode 100644 vendor/github.com/go-xorm/xorm/pq_driver.go create mode 100644 vendor/github.com/go-xorm/xorm/session_cols.go create mode 100644 vendor/github.com/go-xorm/xorm/session_cond.go create mode 100644 vendor/github.com/go-xorm/xorm/session_convert.go delete mode 100644 vendor/github.com/go-xorm/xorm/sqlite3_dialect.go delete mode 100644 vendor/github.com/go-xorm/xorm/sqlite3_driver.go create mode 100644 vendor/github.com/go-xorm/xorm/tag.go diff --git a/vendor/github.com/go-xorm/xorm/README.md b/vendor/github.com/go-xorm/xorm/README.md index 12f6ca90..da55878e 100644 --- a/vendor/github.com/go-xorm/xorm/README.md +++ b/vendor/github.com/go-xorm/xorm/README.md @@ -46,12 +46,15 @@ Drivers for Go's sql package which currently support database/sql includes: * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) -* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc) - * Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment) # Changelog +* **v0.6.2** + * refactor tag parse methods + * add Scan features to Get + * add QueryString method + * **v0.6.0** * remove support for ql * add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or` @@ -79,12 +82,6 @@ methods can use `builder.Cond` as parameter # Installation -If you have [gopm](https://github.com/gpmgo/gopm) installed, - - gopm get github.com/go-xorm/xorm - -Or - go get github.com/go-xorm/xorm # Documents @@ -119,19 +116,21 @@ type User struct { err := engine.Sync2(new(User)) ``` -* Query a SQL string, the returned results is []map[string][]byte +* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`. ```Go results, err := engine.Query("select * from user") + +results, err := engine.QueryString("select * from user") ``` -* Execute a SQL string, the returned results +* `Execute` runs a SQL string, it returns `affetcted` and `error` ```Go affected, err := engine.Exec("update user set age = ? where name = ?", age, name) ``` -* Insert one or multiple records to database +* `Insert` one or multiple records to database ```Go affected, err := engine.Insert(&user) @@ -153,6 +152,18 @@ 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.Where("id = ?", id).Cols("name").Get(&name) +// SELECT name FROM user WHERE id = ? +var id int64 +has, err := engine.Where("name = ?", name).Cols("id").Get(&id) +// SELECT id FROM user WHERE name = ? +var valuesMap = make(map[string]string) +has, err := engine.Where("id = ?", id).Get(&valuesMap) +// SELECT * FROM user WHERE id = ? +var valuesSlice = make([]interface{}, len(cols)) +has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) +// SELECT col1, col2, col3 FROM user WHERE id = ? ``` * Query multiple records from database, also you can use join and extends diff --git a/vendor/github.com/go-xorm/xorm/README_CN.md b/vendor/github.com/go-xorm/xorm/README_CN.md index 3919b3ed..40f5f600 100644 --- a/vendor/github.com/go-xorm/xorm/README_CN.md +++ b/vendor/github.com/go-xorm/xorm/README_CN.md @@ -54,6 +54,11 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 ## 更新日志 +* **v0.6.2** + * 重构Tag解析方式 + * Get方法新增类似Sacn的特性 + * 新增 QueryString 方法 + * **v0.6.0** * 去除对 ql 的支持 * 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数 @@ -81,12 +86,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 ## 安装 -推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装: - - gopm get github.com/go-xorm/xorm - -或者您也可以使用go工具进行安装: - go get github.com/go-xorm/xorm ## 文档 @@ -121,13 +120,15 @@ type User struct { err := engine.Sync2(new(User)) ``` -* 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte +* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string ```Go results, err := engine.Query("select * from user") + +results, err := engine.QueryString("select * from user") ``` -* 执行一个SQL语句 +* `Exec` 执行一个SQL语句 ```Go affected, err := engine.Exec("update user set age = ? where name = ?", age, name) @@ -155,6 +156,18 @@ 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.Where("id = ?", id).Cols("name").Get(&name) +// SELECT name FROM user WHERE id = ? +var id int64 +has, err := engine.Where("name = ?", name).Cols("id").Get(&id) +// SELECT id FROM user WHERE name = ? +var valuesMap = make(map[string]string) +has, err := engine.Where("id = ?", id).Get(&valuesMap) +// SELECT * FROM user WHERE id = ? +var valuesSlice = make([]interface{}, len(cols)) +has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice) +// SELECT col1, col2, col3 FROM user WHERE id = ? ``` * 查询多条记录,当然可以使用Join和extends来组合使用 diff --git a/vendor/github.com/go-xorm/xorm/VERSION b/vendor/github.com/go-xorm/xorm/VERSION deleted file mode 100644 index 22c1aa4d..00000000 --- a/vendor/github.com/go-xorm/xorm/VERSION +++ /dev/null @@ -1 +0,0 @@ -xorm v0.6.0.1022 \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/convert.go b/vendor/github.com/go-xorm/xorm/convert.go new file mode 100644 index 00000000..fbd24b5b --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/convert.go @@ -0,0 +1,336 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "database/sql/driver" + "errors" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } else { + c := make([]byte, len(b)) + copy(c, b) + return c + } +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} + +// convertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func convertAssign(dest, src interface{}) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + } + + case time.Time: + switch d := dest.(type) { + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + switch b := src.(type) { + case []byte: + dv.Set(reflect.ValueOf(cloneBytes(b))) + default: + dv.Set(sv) + } + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } else { + dv.Set(reflect.New(dv.Type().Elem())) + return convertAssign(dv.Interface(), src) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + case reflect.String: + dv.SetString(asString(src)) + return nil + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +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) +} diff --git a/vendor/github.com/go-xorm/xorm/dialect_mssql.go b/vendor/github.com/go-xorm/xorm/dialect_mssql.go new file mode 100644 index 00000000..f83cfc17 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/dialect_mssql.go @@ -0,0 +1,553 @@ +// 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" + "strconv" + "strings" + + "github.com/go-xorm/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.TinyInt + if strings.EqualFold(c.Default, "true") { + c.Default = "1" + } else { + 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 + 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 + from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id + left join sys.syscomments c on a.default_object_id=c.id + where a.object_id=object_id('` + tableName + `')` + db.LogSQL(s, args) + + rows, err := db.DB().Query(s, args...) + if err != nil { + 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 bool + err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault) + if err != nil { + return nil, nil, err + } + + col := new(core.Column) + col.Indexes = make(map[string]int) + col.Name = strings.Trim(name, "` ") + col.Nullable = nullable + col.Default = vdefault + ct := strings.ToUpper(ctype) + if ct == "DECIMAL" { + col.Length = precision + col.Length2 = scale + } else { + col.Length = maxLen + } + switch ct { + case "DATETIMEOFFSET": + col.SQLType = core.SQLType{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) { + kv := strings.Split(dataSourceName, ";") + var dbName string + + for _, c := range kv { + vv := strings.Split(strings.TrimSpace(c), "=") + if len(vv) == 2 { + switch strings.ToLower(vv[0]) { + case "database": + dbName = vv[1] + } + } + } + if dbName == "" { + return nil, errors.New("no db name provided") + } + return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil +} diff --git a/vendor/github.com/go-xorm/xorm/dialect_mysql.go b/vendor/github.com/go-xorm/xorm/dialect_mysql.go new file mode 100644 index 00000000..55cfdd76 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/dialect_mysql.go @@ -0,0 +1,580 @@ +// 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" + + "github.com/go-xorm/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 +} + +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) 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` 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 string + var colDefault *string + err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra) + if err != nil { + return nil, nil, err + } + col.Name = strings.Trim(columnName, "` ") + 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" + } + 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` 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 string + var autoIncr *string + err = rows.Scan(&name, &engine, &tableRows, &autoIncr) + if err != nil { + return nil, err + } + + table.Name = name + 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) 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.*?)(?::(?P.*))?@)?` + // [user[:password]@] + `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] + `\/(?P.*?)` + // /dbname + `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=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 +} diff --git a/vendor/github.com/go-xorm/xorm/dialect_oracle.go b/vendor/github.com/go-xorm/xorm/dialect_oracle.go new file mode 100644 index 00000000..ac0081b3 --- /dev/null +++ b/vendor/github.com/go-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" + + "github.com/go-xorm/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.*?)(?::(?P.*))?@)?` + // [user[:password]@] + `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] + `\/(?P.*?)` + // /dbname + `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=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.*)\/(?P.*)@` + // user:password@ + `(?P.*)` + // ip:port + `\/(?P.*)`) // 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 +} diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/github.com/go-xorm/xorm/dialect_postgres.go new file mode 100644 index 00000000..1d4daa27 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/dialect_postgres.go @@ -0,0 +1,1206 @@ +// Copyright 2015 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "net/url" + "sort" + "strconv" + "strings" + + "github.com/go-xorm/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, + } +) + +type postgres struct { + core.Base +} + +func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { + return db.Base.Init(d, db, uri, drivername, dataSourceName) +} + +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.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: + res = 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 + } + + 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{}) { + args := []interface{}{tableName, idxName} + return `SELECT indexname FROM pg_indexes ` + + `WHERE tablename = ? AND indexname = ?`, args +} + +func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) { + args := []interface{}{tableName} + return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args +} + +/*func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) { + args := []interface{}{tableName, colName} + return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" + + " AND column_name = ?", args +}*/ + +func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string { + return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", + tableName, col.Name, db.SqlType(col)) +} + +func (db *postgres) 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 *postgres) IsColumnExist(tableName, colName string) (bool, error) { + args := []interface{}{tableName, colName} + query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" + + " AND column_name = $2" + db.LogSQL(query, args) + + rows, err := db.DB().Query(query, args...) + if err != nil { + return false, err + } + defer rows.Close() + + return rows.Next(), nil +} + +func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { + // FIXME: the schema should be replaced by user custom's + args := []interface{}{tableName, "public"} + s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix , + CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, + CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey +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 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;` + db.LogSQL(s, args) + + rows, err := db.DB().Query(s, args...) + if 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) { + // FIXME: replace public to user customrize schema + args := []interface{}{"public"} + s := fmt.Sprintf("SELECT tablename FROM pg_tables WHERE schemaname = $1") + db.LogSQL(s, args) + + rows, err := db.DB().Query(s, args...) + if 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 (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { + // FIXME: replace the public schema to user specify schema + args := []interface{}{"public", tableName} + s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname=$1 AND tablename=$2") + db.LogSQL(s, args) + + rows, err := db.DB().Query(s, args...) + if 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 + } + cs := strings.Split(indexdef, "(") + colNames = strings.Split(cs[1][0:len(cs[1])-1], ",") + 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 errorf(s string, args ...interface{}) { + panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) +} + +func parseURL(connstr string) (string, error) { + u, err := url.Parse(connstr) + if err != nil { + return "", err + } + + if u.Scheme != "postgresql" && u.Scheme != "postgres" { + return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) + } + + var kvs []string + escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) + accrue := func(k, v string) { + if v != "" { + kvs = append(kvs, k+"="+escaper.Replace(v)) + } + } + + if u.User != nil { + v := u.User.Username() + accrue("user", v) + + v, _ = u.User.Password() + accrue("password", v) + } + + i := strings.Index(u.Host, ":") + if i < 0 { + accrue("host", u.Host) + } else { + accrue("host", u.Host[:i]) + accrue("port", u.Host[i+1:]) + } + + if u.Path != "" { + accrue("dbname", u.Path[1:]) + } + + q := u.Query() + for k := range q { + accrue(k, q.Get(k)) + } + + sort.Strings(kvs) // Makes testing easier (not a performance concern) + return strings.Join(kvs, " "), nil +} + +func parseOpts(name string, o values) { + if len(name) == 0 { + return + } + + name = strings.TrimSpace(name) + + ps := strings.Split(name, " ") + for _, p := range ps { + kv := strings.Split(p, "=") + if len(kv) < 2 { + errorf("invalid option: %q", p) + } + o.Set(kv[0], kv[1]) + } +} + +func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { + db := &core.Uri{DbType: core.POSTGRES} + o := make(values) + var err error + if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") { + dataSourceName, err = parseURL(dataSourceName) + if err != nil { + return nil, err + } + } + parseOpts(dataSourceName, o) + + db.DbName = o.Get("dbname") + if db.DbName == "" { + return nil, errors.New("dbname is empty") + } + /*db.Schema = o.Get("schema") + if len(db.Schema) == 0 { + db.Schema = "public" + }*/ + return db, nil +} diff --git a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go new file mode 100644 index 00000000..c13fd02b --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go @@ -0,0 +1,446 @@ +// 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" + + "github.com/go-xorm/core" +) + +// func init() { +// RegisterDialect("sqlite3", &sqlite3{}) +// } + +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, ",") + 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) { + return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil +} diff --git a/vendor/github.com/go-xorm/xorm/doc.go b/vendor/github.com/go-xorm/xorm/doc.go index cc71930d..5b36fcd8 100644 --- a/vendor/github.com/go-xorm/xorm/doc.go +++ b/vendor/github.com/go-xorm/xorm/doc.go @@ -24,7 +24,7 @@ Generally, one engine for an application is enough. You can set it as package va Raw Methods -Xorm also support raw sql execution: +XORM also support raw SQL execution: 1. query a SQL string, the returned results is []map[string][]byte @@ -36,7 +36,7 @@ Xorm also support raw sql execution: ORM Methods -There are 7 major ORM methods and many helpful methods to use to operate database. +There are 8 major ORM methods and many helpful methods to use to operate database. 1. Insert one or multiple records to database @@ -58,10 +58,18 @@ There are 7 major ORM methods and many helpful methods to use to operate databas 3. Query multiple records from database - sliceOfStructs := new(Struct) - err := engine.Find(sliceOfStructs) + var sliceOfStructs []Struct + err := engine.Find(&sliceOfStructs) // SELECT * FROM user + var mapOfStructs = make(map[int64]Struct) + err := engine.Find(&mapOfStructs) + // SELECT * FROM user + + var int64s []int64 + err := engine.Table("user").Cols("id").Find(&int64s) + // SELECT id FROM user + 4. Query multiple records and record by record handle, there two methods, one is Iterate, another is Rows @@ -91,20 +99,31 @@ another is Rows counts, err := engine.Count(&user) // SELECT count(*) AS total FROM user +8. Sum records + + sumFloat64, err := engine.Sum(&user, "id") + // SELECT sum(id) from user + + sumFloat64s, err := engine.Sums(&user, "id1", "id2") + // SELECT sum(id1), sum(id2) from user + + sumInt64s, err := engine.SumsInt(&user, "id1", "id2") + // SELECT sum(id1), sum(id2) from user + Conditions -The above 7 methods could use with condition methods chainable. -Attention: the above 7 methods should be the last chainable method. +The above 8 methods could use with condition methods chainable. +Attention: the above 8 methods should be the last chainable method. -1. Id, In +1. ID, In - engine.Id(1).Get(&user) // for single primary key + engine.ID(1).Get(&user) // for single primary key // SELECT * FROM user WHERE id = 1 - engine.Id(core.PK{1, 2}).Get(&user) // for composite primary keys + engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys // SELECT * FROM user WHERE id1 = 1 AND id2 = 2 engine.In("id", 1, 2, 3).Find(&users) // SELECT * FROM user WHERE id IN (1, 2, 3) - engine.In("id", []int{1, 2, 3}) + engine.In("id", []int{1, 2, 3}).Find(&users) // SELECT * FROM user WHERE id IN (1, 2, 3) 2. Where, And, Or @@ -127,10 +146,10 @@ Attention: the above 7 methods should be the last chainable method. // SELECT TOP 5 * FROM user // for mssql // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases -5. Sql, let you custom SQL +5. SQL, let you custom SQL var users []User - engine.Sql("select * from user").Find(&users) + engine.SQL("select * from user").Find(&users) 6. Cols, Omit, Distinct diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/github.com/go-xorm/xorm/engine.go index be90ddbe..a788c117 100644 --- a/vendor/github.com/go-xorm/xorm/engine.go +++ b/vendor/github.com/go-xorm/xorm/engine.go @@ -44,6 +44,8 @@ type Engine struct { DatabaseTZ *time.Location // The timezone of the database disableGlobalCache bool + + tagHandlers map[string]tagHandler } // ShowSQL show SQL statement or not on logger if log level is great than INFO @@ -215,10 +217,15 @@ func (engine *Engine) NoCascade() *Session { } // MapCacher Set a table use a special cacher -func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) { +func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error { v := rValue(bean) - tb := engine.autoMapType(v) + tb, err := engine.autoMapType(v) + if err != nil { + return err + } + tb.Cacher = cacher + return nil } // NewDB provides an interface to operate database directly @@ -260,9 +267,9 @@ func (engine *Engine) Ping() error { func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { if engine.showSQL && !engine.showExecTime { if len(sqlArgs) > 0 { - engine.logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs) + engine.logger.Infof("[SQL] %v %v", sqlStr, sqlArgs) } else { - engine.logger.Infof("[sql] %v", sqlStr) + engine.logger.Infof("[SQL] %v", sqlStr) } } } @@ -273,9 +280,9 @@ func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executi stmt, res, err := executionBlock() execDuration := time.Since(b4ExecTime) if len(args) > 0 { - engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration) + engine.logger.Infof("[SQL] %s %v - took: %v", sqlStr, args, execDuration) } else { - engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration) + engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) } return stmt, res, err } @@ -774,13 +781,18 @@ func (engine *Engine) Having(conditions string) *Session { return session.Having(conditions) } -func (engine *Engine) autoMapType(v reflect.Value) *core.Table { +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 { - table = engine.mapType(v) + 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() { @@ -790,12 +802,11 @@ func (engine *Engine) autoMapType(v reflect.Value) *core.Table { } } } - return table + return table, nil } // GobRegister register one struct to gob for cache use func (engine *Engine) GobRegister(v interface{}) *Engine { - //fmt.Printf("Type: %[1]T => Data: %[1]#v\n", v) gob.Register(v) return engine } @@ -806,10 +817,19 @@ type Table struct { 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) - return &Table{engine.autoMapType(v), engine.tbName(v)} + tb, err := engine.autoMapType(v) + if err != nil { + engine.logger.Error(err) + } + return &Table{tb, engine.tbName(v)} } func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) { @@ -842,7 +862,7 @@ var ( tpTableName = reflect.TypeOf((*TableName)(nil)).Elem() ) -func (engine *Engine) mapType(v reflect.Value) *core.Table { +func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) { t := v.Type() table := engine.newTable() if tb, ok := v.Interface().(TableName); ok { @@ -861,7 +881,6 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { table.Type = t var idFieldColName string - var err error var hasCacheTag, hasNoCacheTag bool for i := 0; i < t.NumField(); i++ { @@ -881,186 +900,95 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { if tags[0] == "-" { continue } + + var ctx = tagContext{ + table: table, + col: col, + fieldValue: fieldValue, + indexNames: make(map[string]int), + engine: engine, + } + if strings.ToUpper(tags[0]) == "EXTENDS" { - switch fieldValue.Kind() { - case reflect.Ptr: - f := fieldValue.Type().Elem() - if f.Kind() == reflect.Struct { - fieldPtr := fieldValue - fieldValue = fieldValue.Elem() - if !fieldValue.IsValid() || fieldPtr.IsNil() { - fieldValue = reflect.New(f).Elem() - } - } - fallthrough - case reflect.Struct: - parentTable := engine.mapType(fieldValue) - for _, col := range parentTable.Columns() { - col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName) - table.AddColumn(col) - for indexName, indexType := range col.Indexes { - addIndex(indexName, table, col, indexType) - } - } - continue - default: - //TODO: warning + if err := ExtendsTagHandler(&ctx); err != nil { + return nil, err } + continue } - indexNames := make(map[string]int) - var isIndex, isUnique bool - var preKey string for j, key := range tags { + if ctx.ignoreNext { + ctx.ignoreNext = false + continue + } + k := strings.ToUpper(key) - switch { - case k == "<-": - col.MapType = core.ONLYFROMDB - case k == "->": - col.MapType = core.ONLYTODB - case k == "PK": - col.IsPrimaryKey = true - col.Nullable = false - case k == "NULL": - if j == 0 { - col.Nullable = true - } else { - col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT") - } - // TODO: for postgres how add autoincr? - /*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"): - col.IsAutoIncrement = true + ctx.tagName = k + ctx.params = []string{} - autoStart := k[len("AUTOINCR")+1 : len(k)-1] - autoStartInt, err := strconv.Atoi(autoStart) - if err != nil { - engine.LogError(err) + pStart := strings.Index(k, "(") + if pStart == 0 { + return nil, errors.New("( could not be the first charactor") } - col.AutoIncrStart = autoStartInt*/ - case k == "AUTOINCR": - col.IsAutoIncrement = true - //col.AutoIncrStart = 1 - case k == "DEFAULT": - col.Default = tags[j+1] - case k == "CREATED": - col.IsCreated = true - case k == "VERSION": - col.IsVersion = true - col.Default = "1" - case k == "UTC": - col.TimeZone = time.UTC - case k == "LOCAL": - col.TimeZone = time.Local - case strings.HasPrefix(k, "LOCALE(") && strings.HasSuffix(k, ")"): - location := k[len("LOCALE")+1 : len(k)-1] - col.TimeZone, err = time.LoadLocation(location) - if err != nil { - engine.logger.Error(err) + if pStart > -1 { + if !strings.HasSuffix(k, ")") { + return nil, errors.New("cannot match ) charactor") } - case k == "UPDATED": - col.IsUpdated = true - case k == "DELETED": - col.IsDeleted = true - case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"): - indexName := k[len("INDEX")+1 : len(k)-1] - indexNames[indexName] = core.IndexType - case k == "INDEX": - isIndex = true - case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"): - indexName := k[len("UNIQUE")+1 : len(k)-1] - indexNames[indexName] = core.UniqueType - case k == "UNIQUE": - isUnique = true - case k == "NOTNULL": - col.Nullable = false - case k == "CACHE": - if !hasCacheTag { - hasCacheTag = true - } - case k == "NOCACHE": - if !hasNoCacheTag { - hasNoCacheTag = true + + 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 } - case k == "NOT": - default: - if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") { - if preKey != "DEFAULT" { - col.Name = key[1 : len(key)-1] - } - } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { - fs := strings.Split(k, "(") - - if _, ok := core.SqlTypes[fs[0]]; !ok { - preKey = k - continue - } - col.SQLType = core.SQLType{Name: fs[0]} - if fs[0] == core.Enum && fs[1][0] == '\'' { //enum - options := strings.Split(fs[1][0:len(fs[1])-1], ",") - 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 fs[0] == core.Set && fs[1][0] == '\'' { //set - options := strings.Split(fs[1][0:len(fs[1])-1], ",") - col.SetOptions = make(map[string]int) - for k, v := range options { - v = strings.TrimSpace(v) - v = strings.Trim(v, "'") - col.SetOptions[v] = k - } - } else { - fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",") - if len(fs2) == 2 { - col.Length, err = strconv.Atoi(fs2[0]) - if err != nil { - engine.logger.Error(err) - } - col.Length2, err = strconv.Atoi(fs2[1]) - if err != nil { - engine.logger.Error(err) - } - } else if len(fs2) == 1 { - col.Length, err = strconv.Atoi(fs2[0]) - if err != nil { - engine.logger.Error(err) - } - } - } + } else { + if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") { + col.Name = key[1 : len(key)-1] } else { - if _, ok := core.SqlTypes[k]; ok { - col.SQLType = core.SQLType{Name: k} - } else if key != col.Default { - col.Name = key - } + col.Name = key } - engine.dialect.SqlType(col) } - preKey = k + + 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 isUnique { - indexNames[col.Name] = core.UniqueType - } else if isIndex { - indexNames[col.Name] = core.IndexType + if ctx.isUnique { + ctx.indexNames[col.Name] = core.UniqueType + } else if ctx.isIndex { + ctx.indexNames[col.Name] = core.IndexType } - for indexName, indexType := range indexNames { + for indexName, indexType := range ctx.indexNames { addIndex(indexName, table, col, indexType) } } @@ -1114,7 +1042,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { table.Cacher = nil } - return table + return table, nil } // IsTableEmpty if a table has any reocrd @@ -1152,8 +1080,21 @@ func (engine *Engine) IdOfV(rv reflect.Value) core.PK { // 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 := engine.autoMapType(v) + table, err := engine.autoMapType(v) + if err != nil { + return nil, err + } + pk := make([]interface{}, len(table.PrimaryKeys)) for i, col := range table.PKColumns() { pkField := v.FieldByName(col.FieldName) @@ -1166,7 +1107,7 @@ func (engine *Engine) IDOfV(rv reflect.Value) core.PK { pk[i] = pkField.Uint() } } - return core.PK(pk) + return core.PK(pk), nil } // CreateIndexes create indexes @@ -1187,13 +1128,6 @@ func (engine *Engine) getCacher2(table *core.Table) core.Cacher { return table.Cacher } -func (engine *Engine) getCacher(v reflect.Value) core.Cacher { - if table := engine.autoMapType(v); table != nil { - return table.Cacher - } - return engine.Cacher -} - // ClearCacheBean if enabled cache, clear the cache bean func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { v := rValue(bean) @@ -1202,7 +1136,10 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { return errors.New("error params") } tableName := engine.tbName(v) - table := engine.autoMapType(v) + table, err := engine.autoMapType(v) + if err != nil { + return err + } cacher := table.Cacher if cacher == nil { cacher = engine.Cacher @@ -1223,7 +1160,11 @@ func (engine *Engine) ClearCache(beans ...interface{}) error { return errors.New("error params") } tableName := engine.tbName(v) - table := engine.autoMapType(v) + table, err := engine.autoMapType(v) + if err != nil { + return err + } + cacher := table.Cacher if cacher == nil { cacher = engine.Cacher @@ -1243,7 +1184,10 @@ func (engine *Engine) Sync(beans ...interface{}) error { for _, bean := range beans { v := rValue(bean) tableName := engine.tbName(v) - table := engine.autoMapType(v) + table, err := engine.autoMapType(v) + if err != nil { + return err + } s := engine.NewSession() defer s.Close() @@ -1279,8 +1223,10 @@ func (engine *Engine) Sync(beans ...interface{}) error { } if !isExist { session := engine.NewSession() - session.Statement.setRefValue(v) defer session.Close() + if err := session.Statement.setRefValue(v); err != nil { + return err + } err = session.addColumn(col.Name) if err != nil { return err @@ -1290,8 +1236,10 @@ func (engine *Engine) Sync(beans ...interface{}) error { for name, index := range table.Indexes { session := engine.NewSession() - session.Statement.setRefValue(v) defer session.Close() + if err := session.Statement.setRefValue(v); err != nil { + return err + } if index.Type == core.UniqueType { //isExist, err := session.isIndexExist(table.Name, name, true) isExist, err := session.isIndexExist2(tableName, index.Cols, true) @@ -1300,8 +1248,11 @@ func (engine *Engine) Sync(beans ...interface{}) error { } if !isExist { session := engine.NewSession() - session.Statement.setRefValue(v) defer session.Close() + if err := session.Statement.setRefValue(v); err != nil { + return err + } + err = session.addUnique(tableName, name) if err != nil { return err @@ -1314,8 +1265,11 @@ func (engine *Engine) Sync(beans ...interface{}) error { } if !isExist { session := engine.NewSession() - session.Statement.setRefValue(v) defer session.Close() + if err := session.Statement.setRefValue(v); err != nil { + return err + } + err = session.addIndex(tableName, name) if err != nil { return err @@ -1337,18 +1291,6 @@ func (engine *Engine) Sync2(beans ...interface{}) error { return s.Sync2(beans...) } -func (engine *Engine) unMap(beans ...interface{}) (e error) { - engine.mutex.Lock() - defer engine.mutex.Unlock() - for _, bean := range beans { - t := rType(bean) - if _, ok := engine.Tables[t]; ok { - delete(engine.Tables, t) - } - } - return -} - // Drop all mapped table func (engine *Engine) dropAll() error { session := engine.NewSession() @@ -1426,6 +1368,13 @@ func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice [ return session.Query(sql, paramStr...) } +// QueryString runs a raw sql and return records as []map[string]string +func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { + session := engine.NewSession() + defer session.Close() + return session.QueryString(sqlStr, args...) +} + // Insert one or more records func (engine *Engine) Insert(beans ...interface{}) (int64, error) { session := engine.NewSession() diff --git a/vendor/github.com/go-xorm/xorm/goracle_driver.go b/vendor/github.com/go-xorm/xorm/goracle_driver.go deleted file mode 100644 index 9fcde48f..00000000 --- a/vendor/github.com/go-xorm/xorm/goracle_driver.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "regexp" - - "github.com/go-xorm/core" -) - -// func init() { -// core.RegisterDriver("goracle", &goracleDriver{}) -// } - -type goracleDriver struct { -} - -func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.ORACLE} - dsnPattern := regexp.MustCompile( - `^(?:(?P.*?)(?::(?P.*))?@)?` + // [user[:password]@] - `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] - `\/(?P.*?)` + // /dbname - `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=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 -} diff --git a/vendor/github.com/go-xorm/xorm/helpers.go b/vendor/github.com/go-xorm/xorm/helpers.go index a015ca50..324c5bea 100644 --- a/vendor/github.com/go-xorm/xorm/helpers.go +++ b/vendor/github.com/go-xorm/xorm/helpers.go @@ -17,74 +17,83 @@ import ( ) // str2PK convert string value to primary key value according to tp -func str2PK(s string, tp reflect.Type) (interface{}, error) { +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 nil, errors.New("convert " + s + " as int: " + err.Error()) + return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error()) } case reflect.Int8: x, err := strconv.Atoi(s) if err != nil { - return nil, errors.New("convert " + s + " as int16: " + err.Error()) + 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 nil, errors.New("convert " + s + " as int16: " + err.Error()) + 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 nil, errors.New("convert " + s + " as int32: " + err.Error()) + 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 nil, errors.New("convert " + s + " as int64: " + err.Error()) + 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 nil, errors.New("convert " + s + " as uint: " + err.Error()) + 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 nil, errors.New("convert " + s + " as uint8: " + err.Error()) + 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 nil, errors.New("convert " + s + " as uint16: " + err.Error()) + 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 nil, errors.New("convert " + s + " as uint32: " + err.Error()) + 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 nil, errors.New("convert " + s + " as uint64: " + err.Error()) + return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error()) } case reflect.String: result = s default: - panic("unsupported convert type") + return defReturn, errors.New("unsupported convert type") } - result = reflect.ValueOf(result).Convert(tp).Interface() - return result, nil + 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) { @@ -171,6 +180,20 @@ func isStructZero(v reflect.Value) bool { return true } +func isArrayValueZero(v reflect.Value) bool { + if !v.IsValid() || v.Len() == 0 { + return true + } + + for i := 0; i < v.Len(); i++ { + if !isZero(v.Index(i).Interface()) { + return false + } + } + + return true +} + func int64ToIntValue(id int64, tp reflect.Type) reflect.Value { var v interface{} switch tp.Kind() { @@ -429,7 +452,7 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, return result, nil } -func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) { +func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) { rows, err := tx.Query(sqlStr, params...) if err != nil { return nil, err @@ -439,13 +462,8 @@ func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice [ return rows2Strings(rows) } -func query2(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) { - s, err := db.Prepare(sqlStr) - if err != nil { - return nil, err - } - defer s.Close() - rows, err := s.Query(params...) +func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) { + rows, err := db.Query(sqlStr, params...) if err != nil { return nil, err } @@ -579,7 +597,6 @@ func indexName(tableName, idxName string) string { } func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) { - if len(m) == 0 { return false, false } diff --git a/vendor/github.com/go-xorm/xorm/mssql_dialect.go b/vendor/github.com/go-xorm/xorm/mssql_dialect.go deleted file mode 100644 index e9bda1fd..00000000 --- a/vendor/github.com/go-xorm/xorm/mssql_dialect.go +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strconv" - "strings" - - "github.com/go-xorm/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.TinyInt - if c.Default == "true" { - c.Default = "1" - } else if 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 - 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 - from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id - left join sys.syscomments c on a.default_object_id=c.id - where a.object_id=object_id('` + tableName + `')` - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - 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 bool - err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault) - if err != nil { - return nil, nil, err - } - - col := new(core.Column) - col.Indexes = make(map[string]int) - col.Name = strings.Trim(name, "` ") - col.Nullable = nullable - col.Default = vdefault - ct := strings.ToUpper(ctype) - if ct == "DECIMAL" { - col.Length = precision - col.Length2 = scale - } else { - col.Length = maxLen - } - switch ct { - case "DATETIMEOFFSET": - col.SQLType = core.SQLType{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, "` ") - - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - indexName = indexName[5+len(tableName):] - } - - var index *core.Index - var ok bool - if index, ok = indexes[indexName]; !ok { - index = new(core.Index) - index.Type = indexType - index.Name = indexName - 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{}} -} diff --git a/vendor/github.com/go-xorm/xorm/mymysql_driver.go b/vendor/github.com/go-xorm/xorm/mymysql_driver.go deleted file mode 100644 index ef3086a4..00000000 --- a/vendor/github.com/go-xorm/xorm/mymysql_driver.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "strings" - "time" - - "github.com/go-xorm/core" -) - -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 -} diff --git a/vendor/github.com/go-xorm/xorm/mysql_dialect.go b/vendor/github.com/go-xorm/xorm/mysql_dialect.go deleted file mode 100644 index ab756f35..00000000 --- a/vendor/github.com/go-xorm/xorm/mysql_dialect.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "crypto/tls" - "fmt" - "strconv" - "strings" - "time" - - "github.com/go-xorm/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 -} - -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) 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` 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 string - var colDefault *string - err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra) - if err != nil { - return nil, nil, err - } - col.Name = strings.Trim(columnName, "` ") - 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" - } - 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` 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 string - var autoIncr *string - err = rows.Scan(&name, &engine, &tableRows, &autoIncr) - if err != nil { - return nil, err - } - - table.Name = name - 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) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}} -} diff --git a/vendor/github.com/go-xorm/xorm/mysql_driver.go b/vendor/github.com/go-xorm/xorm/mysql_driver.go deleted file mode 100644 index 6ceeed58..00000000 --- a/vendor/github.com/go-xorm/xorm/mysql_driver.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "regexp" - "strings" - - "github.com/go-xorm/core" -) - -type mysqlDriver struct { -} - -func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - dsnPattern := regexp.MustCompile( - `^(?:(?P.*?)(?::(?P.*))?@)?` + // [user[:password]@] - `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] - `\/(?P.*?)` + // /dbname - `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=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 -} diff --git a/vendor/github.com/go-xorm/xorm/oci8_driver.go b/vendor/github.com/go-xorm/xorm/oci8_driver.go deleted file mode 100644 index ec5f2022..00000000 --- a/vendor/github.com/go-xorm/xorm/oci8_driver.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "regexp" - - "github.com/go-xorm/core" -) - -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.*)\/(?P.*)@` + // user:password@ - `(?P.*)` + // ip:port - `\/(?P.*)`) // 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 -} diff --git a/vendor/github.com/go-xorm/xorm/odbc_driver.go b/vendor/github.com/go-xorm/xorm/odbc_driver.go deleted file mode 100644 index 6770de60..00000000 --- a/vendor/github.com/go-xorm/xorm/odbc_driver.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "strings" - - "github.com/go-xorm/core" -) - -type odbcDriver struct { -} - -func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - kv := strings.Split(dataSourceName, ";") - var dbName string - - for _, c := range kv { - vv := strings.Split(strings.TrimSpace(c), "=") - if len(vv) == 2 { - switch strings.ToLower(vv[0]) { - case "database": - dbName = vv[1] - } - } - } - if dbName == "" { - return nil, errors.New("no db name provided") - } - return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil -} diff --git a/vendor/github.com/go-xorm/xorm/oracle_dialect.go b/vendor/github.com/go-xorm/xorm/oracle_dialect.go deleted file mode 100644 index b19ea38b..00000000 --- a/vendor/github.com/go-xorm/xorm/oracle_dialect.go +++ /dev/null @@ -1,846 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strconv" - "strings" - - "github.com/go-xorm/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, `" `) - - 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 - 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{}} -} diff --git a/vendor/github.com/go-xorm/xorm/postgres_dialect.go b/vendor/github.com/go-xorm/xorm/postgres_dialect.go deleted file mode 100644 index c23ab6f3..00000000 --- a/vendor/github.com/go-xorm/xorm/postgres_dialect.go +++ /dev/null @@ -1,1097 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strconv" - "strings" - - "github.com/go-xorm/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, - } -) - -type postgres struct { - core.Base -} - -func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - return db.Base.Init(d, db, uri, drivername, dataSourceName) -} - -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.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: - res = 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 - } - - 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{}) { - args := []interface{}{tableName, idxName} - return `SELECT indexname FROM pg_indexes ` + - `WHERE tablename = ? AND indexname = ?`, args -} - -func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{tableName} - return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args -} - -/*func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{tableName, colName} - return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" + - " AND column_name = ?", args -}*/ - -func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string { - return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", - tableName, col.Name, db.SqlType(col)) -} - -func (db *postgres) 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 *postgres) IsColumnExist(tableName, colName string) (bool, error) { - args := []interface{}{tableName, colName} - query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" + - " AND column_name = $2" - db.LogSQL(query, args) - - rows, err := db.DB().Query(query, args...) - if err != nil { - return false, err - } - defer rows.Close() - - return rows.Next(), nil -} - -func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - // FIXME: the schema should be replaced by user custom's - args := []interface{}{tableName, "public"} - s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix , - CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, - CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey -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 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;` - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if 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) { - // FIXME: replace public to user customrize schema - args := []interface{}{"public"} - s := fmt.Sprintf("SELECT tablename FROM pg_tables WHERE schemaname = $1") - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if 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 (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { - // FIXME: replace the public schema to user specify schema - args := []interface{}{"public", tableName} - s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname=$1 AND tablename=$2") - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if 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 - } - cs := strings.Split(indexdef, "(") - colNames = strings.Split(cs[1][0:len(cs[1])-1], ",") - - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - newIdxName := indexName[5+len(tableName):] - 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, `" `)) - } - 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}} -} diff --git a/vendor/github.com/go-xorm/xorm/pq_driver.go b/vendor/github.com/go-xorm/xorm/pq_driver.go deleted file mode 100644 index 5d608f25..00000000 --- a/vendor/github.com/go-xorm/xorm/pq_driver.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "net/url" - "sort" - "strings" - - "github.com/go-xorm/core" -) - -type pqDriver struct { -} - -type values map[string]string - -func (vs values) Set(k, v string) { - vs[k] = v -} - -func (vs values) Get(k string) (v string) { - return vs[k] -} - -func errorf(s string, args ...interface{}) { - panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) -} - -func parseURL(connstr string) (string, error) { - u, err := url.Parse(connstr) - if err != nil { - return "", err - } - - if u.Scheme != "postgresql" && u.Scheme != "postgres" { - return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) - } - - var kvs []string - escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) - accrue := func(k, v string) { - if v != "" { - kvs = append(kvs, k+"="+escaper.Replace(v)) - } - } - - if u.User != nil { - v := u.User.Username() - accrue("user", v) - - v, _ = u.User.Password() - accrue("password", v) - } - - i := strings.Index(u.Host, ":") - if i < 0 { - accrue("host", u.Host) - } else { - accrue("host", u.Host[:i]) - accrue("port", u.Host[i+1:]) - } - - if u.Path != "" { - accrue("dbname", u.Path[1:]) - } - - q := u.Query() - for k := range q { - accrue(k, q.Get(k)) - } - - sort.Strings(kvs) // Makes testing easier (not a performance concern) - return strings.Join(kvs, " "), nil -} - -func parseOpts(name string, o values) { - if len(name) == 0 { - return - } - - name = strings.TrimSpace(name) - - ps := strings.Split(name, " ") - for _, p := range ps { - kv := strings.Split(p, "=") - if len(kv) < 2 { - errorf("invalid option: %q", p) - } - o.Set(kv[0], kv[1]) - } -} - -func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.POSTGRES} - o := make(values) - var err error - if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") { - dataSourceName, err = parseURL(dataSourceName) - if err != nil { - return nil, err - } - } - parseOpts(dataSourceName, o) - - db.DbName = o.Get("dbname") - if db.DbName == "" { - return nil, errors.New("dbname is empty") - } - /*db.Schema = o.Get("schema") - if len(db.Schema) == 0 { - db.Schema = "public" - }*/ - return db, nil -} diff --git a/vendor/github.com/go-xorm/xorm/rows.go b/vendor/github.com/go-xorm/xorm/rows.go index d35040cd..47bc322f 100644 --- a/vendor/github.com/go-xorm/xorm/rows.go +++ b/vendor/github.com/go-xorm/xorm/rows.go @@ -16,13 +16,12 @@ import ( type Rows struct { NoTypeCheck bool - session *Session - stmt *core.Stmt - rows *core.Rows - fields []string - fieldsCount int - beanType reflect.Type - lastError error + session *Session + stmt *core.Stmt + rows *core.Rows + fields []string + beanType reflect.Type + lastError error } func newRows(session *Session, bean interface{}) (*Rows, error) { @@ -35,7 +34,10 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { var sqlStr string var args []interface{} - rows.session.Statement.setRefValue(rValue(bean)) + if err := rows.session.Statement.setRefValue(rValue(bean)); err != nil { + return nil, err + } + if len(session.Statement.TableName()) <= 0 { return nil, ErrTableNotFound } @@ -82,7 +84,6 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { rows.Close() return nil, err } - rows.fieldsCount = len(rows.fields) return rows, nil } @@ -114,7 +115,13 @@ func (rows *Rows) Scan(bean interface{}) error { return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType) } - return rows.session.row2Bean(rows.rows, rows.fields, rows.fieldsCount, bean) + dataStruct := rValue(bean) + if err := rows.session.Statement.setRefValue(dataStruct); err != nil { + return err + } + _, err := rows.session.row2Bean(rows.rows, rows.fields, len(rows.fields), bean, &dataStruct, rows.session.Statement.RefTable) + + return err } // Close session if session.IsAutoClose is true, and claimed any opened resources diff --git a/vendor/github.com/go-xorm/xorm/session.go b/vendor/github.com/go-xorm/xorm/session.go index 6e1b02af..475c769f 100644 --- a/vendor/github.com/go-xorm/xorm/session.go +++ b/vendor/github.com/go-xorm/xorm/session.go @@ -6,17 +6,14 @@ package xorm import ( "database/sql" - "database/sql/driver" "encoding/json" "errors" "fmt" "hash/crc32" "reflect" - "strconv" "strings" "time" - "github.com/go-xorm/builder" "github.com/go-xorm/core" ) @@ -29,7 +26,6 @@ type Session struct { Statement Statement IsAutoCommit bool IsCommitedOrRollbacked bool - TransType string IsAutoClose bool // Automatically reset the statement after operations that execute a SQL @@ -47,7 +43,6 @@ type Session struct { prepareStmt bool stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) - cascadeDeep int // !evalphobia! stored the last executed query on this session //beforeSQLExec func(string, ...interface{}) @@ -113,52 +108,6 @@ func (session *Session) Prepare() *Session { return session } -// 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 -} - // Before Apply before Processor, affected bean is passed to closure arg func (session *Session) Before(closures func(interface{})) *Session { if closures != nil { @@ -187,109 +136,18 @@ func (session *Session) Alias(alias string) *Session { 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 -} - -// 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 -} - // NoCascade indicate that no cascade load child object func (session *Session) NoCascade() *Session { session.Statement.UseCascade = false 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 -} - // ForUpdate Set Read/Write locking for UPDATE func (session *Session) ForUpdate() *Session { session.Statement.IsForUpdate = true 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 -} - // NoAutoCondition disable generate SQL condition from beans func (session *Session) NoAutoCondition(no ...bool) *Session { session.Statement.NoAutoCondition(no...) @@ -375,63 +233,12 @@ func (session *Session) DB() *core.DB { return session.db } -// Conds returns session query conditions -func (session *Session) Conds() builder.Cond { - return session.Statement.cond -} - func cleanupProcessorsClosures(slices *[]func(interface{})) { if len(*slices) > 0 { *slices = make([]func(interface{}), 0) } } -func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error { - dataStruct := rValue(obj) - if dataStruct.Kind() != reflect.Struct { - return errors.New("Expected a pointer to a struct") - } - - var col *core.Column - session.Statement.setRefValue(dataStruct) - table := session.Statement.RefTable - tableName := session.Statement.tableName - - for key, data := range objMap { - if col = table.GetColumn(key); col == nil { - session.Engine.logger.Warnf("struct %v's has not field %v. %v", - table.Type.Name(), key, table.ColumnsSeq()) - continue - } - - fieldName := col.FieldName - fieldPath := strings.Split(fieldName, ".") - var fieldValue reflect.Value - if len(fieldPath) > 2 { - session.Engine.logger.Error("Unsupported mutliderive", fieldName) - continue - } else if len(fieldPath) == 2 { - parentField := dataStruct.FieldByName(fieldPath[0]) - if parentField.IsValid() { - fieldValue = parentField.FieldByName(fieldPath[1]) - } - } else { - fieldValue = dataStruct.FieldByName(fieldName) - } - if !fieldValue.IsValid() || !fieldValue.CanSet() { - session.Engine.logger.Warnf("table %v's column %v is not valid or cannot set", tableName, key) - continue - } - - err := session.bytes2Value(col, &fieldValue, data) - if err != nil { - return err - } - } - - return nil -} - func (session *Session) canCache() bool { if session.Statement.RefTable == nil || session.Statement.JoinStr != "" || @@ -484,40 +291,38 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c type Cell *interface{} func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount int, - table *core.Table, newElemFunc func() reflect.Value, - sliceValueSetFunc func(*reflect.Value)) error { + table *core.Table, newElemFunc func([]string) reflect.Value, + sliceValueSetFunc func(*reflect.Value, core.PK) error) error { for rows.Next() { - var newValue = newElemFunc() + var newValue = newElemFunc(fields) bean := newValue.Interface() dataStruct := rValue(bean) - err := session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table) + pk, err := session.row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table) + if err != nil { + return err + } + + err = sliceValueSetFunc(&newValue, pk) if err != nil { return err } - sliceValueSetFunc(&newValue) } return nil } -func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error { - dataStruct := rValue(bean) - if dataStruct.Kind() != reflect.Struct { - return errors.New("Expected a pointer to a struct") +func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) { + // handle beforeClosures + for _, closure := range session.beforeClosures { + closure(bean) } - session.Statement.setRefValue(dataStruct) - - return session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, session.Statement.RefTable) -} - -func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error { scanResults := make([]interface{}, fieldsCount) for i := 0; i < len(fields); i++ { var cell interface{} scanResults[i] = &cell } if err := rows.Scan(scanResults...); err != nil { - return err + return nil, err } if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet { @@ -532,9 +337,24 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount b.AfterSet(key, Cell(scanResults[ii].(*interface{}))) } } + + // handle afterClosures + for _, closure := range session.afterClosures { + closure(bean) + } }() + dbTZ := session.Engine.DatabaseTZ + if dbTZ == nil { + if session.Engine.dialect.DBType() == core.SQLITE { + dbTZ = time.UTC + } else { + dbTZ = time.Local + } + } + var tempMap = make(map[string]int) + var pk core.PK for ii, key := range fields { var idx int var ok bool @@ -557,9 +377,11 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if fieldValue.CanAddr() { if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { if data, err := value2Bytes(&rawValue); err == nil { - structConvert.FromDB(data) + if err := structConvert.FromDB(data); err != nil { + return nil, err + } } else { - session.Engine.logger.Error(err) + return nil, err } continue } @@ -572,17 +394,19 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount } fieldValue.Interface().(core.Conversion).FromDB(data) } else { - session.Engine.logger.Error(err) + 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 - col := table.GetColumnIdx(key, idx) if col.SQLType.IsJson() { var bs []byte @@ -591,7 +415,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount } else if rawValueType.ConvertibleTo(core.BytesType) { bs = vv.Bytes() } else { - return fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind()) + return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind()) } hasAssigned = true @@ -600,15 +424,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if fieldValue.CanAddr() { err := json.Unmarshal(bs, fieldValue.Addr().Interface()) if err != nil { - session.Engine.logger.Error(key, err) - return err + return nil, err } } else { x := reflect.New(fieldType) err := json.Unmarshal(bs, x.Interface()) if err != nil { - session.Engine.logger.Error(key, err) - return err + return nil, err } fieldValue.Set(x.Elem()) } @@ -632,15 +454,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if fieldValue.CanAddr() { err := json.Unmarshal(bs, fieldValue.Addr().Interface()) if err != nil { - session.Engine.logger.Error(err) - return err + return nil, err } } else { x := reflect.New(fieldType) err := json.Unmarshal(bs, x.Interface()) if err != nil { - session.Engine.logger.Error(err) - return err + return nil, err } fieldValue.Set(x.Elem()) } @@ -652,7 +472,26 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount case reflect.Uint8: if fieldType.Elem().Kind() == reflect.Uint8 { hasAssigned = true - fieldValue.Set(vv) + if col.SQLType.IsText() { + x := reflect.New(fieldType) + err := json.Unmarshal(vv.Bytes(), x.Interface()) + if err != nil { + return nil, err + } + fieldValue.Set(x.Elem()) + } else { + if fieldValue.Len() > 0 { + for i := 0; i < fieldValue.Len(); i++ { + if i < vv.Len() { + fieldValue.Index(i).Set(vv.Index(i)) + } + } + } else { + for i := 0; i < vv.Len(); i++ { + fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i))) + } + } + } } } } @@ -689,21 +528,19 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount } case reflect.Struct: if fieldType.ConvertibleTo(core.TimeType) { + var tz *time.Location + if col.TimeZone == nil { + tz = session.Engine.TZLocation + } else { + tz = col.TimeZone + } + if rawValueType == core.TimeType { hasAssigned = true t := vv.Convert(core.TimeType).Interface().(time.Time) z, _ := t.Zone() - dbTZ := session.Engine.DatabaseTZ - if dbTZ == nil { - if session.Engine.dialect.DBType() == core.SQLITE { - dbTZ = time.UTC - } else { - dbTZ = time.Local - } - } - // 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()) @@ -712,27 +549,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount } // !nashtsai! convert to engine location - if col.TimeZone == nil { - t = t.In(session.Engine.TZLocation) - } else { - t = t.In(col.TimeZone) - } + t = t.In(tz) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) - - // t = fieldValue.Interface().(time.Time) - // z, _ = t.Zone() - // session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) } else if rawValueType == core.IntType || rawValueType == core.Int64Type || rawValueType == core.Int32Type { hasAssigned = true - var tz *time.Location - if col.TimeZone == nil { - tz = session.Engine.TZLocation - } else { - tz = col.TimeZone - } + t := time.Unix(vv.Int(), 0).In(tz) - //vv = reflect.ValueOf(t) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) } else { if d, ok := vv.Interface().([]uint8); ok { @@ -771,8 +594,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if len([]byte(vv.String())) > 0 { err := json.Unmarshal([]byte(vv.String()), x.Interface()) if err != nil { - session.Engine.logger.Error(err) - return err + return nil, err } fieldValue.Set(x.Elem()) } @@ -782,76 +604,47 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if len(vv.Bytes()) > 0 { err := json.Unmarshal(vv.Bytes(), x.Interface()) if err != nil { - session.Engine.logger.Error(err) - return err + return nil, err } fieldValue.Set(x.Elem()) } } } else if session.Statement.UseCascade { - table := session.Engine.autoMapType(*fieldValue) - if table != nil { - hasAssigned = true - if len(table.PrimaryKeys) != 1 { - panic("unsupported non or composited primary key cascade") - } - var pk = make(core.PK, len(table.PrimaryKeys)) - - switch rawValueType.Kind() { - case reflect.Int64: - pk[0] = vv.Int() - case reflect.Int: - pk[0] = int(vv.Int()) - case reflect.Int32: - pk[0] = int32(vv.Int()) - case reflect.Int16: - pk[0] = int16(vv.Int()) - case reflect.Int8: - pk[0] = int8(vv.Int()) - case reflect.Uint64: - pk[0] = vv.Uint() - case reflect.Uint: - pk[0] = uint(vv.Uint()) - case reflect.Uint32: - pk[0] = uint32(vv.Uint()) - case reflect.Uint16: - pk[0] = uint16(vv.Uint()) - case reflect.Uint8: - pk[0] = uint8(vv.Uint()) - case reflect.String: - pk[0] = vv.String() - case reflect.Slice: - pk[0], _ = strconv.ParseInt(string(rawValue.Interface().([]byte)), 10, 64) - default: - panic(fmt.Sprintf("unsupported primary key type: %v, %v", rawValueType, fieldValue)) - } + table, err := session.Engine.autoMapType(*fieldValue) + 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()) - newsession := session.Engine.NewSession() - defer newsession.Close() - has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) - if err != nil { - return err - } - if has { - //v := structInter.Elem().Interface() - //fieldValue.Set(reflect.ValueOf(v)) - fieldValue.Set(structInter.Elem()) - } else { - return errors.New("cascade obj is not exist") - } + hasAssigned = true + if len(table.PrimaryKeys) != 1 { + panic("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()) + newsession := session.Engine.NewSession() + defer newsession.Close() + has, err := newsession.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") } - } else { - session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String()) } } case reflect.Ptr: // !nashtsai! TODO merge duplicated codes above - //typeStr := fieldType.String() switch fieldType { // following types case matching ptr's native type, therefore assign ptr directly case core.PtrStringType: @@ -949,10 +742,9 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if len([]byte(vv.String())) > 0 { err := json.Unmarshal([]byte(vv.String()), &x) if err != nil { - session.Engine.logger.Error(err) - } else { - fieldValue.Set(reflect.ValueOf(&x)) + return nil, err } + fieldValue.Set(reflect.ValueOf(&x)) } hasAssigned = true case core.Complex128Type: @@ -960,29 +752,28 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount if len([]byte(vv.String())) > 0 { err := json.Unmarshal([]byte(vv.String()), &x) if err != nil { - session.Engine.logger.Error(err) - } else { - fieldValue.Set(reflect.ValueOf(&x)) + return nil, err } + fieldValue.Set(reflect.ValueOf(&x)) } hasAssigned = true } // switch fieldType - // default: - // session.Engine.LogError("unsupported type in Scan: ", reflect.TypeOf(v).String()) } // 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 { - session.bytes2Value(col, fieldValue, data) - } else { - session.Engine.logger.Error(err.Error()) + if err != nil { + return nil, err + } + + if err = session.bytes2Value(col, fieldValue, data); err != nil { + return nil, err } } } } - return nil + return pk, nil } func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { @@ -993,657 +784,6 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) session.saveLastSQL(*sqlStr, paramStr...) } -func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { - sdata := strings.TrimSpace(data) - var x time.Time - var err error - - if sdata == "0000-00-00 00:00:00" || - sdata == "0001-01-01 00:00:00" { - } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column - // time stamp - sd, err := strconv.ParseInt(sdata, 10, 64) - if err == nil { - x = time.Unix(sd, 0) - // !nashtsai! HACK mymysql driver is causing Local location being change to CHAT and cause wrong time conversion - if col.TimeZone == nil { - x = x.In(session.Engine.TZLocation) - } else { - x = x.In(col.TimeZone) - } - session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else { - session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - } else if len(sdata) > 19 && strings.Contains(sdata, "-") { - x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - if err != nil { - x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - if err != nil { - x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - - } else if len(sdata) == 19 && strings.Contains(sdata, "-") { - x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { - x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else if col.SQLType.Name == core.Time { - if strings.Contains(sdata, " ") { - ssd := strings.Split(sdata, " ") - sdata = ssd[1] - } - - sdata = strings.TrimSpace(sdata) - if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { - sdata = sdata[len(sdata)-8:] - } - - st := fmt.Sprintf("2006-01-02 %v", sdata) - x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation) - session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else { - outErr = fmt.Errorf("unsupported time format %v", sdata) - return - } - if err != nil { - outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) - return - } - outTime = x - return -} - -func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) { - return session.str2Time(col, string(data)) -} - -// convert a db data([]byte) to a field value -func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { - if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - return structConvert.FromDB(data) - } - - if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { - return structConvert.FromDB(data) - } - - var v interface{} - key := col.Name - fieldType := fieldValue.Type() - - switch fieldType.Kind() { - case reflect.Complex64, reflect.Complex128: - x := reflect.New(fieldType) - if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - case reflect.Slice, reflect.Array, reflect.Map: - v = data - t := fieldType.Elem() - k := t.Kind() - if col.SQLType.IsText() { - x := reflect.New(fieldType) - if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - } else if col.SQLType.IsBlob() { - if k == reflect.Uint8 { - fieldValue.Set(reflect.ValueOf(v)) - } else { - x := reflect.New(fieldType) - if len(data) > 0 { - err := json.Unmarshal(data, x.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - } - } else { - return ErrUnSupportedType - } - case reflect.String: - fieldValue.SetString(string(data)) - case reflect.Bool: - d := string(data) - v, err := strconv.ParseBool(d) - if err != nil { - return fmt.Errorf("arg %v as bool: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(v)) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - sdata := string(data) - var x int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API - if len(data) == 1 { - x = int64(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x, err = strconv.ParseInt(sdata, 16, 64) - } else if strings.HasPrefix(sdata, "0") { - x, err = strconv.ParseInt(sdata, 8, 64) - } else if strings.EqualFold(sdata, "true") { - x = 1 - } else if strings.EqualFold(sdata, "false") { - x = 0 - } else { - x, err = strconv.ParseInt(sdata, 10, 64) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.SetInt(x) - case reflect.Float32, reflect.Float64: - x, err := strconv.ParseFloat(string(data), 64) - if err != nil { - return fmt.Errorf("arg %v as float64: %s", key, err.Error()) - } - fieldValue.SetFloat(x) - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - x, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.SetUint(x) - //Currently only support Time type - case reflect.Struct: - // !! 增加支持sql.Scanner接口的结构,如sql.NullString - if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { - if err := nulVal.Scan(data); err != nil { - return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error()) - } - } else { - if fieldType.ConvertibleTo(core.TimeType) { - x, err := session.byte2Time(col, data) - if err != nil { - return err - } - v = x - fieldValue.Set(reflect.ValueOf(v).Convert(fieldType)) - } else if session.Statement.UseCascade { - table := session.Engine.autoMapType(*fieldValue) - if table != nil { - // TODO: current only support 1 primary key - if len(table.PrimaryKeys) > 1 { - panic("unsupported composited primary key cascade") - } - var pk = make(core.PK, len(table.PrimaryKeys)) - rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) - var err error - pk[0], err = str2PK(string(data), rawValueType) - if err != nil { - return err - } - - if !isPKZero(pk) { - // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch - // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne - // property to be fetched lazily - structInter := reflect.New(fieldValue.Type()) - newsession := session.Engine.NewSession() - defer newsession.Close() - has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) - if err != nil { - return err - } - if has { - v = structInter.Elem().Interface() - fieldValue.Set(reflect.ValueOf(v)) - } else { - return errors.New("cascade obj is not exist") - } - } - } else { - return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) - } - } - } - case reflect.Ptr: - // !nashtsai! TODO merge duplicated codes above - //typeStr := fieldType.String() - switch fieldType.Elem().Kind() { - // case "*string": - case core.StringType.Kind(): - x := string(data) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*bool": - case core.BoolType.Kind(): - d := string(data) - v, err := strconv.ParseBool(d) - if err != nil { - return fmt.Errorf("arg %v as bool: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType)) - // case "*complex64": - case core.Complex64Type.Kind(): - var x complex64 - if len(data) > 0 { - err := json.Unmarshal(data, &x) - if err != nil { - session.Engine.logger.Error(err) - return err - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - } - // case "*complex128": - case core.Complex128Type.Kind(): - var x complex128 - if len(data) > 0 { - err := json.Unmarshal(data, &x) - if err != nil { - session.Engine.logger.Error(err) - return err - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - } - // case "*float64": - case core.Float64Type.Kind(): - x, err := strconv.ParseFloat(string(data), 64) - if err != nil { - return fmt.Errorf("arg %v as float64: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*float32": - case core.Float32Type.Kind(): - var x float32 - x1, err := strconv.ParseFloat(string(data), 32) - if err != nil { - return fmt.Errorf("arg %v as float32: %s", key, err.Error()) - } - x = float32(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint64": - case core.Uint64Type.Kind(): - var x uint64 - x, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint": - case core.UintType.Kind(): - var x uint - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint32": - case core.Uint32Type.Kind(): - var x uint32 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint32(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint8": - case core.Uint8Type.Kind(): - var x uint8 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint8(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint16": - case core.Uint16Type.Kind(): - var x uint16 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint16(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int64": - case core.Int64Type.Kind(): - sdata := string(data) - var x int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.Engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int64(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x, err = strconv.ParseInt(sdata, 16, 64) - } else if strings.HasPrefix(sdata, "0") { - x, err = strconv.ParseInt(sdata, 8, 64) - } else { - x, err = strconv.ParseInt(sdata, 10, 64) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int": - case core.IntType.Kind(): - sdata := string(data) - var x int - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.Engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int32": - case core.Int32Type.Kind(): - sdata := string(data) - var x int32 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - session.Engine.dialect.DBType() == core.MYSQL { - if len(data) == 1 { - x = int32(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int32(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int32(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int32(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int8": - case core.Int8Type.Kind(): - sdata := string(data) - var x int8 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.Engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int8(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int8(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int8(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int8(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int16": - case core.Int16Type.Kind(): - sdata := string(data) - var x int16 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.Engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int16(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int16(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int16(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int16(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*SomeStruct": - case reflect.Struct: - switch fieldType { - // case "*.time.Time": - case core.PtrTimeType: - x, err := session.byte2Time(col, data) - if err != nil { - return err - } - v = x - fieldValue.Set(reflect.ValueOf(&x)) - default: - if session.Statement.UseCascade { - structInter := reflect.New(fieldType.Elem()) - table := session.Engine.autoMapType(structInter.Elem()) - if table != nil { - if len(table.PrimaryKeys) > 1 { - panic("unsupported composited primary key cascade") - } - var pk = make(core.PK, len(table.PrimaryKeys)) - var err error - rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) - pk[0], err = str2PK(string(data), rawValueType) - if err != nil { - return err - } - - if !isPKZero(pk) { - // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch - // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne - // property to be fetched lazily - newsession := session.Engine.NewSession() - defer newsession.Close() - has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) - if err != nil { - return err - } - if has { - v = structInter.Interface() - fieldValue.Set(reflect.ValueOf(v)) - } else { - return errors.New("cascade obj is not exist") - } - } - } - } else { - return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) - } - } - default: - return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) - } - default: - return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) - } - - return nil -} - -// convert a field value of a struct to interface for put into db -func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) { - if fieldValue.CanAddr() { - if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - data, err := fieldConvert.ToDB() - if err != nil { - return 0, err - } - if col.SQLType.IsBlob() { - return data, nil - } - return string(data), nil - } - } - - if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok { - data, err := fieldConvert.ToDB() - if err != nil { - return 0, err - } - if col.SQLType.IsBlob() { - return data, nil - } - return string(data), nil - } - - fieldType := fieldValue.Type() - k := fieldType.Kind() - if k == reflect.Ptr { - if fieldValue.IsNil() { - return nil, nil - } else if !fieldValue.IsValid() { - session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid") - return nil, nil - } else { - // !nashtsai! deference pointer type to instance type - fieldValue = fieldValue.Elem() - fieldType = fieldValue.Type() - k = fieldType.Kind() - } - } - - switch k { - case reflect.Bool: - return fieldValue.Bool(), nil - case reflect.String: - return fieldValue.String(), nil - case reflect.Struct: - if fieldType.ConvertibleTo(core.TimeType) { - t := fieldValue.Convert(core.TimeType).Interface().(time.Time) - if session.Engine.dialect.DBType() == core.MSSQL { - if t.IsZero() { - return nil, nil - } - } - tf := session.Engine.FormatTime(col.SQLType.Name, t) - return tf, nil - } - - if !col.SQLType.IsJson() { - // !! 增加支持driver.Valuer接口的结构,如sql.NullString - if v, ok := fieldValue.Interface().(driver.Valuer); ok { - return v.Value() - } - - fieldTable := session.Engine.autoMapType(fieldValue) - if len(fieldTable.PrimaryKeys) == 1 { - pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName) - return pkField.Interface(), nil - } - return 0, fmt.Errorf("no primary key for col %v", col.Name) - } - - if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - } else if col.SQLType.IsBlob() { - bytes, err := json.Marshal(fieldValue.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return 0, err - } - return bytes, nil - } - return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) - case reflect.Complex64, reflect.Complex128: - bytes, err := json.Marshal(fieldValue.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - case reflect.Array, reflect.Slice, reflect.Map: - if !fieldValue.IsValid() { - return fieldValue.Interface(), nil - } - - if col.SQLType.IsText() { - bytes, err := json.Marshal(fieldValue.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - } else if col.SQLType.IsBlob() { - var bytes []byte - var err error - if (k == reflect.Array || k == reflect.Slice) && - (fieldValue.Type().Elem().Kind() == reflect.Uint8) { - bytes = fieldValue.Bytes() - } else { - bytes, err = json.Marshal(fieldValue.Interface()) - if err != nil { - session.Engine.logger.Error(err) - return 0, err - } - } - return bytes, nil - } - return nil, ErrUnSupportedType - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return int64(fieldValue.Uint()), nil - default: - return fieldValue.Interface(), nil - } -} - // saveLastSQL stores executed query information func (session *Session) saveLastSQL(sql string, args ...interface{}) { session.lastSQL = sql diff --git a/vendor/github.com/go-xorm/xorm/session_cols.go b/vendor/github.com/go-xorm/xorm/session_cols.go new file mode 100644 index 00000000..91185def --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/session_cols.go @@ -0,0 +1,84 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +// Incr provides a query string like "count = count + 1" +func (session *Session) Incr(column string, arg ...interface{}) *Session { + session.Statement.Incr(column, arg...) + return session +} + +// Decr provides a query string like "count = count - 1" +func (session *Session) Decr(column string, arg ...interface{}) *Session { + session.Statement.Decr(column, arg...) + return session +} + +// SetExpr provides a query string like "column = {expression}" +func (session *Session) SetExpr(column string, expression string) *Session { + session.Statement.SetExpr(column, expression) + return session +} + +// Select provides some columns to special +func (session *Session) Select(str string) *Session { + session.Statement.Select(str) + return session +} + +// Cols provides some columns to special +func (session *Session) Cols(columns ...string) *Session { + session.Statement.Cols(columns...) + return session +} + +// AllCols ask all columns +func (session *Session) AllCols() *Session { + session.Statement.AllCols() + return session +} + +// MustCols specify some columns must use even if they are empty +func (session *Session) MustCols(columns ...string) *Session { + session.Statement.MustCols(columns...) + return session +} + +// UseBool automatically retrieve condition according struct, but +// if struct has bool field, it will ignore them. So use UseBool +// to tell system to do not ignore them. +// If no parameters, it will use all the bool field of struct, or +// it will use parameters's columns +func (session *Session) UseBool(columns ...string) *Session { + session.Statement.UseBool(columns...) + return session +} + +// Distinct use for distinct columns. Caution: when you are using cache, +// distinct will not be cached because cache system need id, +// but distinct will not provide id +func (session *Session) Distinct(columns ...string) *Session { + session.Statement.Distinct(columns...) + return session +} + +// Omit Only not use the parameters as select or update columns +func (session *Session) Omit(columns ...string) *Session { + session.Statement.Omit(columns...) + return session +} + +// Nullable Set null when column is zero-value and nullable for update +func (session *Session) Nullable(columns ...string) *Session { + session.Statement.Nullable(columns...) + return session +} + +// NoAutoTime means do not automatically give created field and updated field +// the current time on the current session temporarily +func (session *Session) NoAutoTime() *Session { + session.Statement.UseAutoTime = false + return session +} diff --git a/vendor/github.com/go-xorm/xorm/session_cond.go b/vendor/github.com/go-xorm/xorm/session_cond.go new file mode 100644 index 00000000..948a90bc --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/session_cond.go @@ -0,0 +1,70 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import "github.com/go-xorm/builder" + +// Sql provides raw sql input parameter. When you have a complex SQL statement +// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. +// +// Deprecated: use SQL instead. +func (session *Session) Sql(query string, args ...interface{}) *Session { + return session.SQL(query, args...) +} + +// SQL provides raw sql input parameter. When you have a complex SQL statement +// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. +func (session *Session) SQL(query interface{}, args ...interface{}) *Session { + session.Statement.SQL(query, args...) + return session +} + +// Where provides custom query condition. +func (session *Session) Where(query interface{}, args ...interface{}) *Session { + session.Statement.Where(query, args...) + return session +} + +// And provides custom query condition. +func (session *Session) And(query interface{}, args ...interface{}) *Session { + session.Statement.And(query, args...) + return session +} + +// Or provides custom query condition. +func (session *Session) Or(query interface{}, args ...interface{}) *Session { + session.Statement.Or(query, args...) + return session +} + +// Id provides converting id as a query condition +// +// Deprecated: use ID instead +func (session *Session) Id(id interface{}) *Session { + return session.ID(id) +} + +// ID provides converting id as a query condition +func (session *Session) ID(id interface{}) *Session { + session.Statement.ID(id) + return session +} + +// In provides a query string like "id in (1, 2, 3)" +func (session *Session) In(column string, args ...interface{}) *Session { + session.Statement.In(column, args...) + return session +} + +// NotIn provides a query string like "id in (1, 2, 3)" +func (session *Session) NotIn(column string, args ...interface{}) *Session { + session.Statement.NotIn(column, args...) + return session +} + +// Conds returns session query conditions +func (session *Session) Conds() builder.Cond { + return session.Statement.cond +} diff --git a/vendor/github.com/go-xorm/xorm/session_convert.go b/vendor/github.com/go-xorm/xorm/session_convert.go new file mode 100644 index 00000000..7ef57b5f --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/session_convert.go @@ -0,0 +1,673 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "time" + + "github.com/go-xorm/core" +) + +func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { + sdata := strings.TrimSpace(data) + var x time.Time + var err error + + if sdata == "0000-00-00 00:00:00" || + sdata == "0001-01-01 00:00:00" { + } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column + // time stamp + sd, err := strconv.ParseInt(sdata, 10, 64) + if err == nil { + x = time.Unix(sd, 0) + // !nashtsai! HACK mymysql driver is causing Local location being change to CHAT and cause wrong time conversion + if col.TimeZone == nil { + x = x.In(session.Engine.TZLocation) + } else { + x = x.In(col.TimeZone) + } + session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } else { + session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } + } else if len(sdata) > 19 && strings.Contains(sdata, "-") { + x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + if err != nil { + x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } + if err != nil { + x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } + + } else if len(sdata) == 19 && strings.Contains(sdata, "-") { + x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { + x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } else if col.SQLType.Name == core.Time { + if strings.Contains(sdata, " ") { + ssd := strings.Split(sdata, " ") + sdata = ssd[1] + } + + sdata = strings.TrimSpace(sdata) + if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { + sdata = sdata[len(sdata)-8:] + } + + st := fmt.Sprintf("2006-01-02 %v", sdata) + x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation) + session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) + } else { + outErr = fmt.Errorf("unsupported time format %v", sdata) + return + } + if err != nil { + outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) + return + } + outTime = x + return +} + +func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) { + return session.str2Time(col, string(data)) +} + +// convert a db data([]byte) to a field value +func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { + if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { + return structConvert.FromDB(data) + } + + if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { + return structConvert.FromDB(data) + } + + var v interface{} + key := col.Name + fieldType := fieldValue.Type() + + switch fieldType.Kind() { + case reflect.Complex64, reflect.Complex128: + x := reflect.New(fieldType) + if len(data) > 0 { + err := json.Unmarshal(data, x.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return err + } + fieldValue.Set(x.Elem()) + } + case reflect.Slice, reflect.Array, reflect.Map: + v = data + t := fieldType.Elem() + k := t.Kind() + if col.SQLType.IsText() { + x := reflect.New(fieldType) + if len(data) > 0 { + err := json.Unmarshal(data, x.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return err + } + fieldValue.Set(x.Elem()) + } + } else if col.SQLType.IsBlob() { + if k == reflect.Uint8 { + fieldValue.Set(reflect.ValueOf(v)) + } else { + x := reflect.New(fieldType) + if len(data) > 0 { + err := json.Unmarshal(data, x.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return err + } + fieldValue.Set(x.Elem()) + } + } + } else { + return ErrUnSupportedType + } + case reflect.String: + fieldValue.SetString(string(data)) + case reflect.Bool: + d := string(data) + v, err := strconv.ParseBool(d) + if err != nil { + return fmt.Errorf("arg %v as bool: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(v)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + sdata := string(data) + var x int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API + if len(data) == 1 { + x = int64(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x, err = strconv.ParseInt(sdata, 16, 64) + } else if strings.HasPrefix(sdata, "0") { + x, err = strconv.ParseInt(sdata, 8, 64) + } else if strings.EqualFold(sdata, "true") { + x = 1 + } else if strings.EqualFold(sdata, "false") { + x = 0 + } else { + x, err = strconv.ParseInt(sdata, 10, 64) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.SetInt(x) + case reflect.Float32, reflect.Float64: + x, err := strconv.ParseFloat(string(data), 64) + if err != nil { + return fmt.Errorf("arg %v as float64: %s", key, err.Error()) + } + fieldValue.SetFloat(x) + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + x, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.SetUint(x) + //Currently only support Time type + case reflect.Struct: + // !! 增加支持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 { + panic("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()) + newsession := session.Engine.NewSession() + defer newsession.Close() + has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) + if err != nil { + return err + } + if has { + v = structInter.Elem().Interface() + fieldValue.Set(reflect.ValueOf(v)) + } else { + return errors.New("cascade obj is not exist") + } + } + } + } + case reflect.Ptr: + // !nashtsai! TODO merge duplicated codes above + //typeStr := fieldType.String() + switch fieldType.Elem().Kind() { + // case "*string": + case core.StringType.Kind(): + x := string(data) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*bool": + case core.BoolType.Kind(): + d := string(data) + v, err := strconv.ParseBool(d) + if err != nil { + return fmt.Errorf("arg %v as bool: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType)) + // case "*complex64": + case core.Complex64Type.Kind(): + var x complex64 + if len(data) > 0 { + err := json.Unmarshal(data, &x) + if err != nil { + session.Engine.logger.Error(err) + return err + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + } + // case "*complex128": + case core.Complex128Type.Kind(): + var x complex128 + if len(data) > 0 { + err := json.Unmarshal(data, &x) + if err != nil { + session.Engine.logger.Error(err) + return err + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + } + // case "*float64": + case core.Float64Type.Kind(): + x, err := strconv.ParseFloat(string(data), 64) + if err != nil { + return fmt.Errorf("arg %v as float64: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*float32": + case core.Float32Type.Kind(): + var x float32 + x1, err := strconv.ParseFloat(string(data), 32) + if err != nil { + return fmt.Errorf("arg %v as float32: %s", key, err.Error()) + } + x = float32(x1) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*uint64": + case core.Uint64Type.Kind(): + var x uint64 + x, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*uint": + case core.UintType.Kind(): + var x uint + x1, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + x = uint(x1) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*uint32": + case core.Uint32Type.Kind(): + var x uint32 + x1, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + x = uint32(x1) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*uint8": + case core.Uint8Type.Kind(): + var x uint8 + x1, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + x = uint8(x1) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*uint16": + case core.Uint16Type.Kind(): + var x uint16 + x1, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + x = uint16(x1) + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*int64": + case core.Int64Type.Kind(): + sdata := string(data) + var x int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + strings.Contains(session.Engine.DriverName(), "mysql") { + if len(data) == 1 { + x = int64(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x, err = strconv.ParseInt(sdata, 16, 64) + } else if strings.HasPrefix(sdata, "0") { + x, err = strconv.ParseInt(sdata, 8, 64) + } else { + x, err = strconv.ParseInt(sdata, 10, 64) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*int": + case core.IntType.Kind(): + sdata := string(data) + var x int + var x1 int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + strings.Contains(session.Engine.DriverName(), "mysql") { + if len(data) == 1 { + x = int(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x1, err = strconv.ParseInt(sdata, 16, 64) + x = int(x1) + } else if strings.HasPrefix(sdata, "0") { + x1, err = strconv.ParseInt(sdata, 8, 64) + x = int(x1) + } else { + x1, err = strconv.ParseInt(sdata, 10, 64) + x = int(x1) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*int32": + case core.Int32Type.Kind(): + sdata := string(data) + var x int32 + var x1 int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + session.Engine.dialect.DBType() == core.MYSQL { + if len(data) == 1 { + x = int32(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x1, err = strconv.ParseInt(sdata, 16, 64) + x = int32(x1) + } else if strings.HasPrefix(sdata, "0") { + x1, err = strconv.ParseInt(sdata, 8, 64) + x = int32(x1) + } else { + x1, err = strconv.ParseInt(sdata, 10, 64) + x = int32(x1) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*int8": + case core.Int8Type.Kind(): + sdata := string(data) + var x int8 + var x1 int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + strings.Contains(session.Engine.DriverName(), "mysql") { + if len(data) == 1 { + x = int8(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x1, err = strconv.ParseInt(sdata, 16, 64) + x = int8(x1) + } else if strings.HasPrefix(sdata, "0") { + x1, err = strconv.ParseInt(sdata, 8, 64) + x = int8(x1) + } else { + x1, err = strconv.ParseInt(sdata, 10, 64) + x = int8(x1) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*int16": + case core.Int16Type.Kind(): + sdata := string(data) + var x int16 + var x1 int64 + var err error + // for mysql, when use bit, it returned \x01 + if col.SQLType.Name == core.Bit && + strings.Contains(session.Engine.DriverName(), "mysql") { + if len(data) == 1 { + x = int16(data[0]) + } else { + x = 0 + } + } else if strings.HasPrefix(sdata, "0x") { + x1, err = strconv.ParseInt(sdata, 16, 64) + x = int16(x1) + } else if strings.HasPrefix(sdata, "0") { + x1, err = strconv.ParseInt(sdata, 8, 64) + x = int16(x1) + } else { + x1, err = strconv.ParseInt(sdata, 10, 64) + x = int16(x1) + } + if err != nil { + return fmt.Errorf("arg %v as int: %s", key, err.Error()) + } + fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) + // case "*SomeStruct": + case reflect.Struct: + switch fieldType { + // case "*.time.Time": + case core.PtrTimeType: + x, err := session.byte2Time(col, data) + if err != nil { + return err + } + v = x + fieldValue.Set(reflect.ValueOf(&x)) + default: + if session.Statement.UseCascade { + structInter := reflect.New(fieldType.Elem()) + table, err := session.Engine.autoMapType(structInter.Elem()) + if err != nil { + return err + } + + if len(table.PrimaryKeys) > 1 { + panic("unsupported composited primary key cascade") + } + var pk = make(core.PK, len(table.PrimaryKeys)) + rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) + pk[0], err = str2PK(string(data), rawValueType) + if err != nil { + return err + } + + if !isPKZero(pk) { + // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch + // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne + // property to be fetched lazily + newsession := session.Engine.NewSession() + defer newsession.Close() + has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) + if err != nil { + return err + } + if has { + v = structInter.Interface() + fieldValue.Set(reflect.ValueOf(v)) + } else { + return errors.New("cascade obj is not exist") + } + } + } else { + return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) + } + } + default: + return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) + } + default: + return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) + } + + return nil +} + +// convert a field value of a struct to interface for put into db +func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) { + if fieldValue.CanAddr() { + if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { + data, err := fieldConvert.ToDB() + if err != nil { + return 0, err + } + if col.SQLType.IsBlob() { + return data, nil + } + return string(data), nil + } + } + + if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok { + data, err := fieldConvert.ToDB() + if err != nil { + return 0, err + } + if col.SQLType.IsBlob() { + return data, nil + } + return string(data), nil + } + + fieldType := fieldValue.Type() + k := fieldType.Kind() + if k == reflect.Ptr { + if fieldValue.IsNil() { + return nil, nil + } else if !fieldValue.IsValid() { + session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid") + return nil, nil + } else { + // !nashtsai! deference pointer type to instance type + fieldValue = fieldValue.Elem() + fieldType = fieldValue.Type() + k = fieldType.Kind() + } + } + + switch k { + case reflect.Bool: + return fieldValue.Bool(), nil + case reflect.String: + return fieldValue.String(), nil + case reflect.Struct: + if fieldType.ConvertibleTo(core.TimeType) { + t := fieldValue.Convert(core.TimeType).Interface().(time.Time) + if session.Engine.dialect.DBType() == core.MSSQL { + if t.IsZero() { + return nil, nil + } + } + tf := session.Engine.FormatTime(col.SQLType.Name, t) + return tf, nil + } + + if !col.SQLType.IsJson() { + // !! 增加支持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 := json.Marshal(fieldValue.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return 0, err + } + return string(bytes), nil + } else if col.SQLType.IsBlob() { + bytes, err := json.Marshal(fieldValue.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return 0, err + } + return bytes, nil + } + return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) + case reflect.Complex64, reflect.Complex128: + bytes, err := json.Marshal(fieldValue.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return 0, err + } + return string(bytes), nil + case reflect.Array, reflect.Slice, reflect.Map: + if !fieldValue.IsValid() { + return fieldValue.Interface(), nil + } + + if col.SQLType.IsText() { + bytes, err := json.Marshal(fieldValue.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return 0, err + } + return string(bytes), nil + } else if col.SQLType.IsBlob() { + var bytes []byte + var err error + if (k == reflect.Array || k == reflect.Slice) && + (fieldValue.Type().Elem().Kind() == reflect.Uint8) { + bytes = fieldValue.Bytes() + } else { + bytes, err = json.Marshal(fieldValue.Interface()) + if err != nil { + session.Engine.logger.Error(err) + return 0, err + } + } + return bytes, nil + } + return nil, ErrUnSupportedType + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return int64(fieldValue.Uint()), nil + default: + return fieldValue.Interface(), nil + } +} diff --git a/vendor/github.com/go-xorm/xorm/session_delete.go b/vendor/github.com/go-xorm/xorm/session_delete.go index 1c458fe1..0c1e705e 100644 --- a/vendor/github.com/go-xorm/xorm/session_delete.go +++ b/vendor/github.com/go-xorm/xorm/session_delete.go @@ -83,7 +83,9 @@ func (session *Session) Delete(bean interface{}) (int64, error) { defer session.Close() } - session.Statement.setRefValue(rValue(bean)) + if err := session.Statement.setRefValue(rValue(bean)); err != nil { + return 0, err + } var table = session.Statement.RefTable // handle before delete processors diff --git a/vendor/github.com/go-xorm/xorm/session_find.go b/vendor/github.com/go-xorm/xorm/session_find.go index 2e52fff3..16c6ff4f 100644 --- a/vendor/github.com/go-xorm/xorm/session_find.go +++ b/vendor/github.com/go-xorm/xorm/session_find.go @@ -41,16 +41,18 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) if sliceElementType.Kind() == reflect.Ptr { if sliceElementType.Elem().Kind() == reflect.Struct { pv := reflect.New(sliceElementType.Elem()) - session.Statement.setRefValue(pv.Elem()) + if err := session.Statement.setRefValue(pv.Elem()); err != nil { + return err + } } else { - //return errors.New("slice type") tp = tpNonStruct } } else if sliceElementType.Kind() == reflect.Struct { pv := reflect.New(sliceElementType) - session.Statement.setRefValue(pv.Elem()) + if err := session.Statement.setRefValue(pv.Elem()); err != nil { + return err + } } else { - //return errors.New("slice type") tp = tpNonStruct } } @@ -148,62 +150,10 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) } } - if sliceValue.Kind() != reflect.Map { - return session.noCacheFind(sliceValue, sqlStr, args...) - } - - resultsSlice, err := session.query(sqlStr, args...) - if err != nil { - return err - } - - keyType := sliceValue.Type().Key() - - for _, results := range resultsSlice { - var newValue reflect.Value - if sliceElementType.Kind() == reflect.Ptr { - newValue = reflect.New(sliceElementType.Elem()) - } else { - newValue = reflect.New(sliceElementType) - } - err := session.scanMapIntoStruct(newValue.Interface(), results) - if err != nil { - return err - } - var key interface{} - // if there is only one pk, we can put the id as map key. - if len(table.PrimaryKeys) == 1 { - key, err = str2PK(string(results[table.PrimaryKeys[0]]), keyType) - if err != nil { - return err - } - } else { - if keyType.Kind() != reflect.Slice { - panic("don't support multiple primary key's map has non-slice key type") - } else { - var keys core.PK = make([]interface{}, 0, len(table.PrimaryKeys)) - for _, pk := range table.PrimaryKeys { - skey, err := str2PK(string(results[pk]), keyType) - if err != nil { - return err - } - keys = append(keys, skey) - } - key = keys - } - } - - if sliceElementType.Kind() == reflect.Ptr { - sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(newValue.Interface())) - } else { - sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.Indirect(reflect.ValueOf(newValue.Interface()))) - } - } - - return nil + return session.noCacheFind(table, sliceValue, sqlStr, args...) } -func (session *Session) noCacheFind(sliceValue reflect.Value, sqlStr string, args ...interface{}) error { +func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { var rawRows *core.Rows var err error @@ -223,51 +173,112 @@ func (session *Session) noCacheFind(sliceValue reflect.Value, sqlStr string, arg return err } - var newElemFunc func() reflect.Value - sliceElementType := sliceValue.Type().Elem() - if sliceElementType.Kind() == reflect.Ptr { - newElemFunc = func() reflect.Value { - return reflect.New(sliceElementType.Elem()) - } - } else { - newElemFunc = func() reflect.Value { - return reflect.New(sliceElementType) + 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 sliceValueSetFunc func(*reflect.Value) + var containerValueSetFunc func(*reflect.Value, core.PK) error - if sliceValue.Kind() == reflect.Slice { - if sliceElementType.Kind() == reflect.Ptr { - sliceValueSetFunc = func(newValue *reflect.Value) { - sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(newValue.Interface()))) + 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())) } - } else { - sliceValueSetFunc = func(newValue *reflect.Value) { - sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface())))) + 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 } } - var newValue = newElemFunc() - dataStruct := rValue(newValue.Interface()) - if dataStruct.Kind() == reflect.Struct { - return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, sliceValueSetFunc) + if elemType.Kind() == reflect.Struct { + var newValue = newElemFunc(fields) + dataStruct := rValue(newValue.Interface()) + tb, err := session.Engine.autoMapType(dataStruct) + if err != nil { + return err + } + return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc) } for rawRows.Next() { - var newValue = newElemFunc() + var newValue = newElemFunc(fields) bean := newValue.Interface() - if err := rawRows.Scan(bean); err != nil { + switch elemType.Kind() { + case reflect.Slice: + err = rawRows.ScanSlice(bean) + case reflect.Map: + err = rawRows.ScanMap(bean) + default: + err = rawRows.Scan(bean) + } + + if err != nil { return err } - sliceValueSetFunc(&newValue) + 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 || @@ -404,7 +415,10 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in if rv.Kind() != reflect.Ptr { rv = rv.Addr() } - id := session.Engine.IdOfV(rv) + id, err := session.Engine.idOfV(rv) + if err != nil { + return err + } sid, err := id.ToString() if err != nil { return err diff --git a/vendor/github.com/go-xorm/xorm/session_get.go b/vendor/github.com/go-xorm/xorm/session_get.go index f32bf481..c7c03d90 100644 --- a/vendor/github.com/go-xorm/xorm/session_get.go +++ b/vendor/github.com/go-xorm/xorm/session_get.go @@ -20,7 +20,16 @@ func (session *Session) Get(bean interface{}) (bool, error) { defer session.Close() } - session.Statement.setRefValue(rValue(bean)) + beanValue := reflect.ValueOf(bean) + if beanValue.Kind() != reflect.Ptr { + return false, errors.New("needs a pointer") + } + + if beanValue.Elem().Kind() == reflect.Struct { + if err := session.Statement.setRefValue(beanValue.Elem()); err != nil { + return false, err + } + } var sqlStr string var args []interface{} @@ -36,7 +45,7 @@ func (session *Session) Get(bean interface{}) (bool, error) { args = session.Statement.RawParams } - if session.canCache() { + if session.canCache() && beanValue.Elem().Kind() == reflect.Struct { if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && !session.Statement.unscoped { has, err := session.cacheGet(bean, sqlStr, args...) @@ -46,13 +55,14 @@ func (session *Session) Get(bean interface{}) (bool, error) { } } - return session.nocacheGet(bean, sqlStr, args...) + return session.nocacheGet(beanValue.Elem().Kind(), bean, sqlStr, args...) } -func (session *Session) nocacheGet(bean interface{}, sqlStr string, args ...interface{}) (bool, error) { +func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) { + session.queryPreprocess(&sqlStr, args...) + var rawRows *core.Rows var err error - session.queryPreprocess(&sqlStr, args...) if session.IsAutoCommit { _, rawRows, err = session.innerQuery(sqlStr, args...) } else { @@ -65,10 +75,26 @@ func (session *Session) nocacheGet(bean interface{}, sqlStr string, args ...inte defer rawRows.Close() if rawRows.Next() { - fields, err := rawRows.Columns() - if err == nil { - err = session.row2Bean(rawRows, fields, len(fields), bean) + switch beanKind { + case reflect.Struct: + fields, err := rawRows.Columns() + if err != nil { + // WARN: Alougth rawRows return true, but get fields failed + return true, err + } + dataStruct := rValue(bean) + if err := session.Statement.setRefValue(dataStruct); err != nil { + return false, err + } + _, err = session.row2Bean(rawRows, fields, len(fields), bean, &dataStruct, session.Statement.RefTable) + case reflect.Slice: + err = rawRows.ScanSlice(bean) + case reflect.Map: + err = rawRows.ScanMap(bean) + default: + err = rawRows.Scan(bean) } + return true, err } return false, nil @@ -145,20 +171,8 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf } cacheBean := cacher.GetBean(tableName, sid) if cacheBean == nil { - /*newSession := session.Engine.NewSession() - defer newSession.Close() - cacheBean = reflect.New(structValue.Type()).Interface() - newSession.Id(id).NoCache() - if session.Statement.AltTableName != "" { - newSession.Table(session.Statement.AltTableName) - } - if !session.Statement.UseCascade { - newSession.NoCascade() - } - has, err = newSession.Get(cacheBean) - */ cacheBean = bean - has, err = session.nocacheGet(cacheBean, sqlStr, args...) + has, err = session.nocacheGet(reflect.Struct, cacheBean, sqlStr, args...) if err != nil || !has { return has, err } diff --git a/vendor/github.com/go-xorm/xorm/session_insert.go b/vendor/github.com/go-xorm/xorm/session_insert.go index 96e969c2..2c8ad782 100644 --- a/vendor/github.com/go-xorm/xorm/session_insert.go +++ b/vendor/github.com/go-xorm/xorm/session_insert.go @@ -67,7 +67,9 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error return 0, errors.New("could not insert a empty slice") } - session.Statement.setRefValue(sliceValue.Index(0)) + if err := session.Statement.setRefValue(sliceValue.Index(0)); err != nil { + return 0, err + } if len(session.Statement.TableName()) <= 0 { return 0, ErrTableNotFound @@ -210,13 +212,29 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error } cleanupProcessorsClosures(&session.beforeClosures) - statement := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", - session.Engine.Quote(session.Statement.TableName()), - session.Engine.QuoteStr(), - strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), - session.Engine.QuoteStr(), - strings.Join(colMultiPlaces, "),(")) - + var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)" + var statement string + if session.Engine.dialect.DBType() == core.ORACLE { + sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL" + temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (", + session.Engine.Quote(session.Statement.TableName()), + session.Engine.QuoteStr(), + strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), + session.Engine.QuoteStr()) + statement = fmt.Sprintf(sql, + session.Engine.Quote(session.Statement.TableName()), + session.Engine.QuoteStr(), + strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), + session.Engine.QuoteStr(), + strings.Join(colMultiPlaces, temp)) + } else { + statement = fmt.Sprintf(sql, + session.Engine.Quote(session.Statement.TableName()), + session.Engine.QuoteStr(), + strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), + session.Engine.QuoteStr(), + strings.Join(colMultiPlaces, "),(")) + } res, err := session.exec(statement, args...) if err != nil { return 0, err @@ -281,7 +299,9 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { } func (session *Session) innerInsert(bean interface{}) (int64, error) { - session.Statement.setRefValue(rValue(bean)) + if err := session.Statement.setRefValue(rValue(bean)); err != nil { + return 0, err + } if len(session.Statement.TableName()) <= 0 { return 0, ErrTableNotFound } diff --git a/vendor/github.com/go-xorm/xorm/session_raw.go b/vendor/github.com/go-xorm/xorm/session_raw.go index 9351d5cf..0f5a0a43 100644 --- a/vendor/github.com/go-xorm/xorm/session_raw.go +++ b/vendor/github.com/go-xorm/xorm/session_raw.go @@ -10,7 +10,7 @@ import ( "github.com/go-xorm/core" ) -func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { +func (session *Session) query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) { session.queryPreprocess(&sqlStr, paramStr...) if session.IsAutoCommit { @@ -19,7 +19,7 @@ func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSl return session.txQuery(session.Tx, sqlStr, paramStr...) } -func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) { +func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string][]byte, error) { rows, err := tx.Query(sqlStr, params...) if err != nil { return nil, err @@ -70,8 +70,8 @@ func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map return rows2maps(rows) } -// Query a raw sql and return records as []map[string][]byte -func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { +// Query runs a raw sql and return records as []map[string][]byte +func (session *Session) Query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) { defer session.resetStatement() if session.IsAutoClose { defer session.Close() @@ -80,16 +80,19 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl return session.query(sqlStr, paramStr...) } -// ============================= -// for string -// ============================= -func (session *Session) query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) { - session.queryPreprocess(&sqlStr, paramStr...) +// QueryString runs a raw sql and return records as []map[string]string +func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { + defer session.resetStatement() + if session.IsAutoClose { + defer session.Close() + } + + session.queryPreprocess(&sqlStr, args...) if session.IsAutoCommit { - return query2(session.DB(), sqlStr, paramStr...) + return query2(session.DB(), sqlStr, args...) } - return txQuery2(session.Tx, sqlStr, paramStr...) + return txQuery2(session.Tx, sqlStr, args...) } // Execute sql diff --git a/vendor/github.com/go-xorm/xorm/session_schema.go b/vendor/github.com/go-xorm/xorm/session_schema.go index 9011adad..19c0cbf5 100644 --- a/vendor/github.com/go-xorm/xorm/session_schema.go +++ b/vendor/github.com/go-xorm/xorm/session_schema.go @@ -27,7 +27,9 @@ func (session *Session) Ping() error { // CreateTable create a table according a bean func (session *Session) CreateTable(bean interface{}) error { v := rValue(bean) - session.Statement.setRefValue(v) + if err := session.Statement.setRefValue(v); err != nil { + return err + } defer session.resetStatement() if session.IsAutoClose { @@ -40,7 +42,9 @@ func (session *Session) CreateTable(bean interface{}) error { // CreateIndexes create indexes func (session *Session) CreateIndexes(bean interface{}) error { v := rValue(bean) - session.Statement.setRefValue(v) + if err := session.Statement.setRefValue(v); err != nil { + return err + } defer session.resetStatement() if session.IsAutoClose { @@ -60,7 +64,9 @@ func (session *Session) CreateIndexes(bean interface{}) error { // CreateUniques create uniques func (session *Session) CreateUniques(bean interface{}) error { v := rValue(bean) - session.Statement.setRefValue(v) + if err := session.Statement.setRefValue(v); err != nil { + return err + } defer session.resetStatement() if session.IsAutoClose { @@ -104,7 +110,9 @@ func (session *Session) createAll() error { // DropIndexes drop indexes func (session *Session) DropIndexes(bean interface{}) error { v := rValue(bean) - session.Statement.setRefValue(v) + if err := session.Statement.setRefValue(v); err != nil { + return err + } defer session.resetStatement() if session.IsAutoClose { @@ -306,7 +314,10 @@ func (session *Session) Sync2(beans ...interface{}) error { for _, bean := range beans { v := rValue(bean) - table := engine.mapType(v) + table, err := engine.mapType(v) + if err != nil { + return err + } structTables = append(structTables, table) var tbName = session.tbNameNoSchema(table) diff --git a/vendor/github.com/go-xorm/xorm/session_sum.go b/vendor/github.com/go-xorm/xorm/session_sum.go index 127f83f2..e1409c7f 100644 --- a/vendor/github.com/go-xorm/xorm/session_sum.go +++ b/vendor/github.com/go-xorm/xorm/session_sum.go @@ -123,7 +123,7 @@ func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int6 session.queryPreprocess(&sqlStr, args...) var err error - var res = make([]int64, 0, len(columnNames)) + var res = make([]int64, len(columnNames), len(columnNames)) if session.IsAutoCommit { err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res) } else { diff --git a/vendor/github.com/go-xorm/xorm/session_update.go b/vendor/github.com/go-xorm/xorm/session_update.go index 27e2deb0..1d77d294 100644 --- a/vendor/github.com/go-xorm/xorm/session_update.go +++ b/vendor/github.com/go-xorm/xorm/session_update.go @@ -169,7 +169,9 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 var isMap = t.Kind() == reflect.Map var isStruct = t.Kind() == reflect.Struct if isStruct { - session.Statement.setRefValue(v) + if err := session.Statement.setRefValue(v); err != nil { + return 0, err + } if len(session.Statement.TableName()) <= 0 { return 0, ErrTableNotFound @@ -253,48 +255,59 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 var condSQL string cond := session.Statement.cond.And(autoCond) - doIncVer := false + var doIncVer = (table != nil && table.Version != "" && session.Statement.checkVersion) var verValue *reflect.Value - if table != nil && table.Version != "" && session.Statement.checkVersion { + if doIncVer { verValue, err = table.VersionColumn().ValueOf(bean) if err != nil { return 0, err } cond = cond.And(builder.Eq{session.Engine.Quote(table.Version): verValue.Interface()}) - condSQL, condArgs, _ = builder.ToSQL(cond) - - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } - - if st.LimitN > 0 { - condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) - } + colNames = append(colNames, session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1") + } - sqlStr = fmt.Sprintf("UPDATE %v SET %v, %v %v", - session.Engine.Quote(session.Statement.TableName()), - strings.Join(colNames, ", "), - session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1", - condSQL) + condSQL, condArgs, _ = builder.ToSQL(cond) + if len(condSQL) > 0 { + condSQL = "WHERE " + condSQL + } - doIncVer = true - } else { - condSQL, condArgs, _ = builder.ToSQL(cond) - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } + if st.OrderStr != "" { + condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr) + } - if st.LimitN > 0 { + // TODO: Oracle support needed + var top string + if st.LimitN > 0 { + if st.Engine.dialect.DBType() == core.MYSQL { condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + } else if st.Engine.dialect.DBType() == core.SQLITE { + tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", + session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...)) + condSQL, condArgs, _ = builder.ToSQL(cond) + if len(condSQL) > 0 { + condSQL = "WHERE " + condSQL + } + } else if st.Engine.dialect.DBType() == core.POSTGRES { + tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) + cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", + session.Engine.Quote(session.Statement.TableName()), tempCondSQL), condArgs...)) + condSQL, condArgs, _ = builder.ToSQL(cond) + if len(condSQL) > 0 { + condSQL = "WHERE " + condSQL + } + } else if st.Engine.dialect.DBType() == core.MSSQL { + top = fmt.Sprintf("top (%d) ", st.LimitN) } - - sqlStr = fmt.Sprintf("UPDATE %v SET %v %v", - session.Engine.Quote(session.Statement.TableName()), - strings.Join(colNames, ", "), - condSQL) } + sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v", + top, + session.Engine.Quote(session.Statement.TableName()), + strings.Join(colNames, ", "), + condSQL) + res, err := session.exec(sqlStr, append(args, condArgs...)...) if err != nil { return 0, err diff --git a/vendor/github.com/go-xorm/xorm/sqlite3_dialect.go b/vendor/github.com/go-xorm/xorm/sqlite3_dialect.go deleted file mode 100644 index b72459ae..00000000 --- a/vendor/github.com/go-xorm/xorm/sqlite3_dialect.go +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "errors" - "fmt" - "regexp" - "strings" - - "github.com/go-xorm/core" -) - -// func init() { -// RegisterDialect("sqlite3", &sqlite3{}) -// } - -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, ",") - 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], "` []") - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - index.Name = indexName[5+len(tableName):] - } 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, "` []")) - } - indexes[index.Name] = index - } - - return indexes, nil -} - -func (db *sqlite3) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}} -} diff --git a/vendor/github.com/go-xorm/xorm/sqlite3_driver.go b/vendor/github.com/go-xorm/xorm/sqlite3_driver.go deleted file mode 100644 index 6ae19569..00000000 --- a/vendor/github.com/go-xorm/xorm/sqlite3_driver.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "github.com/go-xorm/core" -) - -// func init() { -// core.RegisterDriver("sqlite3", &sqlite3Driver{}) -// } - -type sqlite3Driver struct { -} - -func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil -} diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index fb116b94..b6f0baf2 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -39,7 +39,7 @@ type Statement struct { Engine *Engine Start int LimitN int - IdParam *core.PK + idParam *core.PK OrderStr string JoinStr string joinArgs []interface{} @@ -91,7 +91,7 @@ func (statement *Statement) Init() { statement.columnMap = make(map[string]bool) statement.AltTableName = "" statement.tableName = "" - statement.IdParam = nil + statement.idParam = nil statement.RawSQL = "" statement.RawParams = make([]interface{}, 0) statement.UseCache = true @@ -195,29 +195,26 @@ func (statement *Statement) Or(query interface{}, args ...interface{}) *Statemen // In generate "Where column IN (?) " statement func (statement *Statement) In(column string, args ...interface{}) *Statement { - if len(args) == 0 { - return statement - } - - in := builder.In(column, args...) + in := builder.In(statement.Engine.Quote(column), args...) statement.cond = statement.cond.And(in) return statement } // NotIn generate "Where column NOT IN (?) " statement func (statement *Statement) NotIn(column string, args ...interface{}) *Statement { - if len(args) == 0 { - return statement - } - - in := builder.NotIn(column, args...) - statement.cond = statement.cond.And(in) + notIn := builder.NotIn(statement.Engine.Quote(column), args...) + statement.cond = statement.cond.And(notIn) return statement } -func (statement *Statement) setRefValue(v reflect.Value) { - statement.RefTable = statement.Engine.autoMapType(reflect.Indirect(v)) +func (statement *Statement) setRefValue(v reflect.Value) error { + var err error + statement.RefTable, err = statement.Engine.autoMapType(reflect.Indirect(v)) + if err != nil { + return err + } statement.tableName = statement.Engine.tbName(v) + return nil } // Table tempororily set table name, the parameter could be a string or a pointer of struct @@ -227,7 +224,12 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { if t.Kind() == reflect.String { statement.AltTableName = tableNameOrBean.(string) } else if t.Kind() == reflect.Struct { - statement.RefTable = statement.Engine.autoMapType(v) + var err error + statement.RefTable, err = statement.Engine.autoMapType(v) + if err != nil { + statement.Engine.logger.Error(err) + return statement + } statement.AltTableName = statement.Engine.tbName(v) } return statement @@ -418,7 +420,11 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{}, if fieldValue == reflect.Zero(fieldType) { continue } - if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 { + if fieldType.Kind() == reflect.Array { + if isArrayValueZero(fieldValue) { + continue + } + } else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 { continue } } @@ -433,13 +439,16 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{}, } else if col.SQLType.IsBlob() { var bytes []byte var err error - if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) && + if fieldType.Kind() == reflect.Slice && fieldType.Elem().Kind() == reflect.Uint8 { if fieldValue.Len() > 0 { val = fieldValue.Bytes() } else { continue } + } else if fieldType.Kind() == reflect.Array && + fieldType.Elem().Kind() == reflect.Uint8 { + val = fieldValue.Slice(0, 0).Interface() } else { bytes, err = json.Marshal(fieldValue.Interface()) if err != nil { @@ -651,7 +660,9 @@ func buildConds(engine *Engine, table *core.Table, bean interface{}, } } } - case reflect.Array, reflect.Slice, reflect.Map: + case reflect.Array: + continue + case reflect.Slice, reflect.Map: if fieldValue == reflect.Zero(fieldType) { continue } @@ -706,13 +717,6 @@ func (statement *Statement) TableName() string { return statement.tableName } -// Id generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?" -// -// Deprecated: use ID instead -func (statement *Statement) Id(id interface{}) *Statement { - return statement.ID(id) -} - // ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?" func (statement *Statement) ID(id interface{}) *Statement { idValue := reflect.ValueOf(id) @@ -721,23 +725,23 @@ func (statement *Statement) ID(id interface{}) *Statement { switch idType { case ptrPkType: if pkPtr, ok := (id).(*core.PK); ok { - statement.IdParam = pkPtr + statement.idParam = pkPtr return statement } case pkType: if pk, ok := (id).(core.PK); ok { - statement.IdParam = &pk + statement.idParam = &pk return statement } } switch idType.Kind() { case reflect.String: - statement.IdParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()} + statement.idParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()} return statement } - statement.IdParam = &core.PK{id} + statement.idParam = &core.PK{id} return statement } @@ -1120,7 +1124,11 @@ func (statement *Statement) genConds(bean interface{}) (string, []interface{}, e } func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}) { - statement.setRefValue(rValue(bean)) + v := rValue(bean) + isStruct := v.Kind() == reflect.Struct + if isStruct { + statement.setRefValue(v) + } var columnStr = statement.ColumnStr if len(statement.selectStr) > 0 { @@ -1139,14 +1147,22 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}) if len(columnStr) == 0 { if len(statement.GroupByStr) > 0 { columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1)) - } else { - columnStr = "*" } } } } - condSQL, condArgs, _ := statement.genConds(bean) + if len(columnStr) == 0 { + columnStr = "*" + } + + var condSQL string + var condArgs []interface{} + if isStruct { + condSQL, condArgs, _ = statement.genConds(bean) + } else { + condSQL, condArgs, _ = builder.ToSQL(statement.cond) + } return statement.genSelectSQL(columnStr, condSQL), append(statement.joinArgs, condArgs...) } @@ -1172,17 +1188,21 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri var sumStrs = make([]string, 0, len(columns)) for _, colName := range columns { + if !strings.Contains(colName, " ") && !strings.Contains(colName, "(") { + colName = statement.Engine.Quote(colName) + } sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName)) } + sumSelect := strings.Join(sumStrs, ", ") condSQL, condArgs, _ := statement.genConds(bean) - return statement.genSelectSQL(strings.Join(sumStrs, ", "), condSQL), append(statement.joinArgs, condArgs...) + return statement.genSelectSQL(sumSelect, condSQL), append(statement.joinArgs, condArgs...) } func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) { var distinct string - if statement.IsDistinct { + if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") { distinct = "DISTINCT " } @@ -1198,8 +1218,14 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) { fmt.Fprintf(&buf, " WHERE %v", condSQL) } var whereStr = buf.String() + var fromStr = " FROM " + + if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") { + fromStr += statement.TableName() + } else { + fromStr += quote(statement.TableName()) + } - var fromStr = " FROM " + quote(statement.TableName()) if statement.TableAlias != "" { if dialect.DBType() == core.ORACLE { fromStr += " " + quote(statement.TableAlias) @@ -1289,14 +1315,14 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string) { } func (statement *Statement) processIDParam() { - if statement.IdParam == nil { + if statement.idParam == nil { return } for i, col := range statement.RefTable.PKColumns() { var colName = statement.colName(col, statement.TableName()) - if i < len(*(statement.IdParam)) { - statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.IdParam))[i]}) + if i < len(*(statement.idParam)) { + statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]}) } else { statement.cond = statement.cond.And(builder.Eq{colName: ""}) } diff --git a/vendor/github.com/go-xorm/xorm/tag.go b/vendor/github.com/go-xorm/xorm/tag.go new file mode 100644 index 00000000..4b0e3f54 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/tag.go @@ -0,0 +1,281 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "time" + + "github.com/go-xorm/core" +) + +type tagContext struct { + tagName string + params []string + preTag, nextTag string + table *core.Table + col *core.Column + fieldValue reflect.Value + isIndex bool + isUnique bool + indexNames map[string]int + engine *Engine + hasCacheTag bool + hasNoCacheTag bool + ignoreNext bool +} + +// tagHandler describes tag handler for XORM +type tagHandler func(ctx *tagContext) error + +var ( + // defaultTagHandlers enumerates all the default tag handler + defaultTagHandlers = map[string]tagHandler{ + "<-": OnlyFromDBTagHandler, + "->": OnlyToDBTagHandler, + "PK": PKTagHandler, + "NULL": NULLTagHandler, + "NOT": IgnoreTagHandler, + "AUTOINCR": AutoIncrTagHandler, + "DEFAULT": DefaultTagHandler, + "CREATED": CreatedTagHandler, + "UPDATED": UpdatedTagHandler, + "DELETED": DeletedTagHandler, + "VERSION": VersionTagHandler, + "UTC": UTCTagHandler, + "LOCAL": LocalTagHandler, + "NOTNULL": NotNullTagHandler, + "INDEX": IndexTagHandler, + "UNIQUE": UniqueTagHandler, + "CACHE": CacheTagHandler, + "NOCACHE": NoCacheTagHandler, + } +) + +func init() { + for k := range core.SqlTypes { + defaultTagHandlers[k] = SQLTypeTagHandler + } +} + +// IgnoreTagHandler describes ignored tag handler +func IgnoreTagHandler(ctx *tagContext) error { + return nil +} + +// OnlyFromDBTagHandler describes mapping direction tag handler +func OnlyFromDBTagHandler(ctx *tagContext) error { + ctx.col.MapType = core.ONLYFROMDB + return nil +} + +// OnlyToDBTagHandler describes mapping direction tag handler +func OnlyToDBTagHandler(ctx *tagContext) error { + ctx.col.MapType = core.ONLYTODB + return nil +} + +// PKTagHandler decribes primary key tag handler +func PKTagHandler(ctx *tagContext) error { + ctx.col.IsPrimaryKey = true + ctx.col.Nullable = false + return nil +} + +// NULLTagHandler describes null tag handler +func NULLTagHandler(ctx *tagContext) error { + ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT") + return nil +} + +// NotNullTagHandler describes notnull tag handler +func NotNullTagHandler(ctx *tagContext) error { + ctx.col.Nullable = false + return nil +} + +// AutoIncrTagHandler describes autoincr tag handler +func AutoIncrTagHandler(ctx *tagContext) error { + ctx.col.IsAutoIncrement = true + /* + if len(ctx.params) > 0 { + autoStartInt, err := strconv.Atoi(ctx.params[0]) + if err != nil { + return err + } + ctx.col.AutoIncrStart = autoStartInt + } else { + ctx.col.AutoIncrStart = 1 + } + */ + return nil +} + +// DefaultTagHandler describes default tag handler +func DefaultTagHandler(ctx *tagContext) error { + if len(ctx.params) > 0 { + ctx.col.Default = ctx.params[0] + } else { + ctx.col.Default = ctx.nextTag + ctx.ignoreNext = true + } + return nil +} + +// CreatedTagHandler describes created tag handler +func CreatedTagHandler(ctx *tagContext) error { + ctx.col.IsCreated = true + return nil +} + +// VersionTagHandler describes version tag handler +func VersionTagHandler(ctx *tagContext) error { + ctx.col.IsVersion = true + ctx.col.Default = "1" + return nil +} + +// UTCTagHandler describes utc tag handler +func UTCTagHandler(ctx *tagContext) error { + ctx.col.TimeZone = time.UTC + return nil +} + +// LocalTagHandler describes local tag handler +func LocalTagHandler(ctx *tagContext) error { + if len(ctx.params) == 0 { + ctx.col.TimeZone = time.Local + } else { + var err error + ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0]) + if err != nil { + return err + } + } + return nil +} + +// UpdatedTagHandler describes updated tag handler +func UpdatedTagHandler(ctx *tagContext) error { + ctx.col.IsUpdated = true + return nil +} + +// DeletedTagHandler describes deleted tag handler +func DeletedTagHandler(ctx *tagContext) error { + ctx.col.IsDeleted = true + return nil +} + +// IndexTagHandler describes index tag handler +func IndexTagHandler(ctx *tagContext) error { + if len(ctx.params) > 0 { + ctx.indexNames[ctx.params[0]] = core.IndexType + } else { + ctx.isIndex = true + } + return nil +} + +// UniqueTagHandler describes unique tag handler +func UniqueTagHandler(ctx *tagContext) error { + if len(ctx.params) > 0 { + ctx.indexNames[ctx.params[0]] = core.UniqueType + } else { + ctx.isUnique = true + } + return nil +} + +// SQLTypeTagHandler describes SQL Type tag handler +func SQLTypeTagHandler(ctx *tagContext) error { + ctx.col.SQLType = core.SQLType{Name: ctx.tagName} + if len(ctx.params) > 0 { + if ctx.tagName == core.Enum { + ctx.col.EnumOptions = make(map[string]int) + for k, v := range ctx.params { + v = strings.TrimSpace(v) + v = strings.Trim(v, "'") + ctx.col.EnumOptions[v] = k + } + } else if ctx.tagName == core.Set { + ctx.col.SetOptions = make(map[string]int) + for k, v := range ctx.params { + v = strings.TrimSpace(v) + v = strings.Trim(v, "'") + ctx.col.SetOptions[v] = k + } + } else { + var err error + if len(ctx.params) == 2 { + ctx.col.Length, err = strconv.Atoi(ctx.params[0]) + if err != nil { + return err + } + ctx.col.Length2, err = strconv.Atoi(ctx.params[1]) + if err != nil { + return err + } + } else if len(ctx.params) == 1 { + ctx.col.Length, err = strconv.Atoi(ctx.params[0]) + if err != nil { + return err + } + } + } + } + return nil +} + +// ExtendsTagHandler describes extends tag handler +func ExtendsTagHandler(ctx *tagContext) error { + var fieldValue = ctx.fieldValue + switch fieldValue.Kind() { + case reflect.Ptr: + f := fieldValue.Type().Elem() + if f.Kind() == reflect.Struct { + fieldPtr := fieldValue + fieldValue = fieldValue.Elem() + if !fieldValue.IsValid() || fieldPtr.IsNil() { + fieldValue = reflect.New(f).Elem() + } + } + fallthrough + case reflect.Struct: + parentTable, err := ctx.engine.mapType(fieldValue) + if err != nil { + return err + } + for _, col := range parentTable.Columns() { + col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName) + ctx.table.AddColumn(col) + for indexName, indexType := range col.Indexes { + addIndex(indexName, ctx.table, col, indexType) + } + } + default: + //TODO: warning + } + return nil +} + +// CacheTagHandler describes cache tag handler +func CacheTagHandler(ctx *tagContext) error { + if !ctx.hasCacheTag { + ctx.hasCacheTag = true + } + return nil +} + +// NoCacheTagHandler describes nocache tag handler +func NoCacheTagHandler(ctx *tagContext) error { + if !ctx.hasNoCacheTag { + ctx.hasNoCacheTag = true + } + return nil +} diff --git a/vendor/github.com/go-xorm/xorm/xorm.go b/vendor/github.com/go-xorm/xorm/xorm.go index 6414d8a2..c22c1b65 100644 --- a/vendor/github.com/go-xorm/xorm/xorm.go +++ b/vendor/github.com/go-xorm/xorm/xorm.go @@ -17,7 +17,7 @@ import ( const ( // Version show the xorm's version - Version string = "0.6.0.1022" + Version string = "0.6.2.0412" ) func regDrvsNDialects() bool { @@ -86,6 +86,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { mutex: &sync.RWMutex{}, TagIdentifier: "xorm", TZLocation: time.Local, + tagHandlers: defaultTagHandlers, } logger := NewSimpleLogger(os.Stdout) diff --git a/vendor/vendor.json b/vendor/vendor.json index abc5d0d3..247983e0 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -159,10 +159,10 @@ "revisionTime": "2017-02-06T15:24:21Z" }, { - "checksumSHA1": "BGWfs63vC5cJuxhVRrj+7YJKz7A=", + "checksumSHA1": "Ka4hFMvc75Fb57ZNLALyYSM7CCE=", "path": "github.com/go-xorm/xorm", - "revision": "19f6dfc2e8c069adc624ca56cf8127444159d5c1", - "revisionTime": "2017-02-10T01:55:37Z" + "revision": "d52a762fba17a2ed265463c1c7b608c14836eaaf", + "revisionTime": "2017-04-20T16:02:48Z" }, { "checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=", -- cgit v1.2.3