github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-xorm/xorm/mysql_dialect.go (about) 1 // Copyright 2015 The Xorm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xorm 6 7 import ( 8 "crypto/tls" 9 "fmt" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/insionng/yougam/libraries/go-xorm/core" 15 ) 16 17 var ( 18 mysqlReservedWords = map[string]bool{ 19 "ADD": true, 20 "ALL": true, 21 "ALTER": true, 22 "ANALYZE": true, 23 "AND": true, 24 "AS": true, 25 "ASC": true, 26 "ASENSITIVE": true, 27 "BEFORE": true, 28 "BETWEEN": true, 29 "BIGINT": true, 30 "BINARY": true, 31 "BLOB": true, 32 "BOTH": true, 33 "BY": true, 34 "CALL": true, 35 "CASCADE": true, 36 "CASE": true, 37 "CHANGE": true, 38 "CHAR": true, 39 "CHARACTER": true, 40 "CHECK": true, 41 "COLLATE": true, 42 "COLUMN": true, 43 "CONDITION": true, 44 "CONNECTION": true, 45 "CONSTRAINT": true, 46 "CONTINUE": true, 47 "CONVERT": true, 48 "CREATE": true, 49 "CROSS": true, 50 "CURRENT_DATE": true, 51 "CURRENT_TIME": true, 52 "CURRENT_TIMESTAMP": true, 53 "CURRENT_USER": true, 54 "CURSOR": true, 55 "DATABASE": true, 56 "DATABASES": true, 57 "DAY_HOUR": true, 58 "DAY_MICROSECOND": true, 59 "DAY_MINUTE": true, 60 "DAY_SECOND": true, 61 "DEC": true, 62 "DECIMAL": true, 63 "DECLARE": true, 64 "DEFAULT": true, 65 "DELAYED": true, 66 "DELETE": true, 67 "DESC": true, 68 "DESCRIBE": true, 69 "DETERMINISTIC": true, 70 "DISTINCT": true, 71 "DISTINCTROW": true, 72 "DIV": true, 73 "DOUBLE": true, 74 "DROP": true, 75 "DUAL": true, 76 "EACH": true, 77 "ELSE": true, 78 "ELSEIF": true, 79 "ENCLOSED": true, 80 "ESCAPED": true, 81 "EXISTS": true, 82 "EXIT": true, 83 "EXPLAIN": true, 84 "FALSE": true, 85 "FETCH": true, 86 "FLOAT": true, 87 "FLOAT4": true, 88 "FLOAT8": true, 89 "FOR": true, 90 "FORCE": true, 91 "FOREIGN": true, 92 "FROM": true, 93 "FULLTEXT": true, 94 "GOTO": true, 95 "GRANT": true, 96 "GROUP": true, 97 "HAVING": true, 98 "HIGH_PRIORITY": true, 99 "HOUR_MICROSECOND": true, 100 "HOUR_MINUTE": true, 101 "HOUR_SECOND": true, 102 "IF": true, 103 "IGNORE": true, 104 "IN": true, "INDEX": true, 105 "INFILE": true, "INNER": true, "INOUT": true, 106 "INSENSITIVE": true, "INSERT": true, "INT": true, 107 "INT1": true, "INT2": true, "INT3": true, 108 "INT4": true, "INT8": true, "INTEGER": true, 109 "INTERVAL": true, "INTO": true, "IS": true, 110 "ITERATE": true, "JOIN": true, "KEY": true, 111 "KEYS": true, "KILL": true, "LABEL": true, 112 "LEADING": true, "LEAVE": true, "LEFT": true, 113 "LIKE": true, "LIMIT": true, "LINEAR": true, 114 "LINES": true, "LOAD": true, "LOCALTIME": true, 115 "LOCALTIMESTAMP": true, "LOCK": true, "LONG": true, 116 "LONGBLOB": true, "LONGTEXT": true, "LOOP": true, 117 "LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true, 118 "MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true, 119 "MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true, 120 "MODIFIES": true, "NATURAL": true, "NOT": true, 121 "NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true, 122 "ON OPTIMIZE": true, "OPTION": true, 123 "OPTIONALLY": true, "OR": true, "ORDER": true, 124 "OUT": true, "OUTER": true, "OUTFILE": true, 125 "PRECISION": true, "PRIMARY": true, "PROCEDURE": true, 126 "PURGE": true, "RAID0": true, "RANGE": true, 127 "READ": true, "READS": true, "REAL": true, 128 "REFERENCES": true, "REGEXP": true, "RELEASE": true, 129 "RENAME": true, "REPEAT": true, "REPLACE": true, 130 "REQUIRE": true, "RESTRICT": true, "RETURN": true, 131 "REVOKE": true, "RIGHT": true, "RLIKE": true, 132 "SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true, 133 "SELECT": true, "SENSITIVE": true, "SEPARATOR": true, 134 "SET": true, "SHOW": true, "SMALLINT": true, 135 "SPATIAL": true, "SPECIFIC": true, "SQL": true, 136 "SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true, 137 "SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true, 138 "SSL": true, "STARTING": true, "STRAIGHT_JOIN": true, 139 "TABLE": true, "TERMINATED": true, "THEN": true, 140 "TINYBLOB": true, "TINYINT": true, "TINYTEXT": true, 141 "TO": true, "TRAILING": true, "TRIGGER": true, 142 "TRUE": true, "UNDO": true, "UNION": true, 143 "UNIQUE": true, "UNLOCK": true, "UNSIGNED": true, 144 "UPDATE": true, "USAGE": true, "USE": true, 145 "USING": true, "UTC_DATE": true, "UTC_TIME": true, 146 "UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true, 147 "VARCHAR": true, 148 "VARCHARACTER": true, 149 "VARYING": true, 150 "WHEN": true, 151 "WHERE": true, 152 "WHILE": true, 153 "WITH": true, 154 "WRITE": true, 155 "X509": true, 156 "XOR": true, 157 "YEAR_MONTH": true, 158 "ZEROFILL": true, 159 } 160 ) 161 162 type mysql struct { 163 core.Base 164 net string 165 addr string 166 params map[string]string 167 loc *time.Location 168 timeout time.Duration 169 tls *tls.Config 170 allowAllFiles bool 171 allowOldPasswords bool 172 clientFoundRows bool 173 } 174 175 func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { 176 return db.Base.Init(d, db, uri, drivername, dataSourceName) 177 } 178 179 func (db *mysql) SqlType(c *core.Column) string { 180 var res string 181 switch t := c.SQLType.Name; t { 182 case core.Bool: 183 res = core.TinyInt 184 c.Length = 1 185 case core.Serial: 186 c.IsAutoIncrement = true 187 c.IsPrimaryKey = true 188 c.Nullable = false 189 res = core.Int 190 case core.BigSerial: 191 c.IsAutoIncrement = true 192 c.IsPrimaryKey = true 193 c.Nullable = false 194 res = core.BigInt 195 case core.Bytea: 196 res = core.Blob 197 case core.TimeStampz: 198 res = core.Char 199 c.Length = 64 200 case core.Enum: //mysql enum 201 res = core.Enum 202 res += "(" 203 opts := "" 204 for v := range c.EnumOptions { 205 opts += fmt.Sprintf(",'%v'", v) 206 } 207 res += strings.TrimLeft(opts, ",") 208 res += ")" 209 case core.Set: //mysql set 210 res = core.Set 211 res += "(" 212 opts := "" 213 for v := range c.SetOptions { 214 opts += fmt.Sprintf(",'%v'", v) 215 } 216 res += strings.TrimLeft(opts, ",") 217 res += ")" 218 case core.NVarchar: 219 res = core.Varchar 220 case core.Uuid: 221 res = core.Varchar 222 c.Length = 40 223 case core.Json: 224 res = core.Text 225 default: 226 res = t 227 } 228 229 hasLen1 := (c.Length > 0) 230 hasLen2 := (c.Length2 > 0) 231 232 if res == core.BigInt && !hasLen1 && !hasLen2 { 233 c.Length = 20 234 hasLen1 = true 235 } 236 237 if hasLen2 { 238 res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" 239 } else if hasLen1 { 240 res += "(" + strconv.Itoa(c.Length) + ")" 241 } 242 return res 243 } 244 245 func (db *mysql) SupportInsertMany() bool { 246 return true 247 } 248 249 func (db *mysql) IsReserved(name string) bool { 250 _, ok := mysqlReservedWords[name] 251 return ok 252 } 253 254 func (db *mysql) Quote(name string) string { 255 return "`" + name + "`" 256 } 257 258 func (db *mysql) QuoteStr() string { 259 return "`" 260 } 261 262 func (db *mysql) SupportEngine() bool { 263 return true 264 } 265 266 func (db *mysql) AutoIncrStr() string { 267 return "AUTO_INCREMENT" 268 } 269 270 func (db *mysql) SupportCharset() bool { 271 return true 272 } 273 274 func (db *mysql) IndexOnTable() bool { 275 return true 276 } 277 278 func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { 279 args := []interface{}{db.DbName, tableName, idxName} 280 sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`" 281 sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?" 282 return sql, args 283 } 284 285 /*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { 286 args := []interface{}{db.DbName, tableName, colName} 287 sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?" 288 return sql, args 289 }*/ 290 291 func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) { 292 args := []interface{}{db.DbName, tableName} 293 sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?" 294 return sql, args 295 } 296 297 func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { 298 args := []interface{}{db.DbName, tableName} 299 s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + 300 " `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" 301 db.LogSQL(s, args) 302 303 rows, err := db.DB().Query(s, args...) 304 if err != nil { 305 return nil, nil, err 306 } 307 defer rows.Close() 308 309 cols := make(map[string]*core.Column) 310 colSeq := make([]string, 0) 311 for rows.Next() { 312 col := new(core.Column) 313 col.Indexes = make(map[string]int) 314 315 var columnName, isNullable, colType, colKey, extra string 316 var colDefault *string 317 err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra) 318 if err != nil { 319 return nil, nil, err 320 } 321 col.Name = strings.Trim(columnName, "` ") 322 if "YES" == isNullable { 323 col.Nullable = true 324 } 325 326 if colDefault != nil { 327 col.Default = *colDefault 328 if col.Default == "" { 329 col.DefaultIsEmpty = true 330 } 331 } 332 333 cts := strings.Split(colType, "(") 334 colName := cts[0] 335 colType = strings.ToUpper(colName) 336 var len1, len2 int 337 if len(cts) == 2 { 338 idx := strings.Index(cts[1], ")") 339 if colType == core.Enum && cts[1][0] == '\'' { //enum 340 options := strings.Split(cts[1][0:idx], ",") 341 col.EnumOptions = make(map[string]int) 342 for k, v := range options { 343 v = strings.TrimSpace(v) 344 v = strings.Trim(v, "'") 345 col.EnumOptions[v] = k 346 } 347 } else if colType == core.Set && cts[1][0] == '\'' { 348 options := strings.Split(cts[1][0:idx], ",") 349 col.SetOptions = make(map[string]int) 350 for k, v := range options { 351 v = strings.TrimSpace(v) 352 v = strings.Trim(v, "'") 353 col.SetOptions[v] = k 354 } 355 } else { 356 lens := strings.Split(cts[1][0:idx], ",") 357 len1, err = strconv.Atoi(strings.TrimSpace(lens[0])) 358 if err != nil { 359 return nil, nil, err 360 } 361 if len(lens) == 2 { 362 len2, err = strconv.Atoi(lens[1]) 363 if err != nil { 364 return nil, nil, err 365 } 366 } 367 } 368 } 369 if colType == "FLOAT UNSIGNED" { 370 colType = "FLOAT" 371 } 372 col.Length = len1 373 col.Length2 = len2 374 if _, ok := core.SqlTypes[colType]; ok { 375 col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2} 376 } else { 377 return nil, nil, fmt.Errorf("Unknown colType %v", colType) 378 } 379 380 if colKey == "PRI" { 381 col.IsPrimaryKey = true 382 } 383 if colKey == "UNI" { 384 //col.is 385 } 386 387 if extra == "auto_increment" { 388 col.IsAutoIncrement = true 389 } 390 391 if col.SQLType.IsText() || col.SQLType.IsTime() { 392 if col.Default != "" { 393 col.Default = "'" + col.Default + "'" 394 } else { 395 if col.DefaultIsEmpty { 396 col.Default = "''" 397 } 398 } 399 } 400 cols[col.Name] = col 401 colSeq = append(colSeq, col.Name) 402 } 403 return colSeq, cols, nil 404 } 405 406 func (db *mysql) GetTables() ([]*core.Table, error) { 407 args := []interface{}{db.DbName} 408 s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " + 409 "`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')" 410 db.LogSQL(s, args) 411 412 rows, err := db.DB().Query(s, args...) 413 if err != nil { 414 return nil, err 415 } 416 defer rows.Close() 417 418 tables := make([]*core.Table, 0) 419 for rows.Next() { 420 table := core.NewEmptyTable() 421 var name, engine, tableRows string 422 var autoIncr *string 423 err = rows.Scan(&name, &engine, &tableRows, &autoIncr) 424 if err != nil { 425 return nil, err 426 } 427 428 table.Name = name 429 table.StoreEngine = engine 430 tables = append(tables, table) 431 } 432 return tables, nil 433 } 434 435 func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) { 436 args := []interface{}{db.DbName, tableName} 437 s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" 438 db.LogSQL(s, args) 439 440 rows, err := db.DB().Query(s, args...) 441 if err != nil { 442 return nil, err 443 } 444 defer rows.Close() 445 446 indexes := make(map[string]*core.Index, 0) 447 for rows.Next() { 448 var indexType int 449 var indexName, colName, nonUnique string 450 err = rows.Scan(&indexName, &nonUnique, &colName) 451 if err != nil { 452 return nil, err 453 } 454 455 if indexName == "PRIMARY" { 456 continue 457 } 458 459 if "YES" == nonUnique || nonUnique == "1" { 460 indexType = core.IndexType 461 } else { 462 indexType = core.UniqueType 463 } 464 465 colName = strings.Trim(colName, "` ") 466 var isRegular bool 467 if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { 468 indexName = indexName[5+len(tableName) : len(indexName)] 469 isRegular = true 470 } 471 472 var index *core.Index 473 var ok bool 474 if index, ok = indexes[indexName]; !ok { 475 index = new(core.Index) 476 index.IsRegular = isRegular 477 index.Type = indexType 478 index.Name = indexName 479 indexes[indexName] = index 480 } 481 index.AddColumn(colName) 482 } 483 return indexes, nil 484 } 485 486 func (db *mysql) Filters() []core.Filter { 487 return []core.Filter{&core.IdFilter{}} 488 }