Merge branch 'master' into master

This commit is contained in:
Lunny Xiao 2021-06-06 19:58:55 +08:00
commit b61a1ee6f6
28 changed files with 371 additions and 120 deletions

View File

@ -3,6 +3,21 @@
This changelog goes through all the changes that have been made in each release This changelog goes through all the changes that have been made in each release
without substantial changes to our git log. without substantial changes to our git log.
## [1.1.0](https://gitea.com/xorm/xorm/releases/tag/1.1.0) - 2021-05-14
* FEATURES
* Unsigned Support for mysql (#1889)
* Support modernc.org/sqlite (#1850)
* TESTING
* More tests (#1890)
* MISC
* Byte strings in postgres aren't 0x... (#1906)
* Fix another bug with #1872 (#1905)
* Fix two issues with dumptables (#1903)
* Fix comments (#1896)
* Fix comments (#1893)
* MariaDB 10.5 adds a suffix on old datatypes (#1885)
## [1.0.7](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1336) - 2021-01-21 ## [1.0.7](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1336) - 2021-01-21
* BUGFIXES * BUGFIXES

View File

@ -243,4 +243,4 @@ test-tidb\#%: go-check
.PHONY: vet .PHONY: vet
vet: vet:
$(GO) vet $(shell $(GO) list ./...) $(GO) vet $(shell $(GO) list ./...)

View File

@ -23,6 +23,7 @@ var (
DefaultCacheSize = 200 DefaultCacheSize = 200
) )
// MapToSlice map query and struct as sql and args
func MapToSlice(query string, mp interface{}) (string, []interface{}, error) { func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
vv := reflect.ValueOf(mp) vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
@ -44,6 +45,7 @@ func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
return query, args, err return query, args, err
} }
// StructToSlice converts a query and struct as sql and args
func StructToSlice(query string, st interface{}) (string, []interface{}, error) { func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
vv := reflect.ValueOf(st) vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
@ -176,6 +178,7 @@ func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
return db.QueryMapContext(context.Background(), query, mp) return db.QueryMapContext(context.Background(), query, mp)
} }
// QueryStructContext query rows with struct
func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) { func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) {
query, args, err := StructToSlice(query, st) query, args, err := StructToSlice(query, st)
if err != nil { if err != nil {
@ -184,10 +187,12 @@ func (db *DB) QueryStructContext(ctx context.Context, query string, st interface
return db.QueryContext(ctx, query, args...) return db.QueryContext(ctx, query, args...)
} }
// QueryStruct query rows with struct
func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) { func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
return db.QueryStructContext(context.Background(), query, st) return db.QueryStructContext(context.Background(), query, st)
} }
// QueryRowContext query row with args
func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row { func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
rows, err := db.QueryContext(ctx, query, args...) rows, err := db.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
@ -196,10 +201,12 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interfa
return &Row{rows, nil} return &Row{rows, nil}
} }
// QueryRow query row with args
func (db *DB) QueryRow(query string, args ...interface{}) *Row { func (db *DB) QueryRow(query string, args ...interface{}) *Row {
return db.QueryRowContext(context.Background(), query, args...) return db.QueryRowContext(context.Background(), query, args...)
} }
// QueryRowMapContext query row with map
func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row { func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row {
query, args, err := MapToSlice(query, mp) query, args, err := MapToSlice(query, mp)
if err != nil { if err != nil {
@ -208,10 +215,12 @@ func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface
return db.QueryRowContext(ctx, query, args...) return db.QueryRowContext(ctx, query, args...)
} }
// QueryRowMap query row with map
func (db *DB) QueryRowMap(query string, mp interface{}) *Row { func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
return db.QueryRowMapContext(context.Background(), query, mp) return db.QueryRowMapContext(context.Background(), query, mp)
} }
// QueryRowStructContext query row with struct
func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row { func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row {
query, args, err := StructToSlice(query, st) query, args, err := StructToSlice(query, st)
if err != nil { if err != nil {
@ -220,6 +229,7 @@ func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interf
return db.QueryRowContext(ctx, query, args...) return db.QueryRowContext(ctx, query, args...)
} }
// QueryRowStruct query row with struct
func (db *DB) QueryRowStruct(query string, st interface{}) *Row { func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
return db.QueryRowStructContext(context.Background(), query, st) return db.QueryRowStructContext(context.Background(), query, st)
} }
@ -239,10 +249,12 @@ func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{})
return db.ExecContext(ctx, query, args...) return db.ExecContext(ctx, query, args...)
} }
// ExecMap exec query with map
func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) { func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) {
return db.ExecMapContext(context.Background(), query, mp) return db.ExecMapContext(context.Background(), query, mp)
} }
// ExecStructContext exec query with map
func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) { func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) {
query, args, err := StructToSlice(query, st) query, args, err := StructToSlice(query, st)
if err != nil { if err != nil {
@ -251,6 +263,7 @@ func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{
return db.ExecContext(ctx, query, args...) return db.ExecContext(ctx, query, args...)
} }
// ExecContext exec query with args
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
hookCtx := contexts.NewContextHook(ctx, query, args) hookCtx := contexts.NewContextHook(ctx, query, args)
ctx, err := db.beforeProcess(hookCtx) ctx, err := db.beforeProcess(hookCtx)
@ -265,6 +278,7 @@ func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}
return res, nil return res, nil
} }
// ExecStruct exec query with struct
func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) { func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
return db.ExecStructContext(context.Background(), query, st) return db.ExecStructContext(context.Background(), query, st)
} }
@ -288,6 +302,7 @@ func (db *DB) afterProcess(c *contexts.ContextHook) error {
return err return err
} }
// AddHook adds hook
func (db *DB) AddHook(h ...contexts.Hook) { func (db *DB) AddHook(h ...contexts.Hook) {
db.hooks.AddHook(h...) db.hooks.AddHook(h...)
} }

View File

@ -21,7 +21,7 @@ import (
var ( var (
dbtype = flag.String("dbtype", "sqlite3", "database type") dbtype = flag.String("dbtype", "sqlite3", "database type")
dbConn = flag.String("dbConn", "./db_test.db", "database connect string") dbConn = flag.String("dbConn", "./db_test.db", "database connect string")
createTableSql string createTableSQL string
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -29,12 +29,12 @@ func TestMain(m *testing.M) {
switch *dbtype { switch *dbtype {
case "sqlite3", "sqlite": case "sqlite3", "sqlite":
createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, " + createTableSQL = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, " +
"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);" "`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
case "mysql": case "mysql":
fallthrough fallthrough
default: default:
createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` TEXT NULL, " + createTableSQL = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` TEXT NULL, " +
"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);" "`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
} }
@ -66,7 +66,7 @@ func BenchmarkOriQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -121,7 +121,7 @@ func BenchmarkStructQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -166,7 +166,7 @@ func BenchmarkStruct2Query(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -212,7 +212,7 @@ func BenchmarkSliceInterfaceQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -270,7 +270,7 @@ func BenchmarkSliceInterfaceQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -321,7 +321,7 @@ func BenchmarkSliceStringQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -372,7 +372,7 @@ func BenchmarkMapInterfaceQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -426,7 +426,7 @@ func BenchmarkMapInterfaceQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -473,7 +473,7 @@ func BenchmarkMapStringQuery(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -519,7 +519,7 @@ func BenchmarkExec(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -544,7 +544,7 @@ func BenchmarkExecMap(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }
@ -577,7 +577,7 @@ func TestExecMap(t *testing.T) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -620,7 +620,7 @@ func TestExecStruct(t *testing.T) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -663,7 +663,7 @@ func BenchmarkExecStruct(b *testing.B) {
} }
defer db.Close() defer db.Close()
_, err = db.Exec(createTableSql) _, err = db.Exec(createTableSQL)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }

View File

@ -11,11 +11,13 @@ import (
"sync" "sync"
) )
// Rows represents rows of table
type Rows struct { type Rows struct {
*sql.Rows *sql.Rows
db *DB db *DB
} }
// ToMapString returns all records
func (rs *Rows) ToMapString() ([]map[string]string, error) { func (rs *Rows) ToMapString() ([]map[string]string, error) {
cols, err := rs.Columns() cols, err := rs.Columns()
if err != nil { if err != nil {
@ -34,7 +36,7 @@ func (rs *Rows) ToMapString() ([]map[string]string, error) {
return results, nil return results, nil
} }
// scan data to a struct's pointer according field index // ScanStructByIndex scan data to a struct's pointer according field index
func (rs *Rows) ScanStructByIndex(dest ...interface{}) error { func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
if len(dest) == 0 { if len(dest) == 0 {
return errors.New("at least one struct") return errors.New("at least one struct")
@ -94,7 +96,7 @@ func fieldByName(v reflect.Value, name string) reflect.Value {
return reflect.Zero(t) return reflect.Zero(t)
} }
// scan data to a struct's pointer according field name // ScanStructByName scan data to a struct's pointer according field name
func (rs *Rows) ScanStructByName(dest interface{}) error { func (rs *Rows) ScanStructByName(dest interface{}) error {
vv := reflect.ValueOf(dest) vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
@ -120,7 +122,7 @@ func (rs *Rows) ScanStructByName(dest interface{}) error {
return rs.Rows.Scan(newDest...) return rs.Rows.Scan(newDest...)
} }
// scan data to a slice's pointer, slice's length should equal to columns' number // ScanSlice scan data to a slice's pointer, slice's length should equal to columns' number
func (rs *Rows) ScanSlice(dest interface{}) error { func (rs *Rows) ScanSlice(dest interface{}) error {
vv := reflect.ValueOf(dest) vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
@ -155,7 +157,7 @@ func (rs *Rows) ScanSlice(dest interface{}) error {
return nil return nil
} }
// scan data to a map's pointer // ScanMap scan data to a map's pointer
func (rs *Rows) ScanMap(dest interface{}) error { func (rs *Rows) ScanMap(dest interface{}) error {
vv := reflect.ValueOf(dest) vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
@ -187,6 +189,7 @@ func (rs *Rows) ScanMap(dest interface{}) error {
return nil return nil
} }
// Row reprents a row of a tab
type Row struct { type Row struct {
rows *Rows rows *Rows
// One of these two will be non-nil: // One of these two will be non-nil:
@ -205,6 +208,7 @@ func NewRow(rows *Rows, err error) *Row {
return &Row{rows, err} return &Row{rows, err}
} }
// Columns returns all columns of the row
func (row *Row) Columns() ([]string, error) { func (row *Row) Columns() ([]string, error) {
if row.err != nil { if row.err != nil {
return nil, row.err return nil, row.err
@ -212,6 +216,7 @@ func (row *Row) Columns() ([]string, error) {
return row.rows.Columns() return row.rows.Columns()
} }
// Scan retrieves all row column values
func (row *Row) Scan(dest ...interface{}) error { func (row *Row) Scan(dest ...interface{}) error {
if row.err != nil { if row.err != nil {
return row.err return row.err
@ -238,6 +243,7 @@ func (row *Row) Scan(dest ...interface{}) error {
return row.rows.Close() return row.rows.Close()
} }
// ScanStructByName retrieves all row column values into a struct
func (row *Row) ScanStructByName(dest interface{}) error { func (row *Row) ScanStructByName(dest interface{}) error {
if row.err != nil { if row.err != nil {
return row.err return row.err
@ -258,6 +264,7 @@ func (row *Row) ScanStructByName(dest interface{}) error {
return row.rows.Close() return row.rows.Close()
} }
// ScanStructByIndex retrieves all row column values into a struct
func (row *Row) ScanStructByIndex(dest interface{}) error { func (row *Row) ScanStructByIndex(dest interface{}) error {
if row.err != nil { if row.err != nil {
return row.err return row.err
@ -278,7 +285,7 @@ func (row *Row) ScanStructByIndex(dest interface{}) error {
return row.rows.Close() return row.rows.Close()
} }
// scan data to a slice's pointer, slice's length should equal to columns' number // ScanSlice scan data to a slice's pointer, slice's length should equal to columns' number
func (row *Row) ScanSlice(dest interface{}) error { func (row *Row) ScanSlice(dest interface{}) error {
if row.err != nil { if row.err != nil {
return row.err return row.err
@ -300,7 +307,7 @@ func (row *Row) ScanSlice(dest interface{}) error {
return row.rows.Close() return row.rows.Close()
} }
// scan data to a map's pointer // ScanMap scan data to a map's pointer
func (row *Row) ScanMap(dest interface{}) error { func (row *Row) ScanMap(dest interface{}) error {
if row.err != nil { if row.err != nil {
return row.err return row.err
@ -322,6 +329,7 @@ func (row *Row) ScanMap(dest interface{}) error {
return row.rows.Close() return row.rows.Close()
} }
// ToMapString returns all clumns of this record
func (row *Row) ToMapString() (map[string]string, error) { func (row *Row) ToMapString() (map[string]string, error) {
cols, err := row.Columns() cols, err := row.Columns()
if err != nil { if err != nil {

View File

@ -10,12 +10,14 @@ import (
"time" "time"
) )
// NullTime defines a customize type NullTime
type NullTime time.Time type NullTime time.Time
var ( var (
_ driver.Valuer = NullTime{} _ driver.Valuer = NullTime{}
) )
// Scan implements driver.Valuer
func (ns *NullTime) Scan(value interface{}) error { func (ns *NullTime) Scan(value interface{}) error {
if value == nil { if value == nil {
return nil return nil
@ -58,9 +60,11 @@ func convertTime(dest *NullTime, src interface{}) error {
return nil return nil
} }
// EmptyScanner represents an empty scanner
type EmptyScanner struct { type EmptyScanner struct {
} }
// Scan implements
func (EmptyScanner) Scan(src interface{}) error { func (EmptyScanner) Scan(src interface{}) error {
return nil return nil
} }

View File

@ -21,6 +21,7 @@ type Stmt struct {
query string query string
} }
// PrepareContext creates a prepare statement
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
names := make(map[string]int) names := make(map[string]int)
var i int var i int
@ -42,10 +43,12 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
return &Stmt{stmt, db, names, query}, nil return &Stmt{stmt, db, names, query}, nil
} }
// Prepare creates a prepare statement
func (db *DB) Prepare(query string) (*Stmt, error) { func (db *DB) Prepare(query string) (*Stmt, error) {
return db.PrepareContext(context.Background(), query) return db.PrepareContext(context.Background(), query)
} }
// ExecMapContext execute with map
func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) { func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) {
vv := reflect.ValueOf(mp) vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
@ -59,10 +62,12 @@ func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result,
return s.ExecContext(ctx, args...) return s.ExecContext(ctx, args...)
} }
// ExecMap executes with map
func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) { func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
return s.ExecMapContext(context.Background(), mp) return s.ExecMapContext(context.Background(), mp)
} }
// ExecStructContext executes with struct
func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) { func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) {
vv := reflect.ValueOf(st) vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
@ -76,10 +81,12 @@ func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Resul
return s.ExecContext(ctx, args...) return s.ExecContext(ctx, args...)
} }
// ExecStruct executes with struct
func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) { func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
return s.ExecStructContext(context.Background(), st) return s.ExecStructContext(context.Background(), st)
} }
// ExecContext with args
func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) { func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) {
hookCtx := contexts.NewContextHook(ctx, s.query, args) hookCtx := contexts.NewContextHook(ctx, s.query, args)
ctx, err := s.db.beforeProcess(hookCtx) ctx, err := s.db.beforeProcess(hookCtx)
@ -94,6 +101,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result
return res, nil return res, nil
} }
// QueryContext query with args
func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) { func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
hookCtx := contexts.NewContextHook(ctx, s.query, args) hookCtx := contexts.NewContextHook(ctx, s.query, args)
ctx, err := s.db.beforeProcess(hookCtx) ctx, err := s.db.beforeProcess(hookCtx)
@ -108,10 +116,12 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
return &Rows{rows, s.db}, nil return &Rows{rows, s.db}, nil
} }
// Query query with args
func (s *Stmt) Query(args ...interface{}) (*Rows, error) { func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return s.QueryContext(context.Background(), args...) return s.QueryContext(context.Background(), args...)
} }
// QueryMapContext query with map
func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) { func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) {
vv := reflect.ValueOf(mp) vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
@ -126,10 +136,12 @@ func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, erro
return s.QueryContext(ctx, args...) return s.QueryContext(ctx, args...)
} }
// QueryMap query with map
func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) { func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
return s.QueryMapContext(context.Background(), mp) return s.QueryMapContext(context.Background(), mp)
} }
// QueryStructContext query with struct
func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) { func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) {
vv := reflect.ValueOf(st) vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
@ -144,19 +156,23 @@ func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, e
return s.QueryContext(ctx, args...) return s.QueryContext(ctx, args...)
} }
// QueryStruct query with struct
func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) { func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
return s.QueryStructContext(context.Background(), st) return s.QueryStructContext(context.Background(), st)
} }
// QueryRowContext query row with args
func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row { func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
rows, err := s.QueryContext(ctx, args...) rows, err := s.QueryContext(ctx, args...)
return &Row{rows, err} return &Row{rows, err}
} }
// QueryRow query row with args
func (s *Stmt) QueryRow(args ...interface{}) *Row { func (s *Stmt) QueryRow(args ...interface{}) *Row {
return s.QueryRowContext(context.Background(), args...) return s.QueryRowContext(context.Background(), args...)
} }
// QueryRowMapContext query row with map
func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row { func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row {
vv := reflect.ValueOf(mp) vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
@ -171,10 +187,12 @@ func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row {
return s.QueryRowContext(ctx, args...) return s.QueryRowContext(ctx, args...)
} }
// QueryRowMap query row with map
func (s *Stmt) QueryRowMap(mp interface{}) *Row { func (s *Stmt) QueryRowMap(mp interface{}) *Row {
return s.QueryRowMapContext(context.Background(), mp) return s.QueryRowMapContext(context.Background(), mp)
} }
// QueryRowStructContext query row with struct
func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row { func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row {
vv := reflect.ValueOf(st) vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
@ -189,6 +207,7 @@ func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row {
return s.QueryRowContext(ctx, args...) return s.QueryRowContext(ctx, args...)
} }
// QueryRowStruct query row with struct
func (s *Stmt) QueryRowStruct(st interface{}) *Row { func (s *Stmt) QueryRowStruct(st interface{}) *Row {
return s.QueryRowStructContext(context.Background(), st) return s.QueryRowStructContext(context.Background(), st)
} }

View File

@ -51,10 +51,7 @@ func (tx *Tx) Commit() error {
} }
err = tx.Tx.Commit() err = tx.Tx.Commit()
hookCtx.End(ctx, nil, err) hookCtx.End(ctx, nil, err)
if err := tx.db.afterProcess(hookCtx); err != nil { return tx.db.afterProcess(hookCtx)
return err
}
return nil
} }
// Rollback rollback the transaction // Rollback rollback the transaction
@ -66,10 +63,7 @@ func (tx *Tx) Rollback() error {
} }
err = tx.Tx.Rollback() err = tx.Tx.Rollback()
hookCtx.End(ctx, nil, err) hookCtx.End(ctx, nil, err)
if err := tx.db.afterProcess(hookCtx); err != nil { return tx.db.afterProcess(hookCtx)
return err
}
return nil
} }
// PrepareContext prepare the query // PrepareContext prepare the query

View File

@ -824,6 +824,11 @@ func (db *postgres) SetQuotePolicy(quotePolicy QuotePolicy) {
} }
} }
// FormatBytes formats bytes
func (db *postgres) FormatBytes(bs []byte) string {
return fmt.Sprintf("E'\\x%x'", bs)
}
func (db *postgres) SQLType(c *schemas.Column) string { func (db *postgres) SQLType(c *schemas.Column) string {
var res string var res string
switch t := c.SQLType.Name; t { switch t := c.SQLType.Name; t {

146
engine.go
View File

@ -21,6 +21,7 @@ import (
"xorm.io/xorm/contexts" "xorm.io/xorm/contexts"
"xorm.io/xorm/core" "xorm.io/xorm/core"
"xorm.io/xorm/dialects" "xorm.io/xorm/dialects"
"xorm.io/xorm/internal/json"
"xorm.io/xorm/internal/utils" "xorm.io/xorm/internal/utils"
"xorm.io/xorm/log" "xorm.io/xorm/log"
"xorm.io/xorm/names" "xorm.io/xorm/names"
@ -457,9 +458,26 @@ func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.
} }
if col.SQLType.IsText() { if col.SQLType.IsText() {
var v = fmt.Sprintf("%s", d) var v string
switch reflect.TypeOf(d).Kind() {
case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map:
bytes, err := json.DefaultJSONHandler.Marshal(d)
if err != nil {
v = fmt.Sprintf("%s", d)
} else {
v = string(bytes)
}
default:
v = fmt.Sprintf("%s", d)
}
return "'" + strings.Replace(v, "'", "''", -1) + "'" return "'" + strings.Replace(v, "'", "''", -1) + "'"
} else if col.SQLType.IsTime() { } else if col.SQLType.IsTime() {
if dstDialect.URI().DBType == schemas.MSSQL && col.SQLType.Name == schemas.DateTime {
if t, ok := d.(time.Time); ok {
return "'" + t.UTC().Format("2006-01-02 15:04:05") + "'"
}
}
var v = fmt.Sprintf("%s", d) var v = fmt.Sprintf("%s", d)
if strings.HasSuffix(v, " +0000 UTC") { if strings.HasSuffix(v, " +0000 UTC") {
return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")]) return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")])
@ -491,7 +509,7 @@ func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.
} }
return fmt.Sprintf("%v", strconv.FormatBool(v)) return fmt.Sprintf("%v", strconv.FormatBool(v))
} }
return fmt.Sprintf("%v", d) return fmt.Sprintf("%d", d)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if col.SQLType.Name == schemas.Bool { if col.SQLType.Name == schemas.Bool {
v := reflect.ValueOf(d).Uint() > 0 v := reflect.ValueOf(d).Uint() > 0
@ -503,7 +521,7 @@ func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.
} }
return fmt.Sprintf("%v", strconv.FormatBool(v)) return fmt.Sprintf("%v", strconv.FormatBool(v))
} }
return fmt.Sprintf("%v", d) return fmt.Sprintf("%d", d)
default: default:
return fmt.Sprintf("%v", d) return fmt.Sprintf("%v", d)
} }
@ -537,6 +555,8 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
} }
dstDialect.Init(&destURI) dstDialect.Init(&destURI)
} }
cacherMgr := caches.NewManager()
dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper(), cacherMgr)
_, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm %s, from %s to %s*/\n\n", _, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm %s, from %s to %s*/\n\n",
time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.URI().DBType, dstDialect.URI().DBType)) time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.URI().DBType, dstDialect.URI().DBType))
@ -545,9 +565,18 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
} }
for i, table := range tables { for i, table := range tables {
tableName := table.Name dstTable := table
if table.Type != nil {
dstTable, err = dstTableCache.Parse(reflect.New(table.Type).Elem())
if err != nil {
engine.logger.Errorf("Unable to infer table for %s in new dialect. Error: %v", table.Name)
dstTable = table
}
}
dstTableName := dstTable.Name
if dstDialect.URI().Schema != "" { if dstDialect.URI().Schema != "" {
tableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, table.Name) dstTableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, dstTable.Name)
} }
originalTableName := table.Name originalTableName := table.Name
if engine.dialect.URI().Schema != "" { if engine.dialect.URI().Schema != "" {
@ -559,27 +588,30 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
return err return err
} }
} }
sqls, _ := dstDialect.CreateTableSQL(table, tableName)
sqls, _ := dstDialect.CreateTableSQL(dstTable, dstTableName)
for _, s := range sqls { for _, s := range sqls {
_, err = io.WriteString(w, s+";\n") _, err = io.WriteString(w, s+";\n")
if err != nil { if err != nil {
return err return err
} }
} }
if len(table.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL { if len(dstTable.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", table.Name) fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", dstTable.Name)
} }
for _, index := range table.Indexes { for _, index := range dstTable.Indexes {
_, err = io.WriteString(w, dstDialect.CreateIndexSQL(table.Name, index)+";\n") _, err = io.WriteString(w, dstDialect.CreateIndexSQL(dstTable.Name, index)+";\n")
if err != nil { if err != nil {
return err return err
} }
} }
cols := table.ColumnsSeq() cols := table.ColumnsSeq()
dstCols := dstTable.ColumnsSeq()
colNames := engine.dialect.Quoter().Join(cols, ", ") colNames := engine.dialect.Quoter().Join(cols, ", ")
destColNames := dstDialect.Quoter().Join(cols, ", ") destColNames := dstDialect.Quoter().Join(dstCols, ", ")
rows, err := engine.DB().QueryContext(engine.defaultContext, "SELECT "+colNames+" FROM "+engine.Quote(originalTableName)) rows, err := engine.DB().QueryContext(engine.defaultContext, "SELECT "+colNames+" FROM "+engine.Quote(originalTableName))
if err != nil { if err != nil {
@ -587,35 +619,83 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
} }
defer rows.Close() defer rows.Close()
for rows.Next() { if table.Type != nil {
dest := make([]interface{}, len(cols)) sess := engine.NewSession()
err = rows.ScanSlice(&dest) defer sess.Close()
if err != nil { for rows.Next() {
return err beanValue := reflect.New(table.Type)
} bean := beanValue.Interface()
fields, err := rows.Columns()
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(tableName)+" ("+destColNames+") VALUES (") if err != nil {
if err != nil { return err
return err }
} scanResults, err := sess.row2Slice(rows, fields, bean)
if err != nil {
var temp string return err
for i, d := range dest { }
col := table.GetColumn(cols[i])
if col == nil { dataStruct := utils.ReflectValue(bean)
return errors.New("unknow column error") _, err = sess.slice2Bean(scanResults, fields, bean, &dataStruct, table)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(dstTableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for _, d := range dstCols {
col := table.GetColumn(d)
if col == nil {
return errors.New("unknown column error")
}
fields := strings.Split(col.FieldName, ".")
field := dataStruct
for _, fieldName := range fields {
field = field.FieldByName(fieldName)
}
temp += "," + formatColumnValue(dstDialect, field.Interface(), col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
} }
temp += "," + formatColumnValue(dstDialect, d, col)
} }
_, err = io.WriteString(w, temp[1:]+");\n") } else {
if err != nil { for rows.Next() {
return err dest := make([]interface{}, len(cols))
err = rows.ScanSlice(&dest)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(dstTableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for i, d := range dest {
col := table.GetColumn(cols[i])
if col == nil {
return errors.New("unknow column error")
}
temp += "," + formatColumnValue(dstDialect, d, col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
}
} }
} }
// FIXME: Hack for postgres // FIXME: Hack for postgres
if dstDialect.URI().DBType == schemas.POSTGRES && table.AutoIncrColumn() != nil { if dstDialect.URI().DBType == schemas.POSTGRES && table.AutoIncrColumn() != nil {
_, err = io.WriteString(w, "SELECT setval('"+tableName+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dstDialect.Quoter().Quote(tableName)+"), 1), false);\n") _, err = io.WriteString(w, "SELECT setval('"+dstTableName+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dstDialect.Quoter().Quote(dstTableName)+"), 1), false);\n")
if err != nil { if err != nil {
return err return err
} }

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.13
require ( require (
github.com/denisenkom/go-mssqldb v0.9.0 github.com/denisenkom/go-mssqldb v0.9.0
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
github.com/json-iterator/go v1.1.11
github.com/lib/pq v1.7.0 github.com/lib/pq v1.7.0
github.com/mattn/go-sqlite3 v1.14.6 github.com/mattn/go-sqlite3 v1.14.6
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0

10
go.sum
View File

@ -1,7 +1,8 @@
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
@ -18,8 +19,11 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
@ -28,6 +32,10 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

View File

@ -97,6 +97,7 @@ func TestDeleted(t *testing.T) {
// Test normal Find() // Test normal Find()
var records1 []Deleted var records1 []Deleted
err = testEngine.Where("`"+testEngine.GetColumnMapper().Obj2Table("Id")+"` > 0").Find(&records1, &Deleted{}) err = testEngine.Where("`"+testEngine.GetColumnMapper().Obj2Table("Id")+"` > 0").Find(&records1, &Deleted{})
assert.NoError(t, err)
assert.EqualValues(t, 3, len(records1)) assert.EqualValues(t, 3, len(records1))
// Test normal Get() // Test normal Get()
@ -132,6 +133,7 @@ func TestDeleted(t *testing.T) {
record2 := &Deleted{} record2 := &Deleted{}
has, err = testEngine.ID(2).Get(record2) has, err = testEngine.ID(2).Get(record2)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has)
assert.True(t, record2.DeletedAt.IsZero()) assert.True(t, record2.DeletedAt.IsZero())
// Test find all records whatever `deleted`. // Test find all records whatever `deleted`.

View File

@ -653,6 +653,31 @@ func TestFindAndCount2(t *testing.T) {
assert.EqualValues(t, 0, cnt) assert.EqualValues(t, 0, cnt)
} }
type FindAndCountWithTableName struct {
Id int64
Name string
}
func (FindAndCountWithTableName) TableName() string {
return "find_and_count_with_table_name1"
}
func TestFindAndCountWithTableName(t *testing.T) {
assert.NoError(t, PrepareEngine())
assertSync(t, new(FindAndCountWithTableName))
cnt, err := testEngine.Insert(&FindAndCountWithTableName{
Name: "1",
})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
var res []FindAndCountWithTableName
cnt, err = testEngine.FindAndCount(&res)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
}
type FindMapDevice struct { type FindMapDevice struct {
Deviceid string `xorm:"pk"` Deviceid string `xorm:"pk"`
Status int Status int

28
internal/json/jsoniter.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2021 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build jsoniter
package json
import (
jsoniter "github.com/json-iterator/go"
)
func init() {
DefaultJSONHandler = JSONiter{}
}
// JSONiter implements JSONInterface via jsoniter
type JSONiter struct{}
// Marshal implements JSONInterface
func (JSONiter) Marshal(v interface{}) ([]byte, error) {
return jsoniter.Marshal(v)
}
// Unmarshal implements JSONInterface
func (JSONiter) Unmarshal(data []byte, v interface{}) error {
return jsoniter.Unmarshal(data, v)
}

View File

@ -12,6 +12,7 @@ import (
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
// ConvertIDSQL converts SQL with id
func (statement *Statement) ConvertIDSQL(sqlStr string) string { func (statement *Statement) ConvertIDSQL(sqlStr string) string {
if statement.RefTable != nil { if statement.RefTable != nil {
cols := statement.RefTable.PKColumns() cols := statement.RefTable.PKColumns()
@ -37,6 +38,7 @@ func (statement *Statement) ConvertIDSQL(sqlStr string) string {
return "" return ""
} }
// ConvertUpdateSQL converts update SQL
func (statement *Statement) ConvertUpdateSQL(sqlStr string) (string, string) { func (statement *Statement) ConvertUpdateSQL(sqlStr string) (string, string) {
if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 { if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 {
return "", "" return "", ""

View File

@ -14,6 +14,7 @@ import (
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
// GenQuerySQL generate query SQL
func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) { func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
if len(sqlOrArgs) > 0 { if len(sqlOrArgs) > 0 {
return statement.ConvertSQLOrArgs(sqlOrArgs...) return statement.ConvertSQLOrArgs(sqlOrArgs...)
@ -72,6 +73,7 @@ func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []int
return sqlStr, args, nil return sqlStr, args, nil
} }
// GenSumSQL generates sum SQL
func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) { func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
if statement.RawSQL != "" { if statement.RawSQL != "" {
return statement.GenRawSQL(), statement.RawParams, nil return statement.GenRawSQL(), statement.RawParams, nil
@ -102,6 +104,7 @@ func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (stri
return sqlStr, append(statement.joinArgs, condArgs...), nil return sqlStr, append(statement.joinArgs, condArgs...), nil
} }
// GenGetSQL generates Get SQL
func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{}, error) { func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{}, error) {
v := rValue(bean) v := rValue(bean)
isStruct := v.Kind() == reflect.Struct isStruct := v.Kind() == reflect.Struct
@ -316,6 +319,7 @@ func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderB
return buf.String(), condArgs, nil return buf.String(), condArgs, nil
} }
// GenExistSQL generates Exist SQL
func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interface{}, error) { func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interface{}, error) {
if statement.RawSQL != "" { if statement.RawSQL != "" {
return statement.GenRawSQL(), statement.RawParams, nil return statement.GenRawSQL(), statement.RawParams, nil
@ -385,6 +389,7 @@ func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interfac
return sqlStr, args, nil return sqlStr, args, nil
} }
// GenFindSQL generates Find SQL
func (statement *Statement) GenFindSQL(autoCond builder.Cond) (string, []interface{}, error) { func (statement *Statement) GenFindSQL(autoCond builder.Cond) (string, []interface{}, error) {
if statement.RawSQL != "" { if statement.RawSQL != "" {
return statement.GenRawSQL(), statement.RawParams, nil return statement.GenRawSQL(), statement.RawParams, nil

View File

@ -90,14 +90,11 @@ func NewStatement(dialect dialects.Dialect, tagParser *tags.Parser, defaultTimeZ
return statement return statement
} }
// SetTableName set table name
func (statement *Statement) SetTableName(tableName string) { func (statement *Statement) SetTableName(tableName string) {
statement.tableName = tableName statement.tableName = tableName
} }
func (statement *Statement) omitStr() string {
return statement.dialect.Quoter().Join(statement.OmitColumnMap, " ,")
}
// GenRawSQL generates correct raw sql // GenRawSQL generates correct raw sql
func (statement *Statement) GenRawSQL() string { func (statement *Statement) GenRawSQL() string {
return statement.ReplaceQuote(statement.RawSQL) return statement.ReplaceQuote(statement.RawSQL)
@ -112,6 +109,7 @@ func (statement *Statement) GenCondSQL(condOrBuilder interface{}) (string, []int
return statement.ReplaceQuote(condSQL), condArgs, nil return statement.ReplaceQuote(condSQL), condArgs, nil
} }
// ReplaceQuote replace sql key words with quote
func (statement *Statement) ReplaceQuote(sql string) string { func (statement *Statement) ReplaceQuote(sql string) string {
if sql == "" || statement.dialect.URI().DBType == schemas.MYSQL || if sql == "" || statement.dialect.URI().DBType == schemas.MYSQL ||
statement.dialect.URI().DBType == schemas.SQLITE { statement.dialect.URI().DBType == schemas.SQLITE {
@ -591,7 +589,7 @@ func (statement *Statement) Having(conditions string) *Statement {
return statement return statement
} }
// Unscoped always disable struct tag "deleted" // SetUnscoped always disable struct tag "deleted"
func (statement *Statement) SetUnscoped() *Statement { func (statement *Statement) SetUnscoped() *Statement {
statement.unscoped = true statement.unscoped = true
return statement return statement
@ -923,10 +921,7 @@ func (statement *Statement) mergeConds(bean interface{}) error {
statement.cond = statement.cond.And(autoCond) statement.cond = statement.cond.And(autoCond)
} }
if err := statement.ProcessIDParam(); err != nil { return statement.ProcessIDParam()
return err
}
return nil
} }
// GenConds generates conditions // GenConds generates conditions

View File

@ -77,6 +77,7 @@ func convertArg(arg interface{}, convertFunc func(string) string) string {
const insertSelectPlaceHolder = true const insertSelectPlaceHolder = true
// WriteArg writes an arg
func (statement *Statement) WriteArg(w *builder.BytesWriter, arg interface{}) error { func (statement *Statement) WriteArg(w *builder.BytesWriter, arg interface{}) error {
switch argv := arg.(type) { switch argv := arg.(type) {
case *builder.Builder: case *builder.Builder:
@ -116,6 +117,7 @@ func (statement *Statement) WriteArg(w *builder.BytesWriter, arg interface{}) er
return nil return nil
} }
// WriteArgs writes args
func (statement *Statement) WriteArgs(w *builder.BytesWriter, args []interface{}) error { func (statement *Statement) WriteArgs(w *builder.BytesWriter, args []interface{}) error {
for i, arg := range args { for i, arg := range args {
if err := statement.WriteArg(w, arg); err != nil { if err := statement.WriteArg(w, arg); err != nil {

View File

@ -16,6 +16,7 @@ type Mapper interface {
Table2Obj(string) string Table2Obj(string) string
} }
// CacheMapper represents a cache mapper
type CacheMapper struct { type CacheMapper struct {
oriMapper Mapper oriMapper Mapper
obj2tableCache map[string]string obj2tableCache map[string]string
@ -24,12 +25,14 @@ type CacheMapper struct {
table2objMutex sync.RWMutex table2objMutex sync.RWMutex
} }
// NewCacheMapper creates a cache mapper
func NewCacheMapper(mapper Mapper) *CacheMapper { func NewCacheMapper(mapper Mapper) *CacheMapper {
return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string), return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string),
table2objCache: make(map[string]string), table2objCache: make(map[string]string),
} }
} }
// Obj2Table implements Mapper
func (m *CacheMapper) Obj2Table(o string) string { func (m *CacheMapper) Obj2Table(o string) string {
m.obj2tableMutex.RLock() m.obj2tableMutex.RLock()
t, ok := m.obj2tableCache[o] t, ok := m.obj2tableCache[o]
@ -45,6 +48,7 @@ func (m *CacheMapper) Obj2Table(o string) string {
return t return t
} }
// Table2Obj implements Mapper
func (m *CacheMapper) Table2Obj(t string) string { func (m *CacheMapper) Table2Obj(t string) string {
m.table2objMutex.RLock() m.table2objMutex.RLock()
o, ok := m.table2objCache[t] o, ok := m.table2objCache[t]
@ -60,15 +64,17 @@ func (m *CacheMapper) Table2Obj(t string) string {
return o return o
} }
// SameMapper implements IMapper and provides same name between struct and // SameMapper implements Mapper and provides same name between struct and
// database table // database table
type SameMapper struct { type SameMapper struct {
} }
// Obj2Table implements Mapper
func (m SameMapper) Obj2Table(o string) string { func (m SameMapper) Obj2Table(o string) string {
return o return o
} }
// Table2Obj implements Mapper
func (m SameMapper) Table2Obj(t string) string { func (m SameMapper) Table2Obj(t string) string {
return t return t
} }
@ -98,6 +104,7 @@ func snakeCasedName(name string) string {
return b2s(newstr) return b2s(newstr)
} }
// Obj2Table implements Mapper
func (mapper SnakeMapper) Obj2Table(name string) string { func (mapper SnakeMapper) Obj2Table(name string) string {
return snakeCasedName(name) return snakeCasedName(name)
} }
@ -127,6 +134,7 @@ func titleCasedName(name string) string {
return b2s(newstr) return b2s(newstr)
} }
// Table2Obj implements Mapper
func (mapper SnakeMapper) Table2Obj(name string) string { func (mapper SnakeMapper) Table2Obj(name string) string {
return titleCasedName(name) return titleCasedName(name)
} }
@ -168,10 +176,12 @@ func gonicCasedName(name string) string {
return strings.ToLower(string(newstr)) return strings.ToLower(string(newstr))
} }
// Obj2Table implements Mapper
func (mapper GonicMapper) Obj2Table(name string) string { func (mapper GonicMapper) Obj2Table(name string) string {
return gonicCasedName(name) return gonicCasedName(name)
} }
// Table2Obj implements Mapper
func (mapper GonicMapper) Table2Obj(name string) string { func (mapper GonicMapper) Table2Obj(name string) string {
newstr := make([]rune, 0) newstr := make([]rune, 0)
@ -234,14 +244,17 @@ type PrefixMapper struct {
Prefix string Prefix string
} }
// Obj2Table implements Mapper
func (mapper PrefixMapper) Obj2Table(name string) string { func (mapper PrefixMapper) Obj2Table(name string) string {
return mapper.Prefix + mapper.Mapper.Obj2Table(name) return mapper.Prefix + mapper.Mapper.Obj2Table(name)
} }
// Table2Obj implements Mapper
func (mapper PrefixMapper) Table2Obj(name string) string { func (mapper PrefixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):]) return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):])
} }
// NewPrefixMapper creates a prefix mapper
func NewPrefixMapper(mapper Mapper, prefix string) PrefixMapper { func NewPrefixMapper(mapper Mapper, prefix string) PrefixMapper {
return PrefixMapper{mapper, prefix} return PrefixMapper{mapper, prefix}
} }
@ -252,14 +265,17 @@ type SuffixMapper struct {
Suffix string Suffix string
} }
// Obj2Table implements Mapper
func (mapper SuffixMapper) Obj2Table(name string) string { func (mapper SuffixMapper) Obj2Table(name string) string {
return mapper.Mapper.Obj2Table(name) + mapper.Suffix return mapper.Mapper.Obj2Table(name) + mapper.Suffix
} }
// Table2Obj implements Mapper
func (mapper SuffixMapper) Table2Obj(name string) string { func (mapper SuffixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[:len(name)-len(mapper.Suffix)]) return mapper.Mapper.Table2Obj(name[:len(name)-len(mapper.Suffix)])
} }
// NewSuffixMapper creates a suffix mapper
func NewSuffixMapper(mapper Mapper, suffix string) SuffixMapper { func NewSuffixMapper(mapper Mapper, suffix string) SuffixMapper {
return SuffixMapper{mapper, suffix} return SuffixMapper{mapper, suffix}
} }

View File

@ -19,6 +19,7 @@ var (
tvCache sync.Map tvCache sync.Map
) )
// GetTableName returns table name
func GetTableName(mapper Mapper, v reflect.Value) string { func GetTableName(mapper Mapper, v reflect.Value) string {
if v.Type().Implements(tpTableName) { if v.Type().Implements(tpTableName) {
return v.Interface().(TableName).TableName() return v.Interface().(TableName).TableName()

View File

@ -13,6 +13,7 @@ import (
"time" "time"
) )
// enumerates all database mapping way
const ( const (
TWOSIDES = iota + 1 TWOSIDES = iota + 1
ONLYTODB ONLYTODB

View File

@ -28,6 +28,7 @@ func NewIndex(name string, indexType int) *Index {
return &Index{true, name, indexType, make([]string, 0)} return &Index{true, name, indexType, make([]string, 0)}
} }
// XName returns the special index name for the table
func (index *Index) XName(tableName string) string { func (index *Index) XName(tableName string) string {
if !strings.HasPrefix(index.Name, "UQE_") && if !strings.HasPrefix(index.Name, "UQE_") &&
!strings.HasPrefix(index.Name, "IDX_") { !strings.HasPrefix(index.Name, "IDX_") {
@ -43,11 +44,10 @@ func (index *Index) XName(tableName string) string {
// AddColumn add columns which will be composite index // AddColumn add columns which will be composite index
func (index *Index) AddColumn(cols ...string) { func (index *Index) AddColumn(cols ...string) {
for _, col := range cols { index.Cols = append(index.Cols, cols...)
index.Cols = append(index.Cols, col)
}
} }
// Equal return true if the two Index is equal
func (index *Index) Equal(dst *Index) bool { func (index *Index) Equal(dst *Index) bool {
if index.Type != dst.Type { if index.Type != dst.Type {
return false return false

View File

@ -11,13 +11,16 @@ import (
"xorm.io/xorm/internal/utils" "xorm.io/xorm/internal/utils"
) )
// PK represents primary key values
type PK []interface{} type PK []interface{}
// NewPK creates primay keys
func NewPK(pks ...interface{}) *PK { func NewPK(pks ...interface{}) *PK {
p := PK(pks) p := PK(pks)
return &p return &p
} }
// IsZero return true if primay keys are zero
func (p *PK) IsZero() bool { func (p *PK) IsZero() bool {
for _, k := range *p { for _, k := range *p {
if utils.IsZero(k) { if utils.IsZero(k) {
@ -27,6 +30,7 @@ func (p *PK) IsZero() bool {
return false return false
} }
// ToString convert to SQL string
func (p *PK) ToString() (string, error) { func (p *PK) ToString() (string, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf) enc := gob.NewEncoder(buf)
@ -34,6 +38,7 @@ func (p *PK) ToString() (string, error) {
return buf.String(), err return buf.String(), err
} }
// FromString reads content to load primary keys
func (p *PK) FromString(content string) error { func (p *PK) FromString(content string) error {
dec := gob.NewDecoder(bytes.NewBufferString(content)) dec := gob.NewDecoder(bytes.NewBufferString(content))
err := dec.Decode(p) err := dec.Decode(p)

View File

@ -16,10 +16,10 @@ type Quoter struct {
} }
var ( var (
// AlwaysFalseReverse always think it's not a reverse word // AlwaysNoReserve always think it's not a reverse word
AlwaysNoReserve = func(string) bool { return false } AlwaysNoReserve = func(string) bool { return false }
// AlwaysReverse always reverse the word // AlwaysReserve always reverse the word
AlwaysReserve = func(string) bool { return true } AlwaysReserve = func(string) bool { return true }
// CommanQuoteMark represnets the common quote mark // CommanQuoteMark represnets the common quote mark
@ -29,10 +29,12 @@ var (
CommonQuoter = Quoter{CommanQuoteMark, CommanQuoteMark, AlwaysReserve} CommonQuoter = Quoter{CommanQuoteMark, CommanQuoteMark, AlwaysReserve}
) )
// IsEmpty return true if no prefix and suffix
func (q Quoter) IsEmpty() bool { func (q Quoter) IsEmpty() bool {
return q.Prefix == 0 && q.Suffix == 0 return q.Prefix == 0 && q.Suffix == 0
} }
// Quote quote a string
func (q Quoter) Quote(s string) string { func (q Quoter) Quote(s string) string {
var buf strings.Builder var buf strings.Builder
q.QuoteTo(&buf, s) q.QuoteTo(&buf, s)
@ -59,12 +61,14 @@ func (q Quoter) Trim(s string) string {
return buf.String() return buf.String()
} }
// Join joins a slice with quoters
func (q Quoter) Join(a []string, sep string) string { func (q Quoter) Join(a []string, sep string) string {
var b strings.Builder var b strings.Builder
q.JoinWrite(&b, a, sep) q.JoinWrite(&b, a, sep)
return b.String() return b.String()
} }
// JoinWrite writes quoted content to a builder
func (q Quoter) JoinWrite(b *strings.Builder, a []string, sep string) error { func (q Quoter) JoinWrite(b *strings.Builder, a []string, sep string) error {
if len(a) == 0 { if len(a) == 0 {
return nil return nil

View File

@ -90,23 +90,28 @@ func (table *Table) PKColumns() []*Column {
return columns return columns
} }
// ColumnType returns a column's type
func (table *Table) ColumnType(name string) reflect.Type { func (table *Table) ColumnType(name string) reflect.Type {
t, _ := table.Type.FieldByName(name) t, _ := table.Type.FieldByName(name)
return t.Type return t.Type
} }
// AutoIncrColumn returns autoincrement column
func (table *Table) AutoIncrColumn() *Column { func (table *Table) AutoIncrColumn() *Column {
return table.GetColumn(table.AutoIncrement) return table.GetColumn(table.AutoIncrement)
} }
// VersionColumn returns version column's information
func (table *Table) VersionColumn() *Column { func (table *Table) VersionColumn() *Column {
return table.GetColumn(table.Version) return table.GetColumn(table.Version)
} }
// UpdatedColumn returns updated column's information
func (table *Table) UpdatedColumn() *Column { func (table *Table) UpdatedColumn() *Column {
return table.GetColumn(table.Updated) return table.GetColumn(table.Updated)
} }
// DeletedColumn returns deleted column's information
func (table *Table) DeletedColumn() *Column { func (table *Table) DeletedColumn() *Column {
return table.GetColumn(table.Deleted) return table.GetColumn(table.Deleted)
} }

View File

@ -222,53 +222,55 @@ var (
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison // !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
var ( var (
c_EMPTY_STRING string emptyString string
c_BOOL_DEFAULT bool boolDefault bool
c_BYTE_DEFAULT byte byteDefault byte
c_COMPLEX64_DEFAULT complex64 complex64Default complex64
c_COMPLEX128_DEFAULT complex128 complex128Default complex128
c_FLOAT32_DEFAULT float32 float32Default float32
c_FLOAT64_DEFAULT float64 float64Default float64
c_INT64_DEFAULT int64 int64Default int64
c_UINT64_DEFAULT uint64 uint64Default uint64
c_INT32_DEFAULT int32 int32Default int32
c_UINT32_DEFAULT uint32 uint32Default uint32
c_INT16_DEFAULT int16 int16Default int16
c_UINT16_DEFAULT uint16 uint16Default uint16
c_INT8_DEFAULT int8 int8Default int8
c_UINT8_DEFAULT uint8 uint8Default uint8
c_INT_DEFAULT int intDefault int
c_UINT_DEFAULT uint uintDefault uint
c_TIME_DEFAULT time.Time timeDefault time.Time
) )
// enumerates all types
var ( var (
IntType = reflect.TypeOf(c_INT_DEFAULT) IntType = reflect.TypeOf(intDefault)
Int8Type = reflect.TypeOf(c_INT8_DEFAULT) Int8Type = reflect.TypeOf(int8Default)
Int16Type = reflect.TypeOf(c_INT16_DEFAULT) Int16Type = reflect.TypeOf(int16Default)
Int32Type = reflect.TypeOf(c_INT32_DEFAULT) Int32Type = reflect.TypeOf(int32Default)
Int64Type = reflect.TypeOf(c_INT64_DEFAULT) Int64Type = reflect.TypeOf(int64Default)
UintType = reflect.TypeOf(c_UINT_DEFAULT) UintType = reflect.TypeOf(uintDefault)
Uint8Type = reflect.TypeOf(c_UINT8_DEFAULT) Uint8Type = reflect.TypeOf(uint8Default)
Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT) Uint16Type = reflect.TypeOf(uint16Default)
Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT) Uint32Type = reflect.TypeOf(uint32Default)
Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT) Uint64Type = reflect.TypeOf(uint64Default)
Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT) Float32Type = reflect.TypeOf(float32Default)
Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT) Float64Type = reflect.TypeOf(float64Default)
Complex64Type = reflect.TypeOf(c_COMPLEX64_DEFAULT) Complex64Type = reflect.TypeOf(complex64Default)
Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT) Complex128Type = reflect.TypeOf(complex128Default)
StringType = reflect.TypeOf(c_EMPTY_STRING) StringType = reflect.TypeOf(emptyString)
BoolType = reflect.TypeOf(c_BOOL_DEFAULT) BoolType = reflect.TypeOf(boolDefault)
ByteType = reflect.TypeOf(c_BYTE_DEFAULT) ByteType = reflect.TypeOf(byteDefault)
BytesType = reflect.SliceOf(ByteType) BytesType = reflect.SliceOf(ByteType)
TimeType = reflect.TypeOf(c_TIME_DEFAULT) TimeType = reflect.TypeOf(timeDefault)
) )
// enumerates all types
var ( var (
PtrIntType = reflect.PtrTo(IntType) PtrIntType = reflect.PtrTo(IntType)
PtrInt8Type = reflect.PtrTo(Int8Type) PtrInt8Type = reflect.PtrTo(Int8Type)
@ -313,7 +315,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
st = SQLType{Varchar, 64, 0} st = SQLType{Varchar, 64, 0}
case reflect.Array, reflect.Slice, reflect.Map: case reflect.Array, reflect.Slice, reflect.Map:
if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) { if t.Elem() == reflect.TypeOf(byteDefault) {
st = SQLType{Blob, 0, 0} st = SQLType{Blob, 0, 0}
} else { } else {
st = SQLType{Text, 0, 0} st = SQLType{Text, 0, 0}
@ -337,7 +339,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
return return
} }
// default sql type change to go types // SQLType2Type convert default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type { func SQLType2Type(st SQLType) reflect.Type {
name := strings.ToUpper(st.Name) name := strings.ToUpper(st.Name)
switch name { switch name {
@ -356,7 +358,7 @@ func SQLType2Type(st SQLType) reflect.Type {
case Bool: case Bool:
return reflect.TypeOf(true) return reflect.TypeOf(true)
case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime, Year: case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime, Year:
return reflect.TypeOf(c_TIME_DEFAULT) return reflect.TypeOf(timeDefault)
case Decimal, Numeric, Money, SmallMoney: case Decimal, Numeric, Money, SmallMoney:
return reflect.TypeOf("") return reflect.TypeOf("")
default: default:

View File

@ -21,9 +21,11 @@ import (
) )
var ( var (
// ErrUnsupportedType represents an unsupported type error
ErrUnsupportedType = errors.New("Unsupported type") ErrUnsupportedType = errors.New("Unsupported type")
) )
// Parser represents a parser for xorm tag
type Parser struct { type Parser struct {
identifier string identifier string
dialect dialects.Dialect dialect dialects.Dialect
@ -34,6 +36,7 @@ type Parser struct {
tableCache sync.Map // map[reflect.Type]*schemas.Table tableCache sync.Map // map[reflect.Type]*schemas.Table
} }
// NewParser creates a tag parser
func NewParser(identifier string, dialect dialects.Dialect, tableMapper, columnMapper names.Mapper, cacherMgr *caches.Manager) *Parser { func NewParser(identifier string, dialect dialects.Dialect, tableMapper, columnMapper names.Mapper, cacherMgr *caches.Manager) *Parser {
return &Parser{ return &Parser{
identifier: identifier, identifier: identifier,
@ -45,29 +48,35 @@ func NewParser(identifier string, dialect dialects.Dialect, tableMapper, columnM
} }
} }
// GetTableMapper returns table mapper
func (parser *Parser) GetTableMapper() names.Mapper { func (parser *Parser) GetTableMapper() names.Mapper {
return parser.tableMapper return parser.tableMapper
} }
// SetTableMapper sets table mapper
func (parser *Parser) SetTableMapper(mapper names.Mapper) { func (parser *Parser) SetTableMapper(mapper names.Mapper) {
parser.ClearCaches() parser.ClearCaches()
parser.tableMapper = mapper parser.tableMapper = mapper
} }
// GetColumnMapper returns column mapper
func (parser *Parser) GetColumnMapper() names.Mapper { func (parser *Parser) GetColumnMapper() names.Mapper {
return parser.columnMapper return parser.columnMapper
} }
// SetColumnMapper sets column mapper
func (parser *Parser) SetColumnMapper(mapper names.Mapper) { func (parser *Parser) SetColumnMapper(mapper names.Mapper) {
parser.ClearCaches() parser.ClearCaches()
parser.columnMapper = mapper parser.columnMapper = mapper
} }
// SetIdentifier sets tag identifier
func (parser *Parser) SetIdentifier(identifier string) { func (parser *Parser) SetIdentifier(identifier string) {
parser.ClearCaches() parser.ClearCaches()
parser.identifier = identifier parser.identifier = identifier
} }
// ParseWithCache parse a struct with cache
func (parser *Parser) ParseWithCache(v reflect.Value) (*schemas.Table, error) { func (parser *Parser) ParseWithCache(v reflect.Value) (*schemas.Table, error) {
t := v.Type() t := v.Type()
tableI, ok := parser.tableCache.Load(t) tableI, ok := parser.tableCache.Load(t)