/
githubmirror
/
GoFrame
Обзор
Документация
Войти
/
githubmirror
/
GoFrame
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
contrib/drivers/mysql/mysql.go
173 строки
5 KB
Lonely
improve Timezone escape for driver dm/mysql (#2412)
08 фев 2023, 14:35
Не верифицирован
08 фев 2023, 14:35
013f8b2
Код
Авторство
О чём код?
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. // Package mysql implements gdb.Driver, which supports operations for database MySQL. package mysql import ( "context" "database/sql" "fmt" "net/url" "strings" _ "github.com/go-sql-driver/mysql" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/util/gutil" ) // Driver is the driver for mysql database. type Driver struct { *gdb.Core } func init() { var ( err error driverObj = New() driverNames = g.SliceStr{"mysql", "mariadb", "tidb"} ) for _, driverName := range driverNames { if err = gdb.Register(driverName, driverObj); err != nil { panic(err) } } } // New create and returns a driver that implements gdb.Driver, which supports operations for MySQL. func New() gdb.Driver { return &Driver{} } // New creates and returns a database object for mysql. // It implements the interface of gdb.Driver for extra database driver installation. func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) { return &Driver{ Core: core, }, nil } // Open creates and returns an underlying sql.DB object for mysql. // Note that it converts time.Time argument to local timezone in default. func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { var ( source string underlyingDriverName = "mysql" ) // [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] if config.Link != "" { // ============================================================================ // Deprecated from v2.2.0. // ============================================================================ source = config.Link // Custom changing the schema in runtime. if config.Name != "" { source, _ = gregex.ReplaceString(`/([\w\.\-]+)+`, "/"+config.Name, source) } } else { source = fmt.Sprintf( "%s:%s@%s(%s:%s)/%s?charset=%s", config.User, config.Pass, config.Protocol, config.Host, config.Port, config.Name, config.Charset, ) if config.Timezone != "" { if strings.Contains(config.Timezone, "/") { config.Timezone = url.QueryEscape(config.Timezone) } source = fmt.Sprintf("%s&loc=%s", source, config.Timezone) } if config.Extra != "" { source = fmt.Sprintf("%s&%s", source, config.Extra) } } if db, err = sql.Open(underlyingDriverName, source); err != nil { err = gerror.WrapCodef( gcode.CodeDbOperationError, err, `sql.Open failed for driver "%s" by source "%s"`, underlyingDriverName, source, ) return nil, err } return } // GetChars returns the security char for this type of database. func (d *Driver) GetChars() (charLeft string, charRight string) { return "`", "`" } // DoFilter handles the sql before posts it to database. func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) { return d.Core.DoFilter(ctx, link, sql, args) } // Tables retrieves and returns the tables of current schema. // It's mainly used in cli tool chain for automatically generating the models. func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) { var result gdb.Result link, err := d.SlaveLink(schema...) if err != nil { return nil, err } result, err = d.DoSelect(ctx, link, `SHOW TABLES`) if err != nil { return } for _, m := range result { for _, v := range m { tables = append(tables, v.String()) } } return } // TableFields retrieves and returns the fields' information of specified table of current // schema. // // The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection // as its link to proceed necessary sql query. // // Note that it returns a map containing the field name and its corresponding fields. // As a map is unsorted, the TableField struct has a "Index" field marks its sequence in // the fields. // // It's using cache feature to enhance the performance, which is never expired util the // process restarts. func (d *Driver) TableFields( ctx context.Context, table string, schema ...string, ) (fields map[string]*gdb.TableField, err error) { var ( result gdb.Result link gdb.Link useSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...) ) if link, err = d.SlaveLink(useSchema); err != nil { return nil, err } result, err = d.DoSelect( ctx, link, fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.QuoteWord(table)), ) if err != nil { return nil, err } fields = make(map[string]*gdb.TableField) for i, m := range result { fields[m["Field"].String()] = &gdb.TableField{ Index: i, Name: m["Field"].String(), Type: m["Type"].String(), Null: m["Null"].Bool(), Key: m["Key"].String(), Default: m["Default"].Val(), Extra: m["Extra"].String(), Comment: m["Comment"].String(), } } return fields, nil }