github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-xorm/tidb/tidb_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 tidb
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/insionng/yougam/libraries/go-xorm/core"
    14  )
    15  
    16  type tidb struct {
    17  	core.Base
    18  }
    19  
    20  func (db *tidb) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
    21  	return db.Base.Init(d, db, uri, drivername, dataSourceName)
    22  }
    23  
    24  func (db *tidb) SqlType(c *core.Column) string {
    25  	var res string
    26  	switch t := c.SQLType.Name; t {
    27  	case core.Bool:
    28  		res = core.Bool
    29  	case core.Serial:
    30  		c.IsAutoIncrement = true
    31  		c.IsPrimaryKey = true
    32  		c.Nullable = false
    33  		res = core.Int
    34  	case core.BigSerial:
    35  		c.IsAutoIncrement = true
    36  		c.IsPrimaryKey = true
    37  		c.Nullable = false
    38  		res = core.BigInt
    39  	case core.Bytea:
    40  		res = core.Blob
    41  	case core.TimeStampz:
    42  		res = core.Char
    43  		c.Length = 64
    44  	case core.Enum: //mysql enum
    45  		res = core.Enum
    46  		res += "("
    47  		opts := ""
    48  		for v, _ := range c.EnumOptions {
    49  			opts += fmt.Sprintf(",'%v'", v)
    50  		}
    51  		res += strings.TrimLeft(opts, ",")
    52  		res += ")"
    53  	case core.Set: //mysql set
    54  		res = core.Set
    55  		res += "("
    56  		opts := ""
    57  		for v, _ := range c.SetOptions {
    58  			opts += fmt.Sprintf(",'%v'", v)
    59  		}
    60  		res += strings.TrimLeft(opts, ",")
    61  		res += ")"
    62  	case core.NVarchar:
    63  		res = core.Varchar
    64  	case core.Uuid:
    65  		res = core.Varchar
    66  		c.Length = 40
    67  	case core.Json:
    68  		res = core.Text
    69  	default:
    70  		res = t
    71  	}
    72  
    73  	var hasLen1 bool = (c.Length > 0)
    74  	var hasLen2 bool = (c.Length2 > 0)
    75  
    76  	if res == core.BigInt && !hasLen1 && !hasLen2 {
    77  		c.Length = 20
    78  		hasLen1 = true
    79  	}
    80  
    81  	if hasLen2 {
    82  		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
    83  	} else if hasLen1 {
    84  		res += "(" + strconv.Itoa(c.Length) + ")"
    85  	}
    86  	return res
    87  }
    88  
    89  func (db *tidb) SupportInsertMany() bool {
    90  	return true
    91  }
    92  
    93  func (db *tidb) IsReserved(name string) bool {
    94  	return false
    95  }
    96  
    97  func (db *tidb) Quote(name string) string {
    98  	return "`" + name + "`"
    99  }
   100  
   101  func (db *tidb) QuoteStr() string {
   102  	return "`"
   103  }
   104  
   105  func (db *tidb) SupportEngine() bool {
   106  	return false
   107  }
   108  
   109  func (db *tidb) AutoIncrStr() string {
   110  	return "AUTO_INCREMENT"
   111  }
   112  
   113  func (db *tidb) SupportCharset() bool {
   114  	return false
   115  }
   116  
   117  func (db *tidb) IndexOnTable() bool {
   118  	return true
   119  }
   120  
   121  func (db *tidb) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
   122  	args := []interface{}{db.DbName, tableName, idxName}
   123  	sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
   124  	sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
   125  	return sql, args
   126  }
   127  
   128  func (db *tidb) TableCheckSql(tableName string) (string, []interface{}) {
   129  	args := []interface{}{db.DbName, tableName}
   130  	sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
   131  	return sql, args
   132  }
   133  
   134  func (db *tidb) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
   135  	args := []interface{}{db.DbName, tableName}
   136  	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
   137  		" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
   138  
   139  	rows, err := db.DB().Query(s, args...)
   140  	db.LogSQL(s, args)
   141  
   142  	if err != nil {
   143  		return nil, nil, err
   144  	}
   145  	defer rows.Close()
   146  
   147  	cols := make(map[string]*core.Column)
   148  	colSeq := make([]string, 0)
   149  	for rows.Next() {
   150  		col := new(core.Column)
   151  		col.Indexes = make(map[string]int)
   152  
   153  		var columnName, isNullable, colType, colKey, extra string
   154  		var colDefault *string
   155  		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra)
   156  		if err != nil {
   157  			return nil, nil, err
   158  		}
   159  		col.Name = strings.Trim(columnName, "` ")
   160  		if "YES" == isNullable {
   161  			col.Nullable = true
   162  		}
   163  
   164  		if colDefault != nil {
   165  			col.Default = *colDefault
   166  			if col.Default == "" {
   167  				col.DefaultIsEmpty = true
   168  			}
   169  		}
   170  
   171  		cts := strings.Split(colType, "(")
   172  		colName := cts[0]
   173  		colType = strings.ToUpper(colName)
   174  		var len1, len2 int
   175  		if len(cts) == 2 {
   176  			idx := strings.Index(cts[1], ")")
   177  			if colType == core.Enum && cts[1][0] == '\'' { //enum
   178  				options := strings.Split(cts[1][0:idx], ",")
   179  				col.EnumOptions = make(map[string]int)
   180  				for k, v := range options {
   181  					v = strings.TrimSpace(v)
   182  					v = strings.Trim(v, "'")
   183  					col.EnumOptions[v] = k
   184  				}
   185  			} else if colType == core.Set && cts[1][0] == '\'' {
   186  				options := strings.Split(cts[1][0:idx], ",")
   187  				col.SetOptions = make(map[string]int)
   188  				for k, v := range options {
   189  					v = strings.TrimSpace(v)
   190  					v = strings.Trim(v, "'")
   191  					col.SetOptions[v] = k
   192  				}
   193  			} else {
   194  				lens := strings.Split(cts[1][0:idx], ",")
   195  				len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
   196  				if err != nil {
   197  					return nil, nil, err
   198  				}
   199  				if len(lens) == 2 {
   200  					len2, err = strconv.Atoi(lens[1])
   201  					if err != nil {
   202  						return nil, nil, err
   203  					}
   204  				}
   205  			}
   206  		}
   207  		if colType == "FLOAT UNSIGNED" {
   208  			colType = "FLOAT"
   209  		}
   210  		col.Length = len1
   211  		col.Length2 = len2
   212  		if _, ok := core.SqlTypes[colType]; ok {
   213  			col.SQLType = core.SQLType{colType, len1, len2}
   214  		} else {
   215  			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
   216  		}
   217  
   218  		if colKey == "PRI" {
   219  			col.IsPrimaryKey = true
   220  		}
   221  		if colKey == "UNI" {
   222  			//col.is
   223  		}
   224  
   225  		if extra == "auto_increment" {
   226  			col.IsAutoIncrement = true
   227  		}
   228  
   229  		if col.SQLType.IsText() || col.SQLType.IsTime() {
   230  			if col.Default != "" {
   231  				col.Default = "'" + col.Default + "'"
   232  			} else {
   233  				if col.DefaultIsEmpty {
   234  					col.Default = "''"
   235  				}
   236  			}
   237  		}
   238  		cols[col.Name] = col
   239  		colSeq = append(colSeq, col.Name)
   240  	}
   241  	return colSeq, cols, nil
   242  }
   243  
   244  func (db *tidb) GetTables() ([]*core.Table, error) {
   245  	args := []interface{}{db.DbName}
   246  	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
   247  		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
   248  
   249  	rows, err := db.DB().Query(s, args...)
   250  	db.LogSQL(s, args)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	defer rows.Close()
   255  
   256  	tables := make([]*core.Table, 0)
   257  	for rows.Next() {
   258  		table := core.NewEmptyTable()
   259  		var name, engine, tableRows string
   260  		var autoIncr *string
   261  		err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
   262  		if err != nil {
   263  			return nil, err
   264  		}
   265  
   266  		table.Name = name
   267  		table.StoreEngine = engine
   268  		tables = append(tables, table)
   269  	}
   270  	return tables, nil
   271  }
   272  
   273  func (db *tidb) GetIndexes(tableName string) (map[string]*core.Index, error) {
   274  	args := []interface{}{db.DbName, tableName}
   275  	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
   276  
   277  	rows, err := db.DB().Query(s, args...)
   278  	db.LogSQL(s, args)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  	defer rows.Close()
   283  
   284  	indexes := make(map[string]*core.Index, 0)
   285  	for rows.Next() {
   286  		var indexType int
   287  		var indexName, colName, nonUnique string
   288  		err = rows.Scan(&indexName, &nonUnique, &colName)
   289  		if err != nil {
   290  			return nil, err
   291  		}
   292  
   293  		if indexName == "PRIMARY" {
   294  			continue
   295  		}
   296  
   297  		if "YES" == nonUnique || nonUnique == "1" {
   298  			indexType = core.IndexType
   299  		} else {
   300  			indexType = core.UniqueType
   301  		}
   302  
   303  		colName = strings.Trim(colName, "` ")
   304  		var isRegular bool
   305  		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
   306  			indexName = indexName[5+len(tableName) : len(indexName)]
   307  			isRegular = true
   308  		}
   309  
   310  		var index *core.Index
   311  		var ok bool
   312  		if index, ok = indexes[indexName]; !ok {
   313  			index = new(core.Index)
   314  			index.IsRegular = isRegular
   315  			index.Type = indexType
   316  			index.Name = indexName
   317  			indexes[indexName] = index
   318  		}
   319  		index.AddColumn(colName)
   320  	}
   321  	return indexes, nil
   322  }
   323  
   324  func (db *tidb) Filters() []core.Filter {
   325  	return []core.Filter{&core.IdFilter{}}
   326  }