2015-01-20 21:15:48 +08:00
package migrator
2015-01-19 17:44:16 +08:00
2017-03-28 20:34:53 +08:00
import (
2018-05-10 22:54:21 +08:00
"fmt"
2017-03-28 20:34:53 +08:00
"strconv"
"strings"
2018-05-10 22:54:21 +08:00
2018-09-27 18:07:43 +08:00
"github.com/VividCortex/mysqlerr"
"github.com/go-sql-driver/mysql"
2020-04-01 21:57:21 +08:00
"xorm.io/xorm"
2017-03-28 20:34:53 +08:00
)
2015-01-19 17:44:16 +08:00
type Mysql struct {
BaseDialect
}
2018-05-10 22:54:21 +08:00
func NewMysqlDialect ( engine * xorm . Engine ) * Mysql {
2015-01-19 17:44:16 +08:00
d := Mysql { }
d . BaseDialect . dialect = & d
2018-05-10 22:54:21 +08:00
d . BaseDialect . engine = engine
2015-01-19 17:44:16 +08:00
d . BaseDialect . driverName = MYSQL
return & d
}
2015-01-20 21:44:37 +08:00
func ( db * Mysql ) SupportEngine ( ) bool {
return true
}
2015-01-19 17:44:16 +08:00
func ( db * Mysql ) Quote ( name string ) string {
return "`" + name + "`"
}
func ( db * Mysql ) AutoIncrStr ( ) string {
return "AUTO_INCREMENT"
}
2016-09-23 14:07:14 +08:00
func ( db * Mysql ) BooleanStr ( value bool ) string {
2016-10-25 20:52:20 +08:00
if value {
2016-12-14 11:15:35 +08:00
return "1"
}
return "0"
2016-09-23 14:07:14 +08:00
}
2015-01-19 17:44:16 +08:00
func ( db * Mysql ) SqlType ( c * Column ) string {
var res string
switch c . Type {
case DB_Bool :
res = DB_TinyInt
c . Length = 1
case DB_Serial :
c . IsAutoIncrement = true
c . IsPrimaryKey = true
c . Nullable = false
res = DB_Int
case DB_BigSerial :
c . IsAutoIncrement = true
c . IsPrimaryKey = true
c . Nullable = false
res = DB_BigInt
case DB_Bytea :
res = DB_Blob
case DB_TimeStampz :
res = DB_Char
c . Length = 64
case DB_NVarchar :
res = DB_Varchar
default :
res = c . Type
}
2018-04-28 04:14:36 +08:00
var hasLen1 = ( c . Length > 0 )
var hasLen2 = ( c . Length2 > 0 )
2015-01-19 17:44:16 +08:00
if res == DB_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 ) + ")"
}
2017-03-28 20:34:53 +08:00
switch c . Type {
case DB_Char , DB_Varchar , DB_NVarchar , DB_TinyText , DB_Text , DB_MediumText , DB_LongText :
res += " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
}
2015-01-19 17:44:16 +08:00
return res
}
2017-03-28 20:34:53 +08:00
func ( db * Mysql ) UpdateTableSql ( tableName string , columns [ ] * Column ) string {
var statements = [ ] string { }
statements = append ( statements , "DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" )
for _ , col := range columns {
statements = append ( statements , "MODIFY " + col . StringNoPk ( db ) )
}
return "ALTER TABLE " + db . Quote ( tableName ) + " " + strings . Join ( statements , ", " ) + ";"
}
2018-05-10 22:54:21 +08:00
2018-12-19 04:47:45 +08:00
func ( db * Mysql ) IndexCheckSql ( tableName , indexName string ) ( string , [ ] interface { } ) {
args := [ ] interface { } { tableName , indexName }
sql := "SELECT 1 FROM " + db . Quote ( "INFORMATION_SCHEMA" ) + "." + db . Quote ( "STATISTICS" ) + " WHERE " + db . Quote ( "TABLE_SCHEMA" ) + " = DATABASE() AND " + db . Quote ( "TABLE_NAME" ) + "=? AND " + db . Quote ( "INDEX_NAME" ) + "=?"
return sql , args
}
2018-12-19 06:02:08 +08:00
func ( db * Mysql ) ColumnCheckSql ( tableName , columnName string ) ( string , [ ] interface { } ) {
args := [ ] interface { } { tableName , columnName }
sql := "SELECT 1 FROM " + db . Quote ( "INFORMATION_SCHEMA" ) + "." + db . Quote ( "COLUMNS" ) + " WHERE " + db . Quote ( "TABLE_SCHEMA" ) + " = DATABASE() AND " + db . Quote ( "TABLE_NAME" ) + "=? AND " + db . Quote ( "COLUMN_NAME" ) + "=?"
return sql , args
}
2018-05-10 22:54:21 +08:00
func ( db * Mysql ) CleanDB ( ) error {
tables , _ := db . engine . DBMetas ( )
sess := db . engine . NewSession ( )
defer sess . Close ( )
for _ , table := range tables {
if _ , err := sess . Exec ( "set foreign_key_checks = 0" ) ; err != nil {
return fmt . Errorf ( "failed to disable foreign key checks" )
}
if _ , err := sess . Exec ( "drop table " + table . Name + " ;" ) ; err != nil {
return fmt . Errorf ( "failed to delete table: %v, err: %v" , table . Name , err )
}
if _ , err := sess . Exec ( "set foreign_key_checks = 1" ) ; err != nil {
return fmt . Errorf ( "failed to disable foreign key checks" )
}
}
return nil
}
2018-09-27 18:07:43 +08:00
2019-06-13 21:36:09 +08:00
func ( db * Mysql ) isThisError ( err error , errcode uint16 ) bool {
2018-09-27 18:07:43 +08:00
if driverErr , ok := err . ( * mysql . MySQLError ) ; ok {
2019-06-13 21:36:09 +08:00
if driverErr . Number == errcode {
2018-09-27 18:07:43 +08:00
return true
}
}
return false
}
2019-06-13 21:36:09 +08:00
func ( db * Mysql ) IsUniqueConstraintViolation ( err error ) bool {
return db . isThisError ( err , mysqlerr . ER_DUP_ENTRY )
}
2020-04-20 21:48:38 +08:00
func ( db * Mysql ) ErrorMessage ( err error ) string {
if driverErr , ok := err . ( * mysql . MySQLError ) ; ok {
return driverErr . Message
}
return ""
}
2019-06-13 21:36:09 +08:00
func ( db * Mysql ) IsDeadlock ( err error ) bool {
return db . isThisError ( err , mysqlerr . ER_LOCK_DEADLOCK )
}