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  }