This repository has been archived by the owner on Jun 21, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 47a6395
Showing
4 changed files
with
562 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
tidb driver and dialect for github.com/go-xorm/xorm | ||
======== | ||
|
||
** experiment support ** | ||
|
||
STATUS: build pass but some tests failed. | ||
|
||
Currently, we can support tidb for some operations. | ||
|
||
# How to use | ||
|
||
Just like other supports of xorm, but you should import the three packages: | ||
|
||
Since github.com/cznic/ql# has not been resolved, we just use github.com/lunny/ql instead. | ||
|
||
```Go | ||
import ( | ||
_ "github.com/pingcap/tidb" | ||
_ "github.com/go-xorm/tidb" | ||
"github.com/go-xorm/xorm" | ||
) | ||
|
||
// for open a file | ||
xorm.NewEngine("tidb", "goleveldb://./tidb.db") | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,333 @@ | ||
// Copyright 2015 The Xorm Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package tidb | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/go-xorm/core" | ||
) | ||
|
||
type tidb struct { | ||
core.Base | ||
} | ||
|
||
func (db *tidb) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { | ||
return db.Base.Init(d, db, uri, drivername, dataSourceName) | ||
} | ||
|
||
func (db *tidb) SqlType(c *core.Column) string { | ||
var res string | ||
switch t := c.SQLType.Name; t { | ||
case core.Bool: | ||
res = core.TinyInt | ||
c.Length = 1 | ||
case core.Serial: | ||
c.IsAutoIncrement = true | ||
c.IsPrimaryKey = true | ||
c.Nullable = false | ||
res = core.Int | ||
case core.BigSerial: | ||
c.IsAutoIncrement = true | ||
c.IsPrimaryKey = true | ||
c.Nullable = false | ||
res = core.BigInt | ||
case core.Bytea: | ||
res = core.Blob | ||
case core.TimeStampz: | ||
res = core.Char | ||
c.Length = 64 | ||
case core.Enum: //mysql enum | ||
res = core.Enum | ||
res += "(" | ||
opts := "" | ||
for v, _ := range c.EnumOptions { | ||
opts += fmt.Sprintf(",'%v'", v) | ||
} | ||
res += strings.TrimLeft(opts, ",") | ||
res += ")" | ||
case core.Set: //mysql set | ||
res = core.Set | ||
res += "(" | ||
opts := "" | ||
for v, _ := range c.SetOptions { | ||
opts += fmt.Sprintf(",'%v'", v) | ||
} | ||
res += strings.TrimLeft(opts, ",") | ||
res += ")" | ||
case core.NVarchar: | ||
res = core.Varchar | ||
case core.Uuid: | ||
res = core.Varchar | ||
c.Length = 40 | ||
case core.Json: | ||
res = core.Text | ||
default: | ||
res = t | ||
} | ||
|
||
var hasLen1 bool = (c.Length > 0) | ||
var hasLen2 bool = (c.Length2 > 0) | ||
|
||
if res == core.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) + ")" | ||
} | ||
return res | ||
} | ||
|
||
func (db *tidb) SupportInsertMany() bool { | ||
return true | ||
} | ||
|
||
func (db *tidb) IsReserved(name string) bool { | ||
return false | ||
} | ||
|
||
func (db *tidb) Quote(name string) string { | ||
return "`" + name + "`" | ||
} | ||
|
||
func (db *tidb) QuoteStr() string { | ||
return "`" | ||
} | ||
|
||
func (db *tidb) SupportEngine() bool { | ||
return false | ||
} | ||
|
||
func (db *tidb) AutoIncrStr() string { | ||
return "AUTO_INCREMENT" | ||
} | ||
|
||
func (db *tidb) SupportCharset() bool { | ||
return false | ||
} | ||
|
||
func (db *tidb) IndexOnTable() bool { | ||
return true | ||
} | ||
|
||
func (db *tidb) IndexCheckSql(tableName, idxName string) (string, []interface{}) { | ||
args := []interface{}{db.DbName, tableName, idxName} | ||
sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`" | ||
sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?" | ||
return sql, args | ||
} | ||
|
||
func (db *tidb) TableCheckSql(tableName string) (string, []interface{}) { | ||
args := []interface{}{db.DbName, tableName} | ||
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?" | ||
return sql, args | ||
} | ||
|
||
func (db *tidb) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { | ||
args := []interface{}{db.DbName, tableName} | ||
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + | ||
" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" | ||
|
||
rows, err := db.DB().Query(s, args...) | ||
if db.Logger != nil { | ||
db.Logger.Info("[sql]", s, args) | ||
} | ||
|
||
if err != nil { | ||
return nil, nil, err | ||
} | ||
defer rows.Close() | ||
|
||
cols := make(map[string]*core.Column) | ||
colSeq := make([]string, 0) | ||
for rows.Next() { | ||
col := new(core.Column) | ||
col.Indexes = make(map[string]bool) | ||
|
||
var columnName, isNullable, colType, colKey, extra string | ||
var colDefault *string | ||
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
col.Name = strings.Trim(columnName, "` ") | ||
if "YES" == isNullable { | ||
col.Nullable = true | ||
} | ||
|
||
if colDefault != nil { | ||
col.Default = *colDefault | ||
if col.Default == "" { | ||
col.DefaultIsEmpty = true | ||
} | ||
} | ||
|
||
cts := strings.Split(colType, "(") | ||
colName := cts[0] | ||
colType = strings.ToUpper(colName) | ||
var len1, len2 int | ||
if len(cts) == 2 { | ||
idx := strings.Index(cts[1], ")") | ||
if colType == core.Enum && cts[1][0] == '\'' { //enum | ||
options := strings.Split(cts[1][0:idx], ",") | ||
col.EnumOptions = make(map[string]int) | ||
for k, v := range options { | ||
v = strings.TrimSpace(v) | ||
v = strings.Trim(v, "'") | ||
col.EnumOptions[v] = k | ||
} | ||
} else if colType == core.Set && cts[1][0] == '\'' { | ||
options := strings.Split(cts[1][0:idx], ",") | ||
col.SetOptions = make(map[string]int) | ||
for k, v := range options { | ||
v = strings.TrimSpace(v) | ||
v = strings.Trim(v, "'") | ||
col.SetOptions[v] = k | ||
} | ||
} else { | ||
lens := strings.Split(cts[1][0:idx], ",") | ||
len1, err = strconv.Atoi(strings.TrimSpace(lens[0])) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
if len(lens) == 2 { | ||
len2, err = strconv.Atoi(lens[1]) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
} | ||
} | ||
} | ||
if colType == "FLOAT UNSIGNED" { | ||
colType = "FLOAT" | ||
} | ||
col.Length = len1 | ||
col.Length2 = len2 | ||
if _, ok := core.SqlTypes[colType]; ok { | ||
col.SQLType = core.SQLType{colType, len1, len2} | ||
} else { | ||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType)) | ||
} | ||
|
||
if colKey == "PRI" { | ||
col.IsPrimaryKey = true | ||
} | ||
if colKey == "UNI" { | ||
//col.is | ||
} | ||
|
||
if extra == "auto_increment" { | ||
col.IsAutoIncrement = true | ||
} | ||
|
||
if col.SQLType.IsText() || col.SQLType.IsTime() { | ||
if col.Default != "" { | ||
col.Default = "'" + col.Default + "'" | ||
} else { | ||
if col.DefaultIsEmpty { | ||
col.Default = "''" | ||
} | ||
} | ||
} | ||
cols[col.Name] = col | ||
colSeq = append(colSeq, col.Name) | ||
} | ||
return colSeq, cols, nil | ||
} | ||
|
||
func (db *tidb) GetTables() ([]*core.Table, error) { | ||
args := []interface{}{db.DbName} | ||
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " + | ||
"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')" | ||
|
||
rows, err := db.DB().Query(s, args...) | ||
if db.Logger != nil { | ||
db.Logger.Info("[sql]", s, args) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer rows.Close() | ||
|
||
tables := make([]*core.Table, 0) | ||
for rows.Next() { | ||
table := core.NewEmptyTable() | ||
var name, engine, tableRows string | ||
var autoIncr *string | ||
err = rows.Scan(&name, &engine, &tableRows, &autoIncr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
table.Name = name | ||
table.StoreEngine = engine | ||
tables = append(tables, table) | ||
} | ||
return tables, nil | ||
} | ||
|
||
func (db *tidb) GetIndexes(tableName string) (map[string]*core.Index, error) { | ||
args := []interface{}{db.DbName, tableName} | ||
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" | ||
|
||
rows, err := db.DB().Query(s, args...) | ||
if db.Logger != nil { | ||
db.Logger.Info("[sql]", s, args) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer rows.Close() | ||
|
||
indexes := make(map[string]*core.Index, 0) | ||
for rows.Next() { | ||
var indexType int | ||
var indexName, colName, nonUnique string | ||
err = rows.Scan(&indexName, &nonUnique, &colName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if indexName == "PRIMARY" { | ||
continue | ||
} | ||
|
||
if "YES" == nonUnique || nonUnique == "1" { | ||
indexType = core.IndexType | ||
} else { | ||
indexType = core.UniqueType | ||
} | ||
|
||
colName = strings.Trim(colName, "` ") | ||
var isRegular bool | ||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { | ||
indexName = indexName[5+len(tableName) : len(indexName)] | ||
isRegular = true | ||
} | ||
|
||
var index *core.Index | ||
var ok bool | ||
if index, ok = indexes[indexName]; !ok { | ||
index = new(core.Index) | ||
index.IsRegular = isRegular | ||
index.Type = indexType | ||
index.Name = indexName | ||
indexes[indexName] = index | ||
} | ||
index.AddColumn(colName) | ||
} | ||
return indexes, nil | ||
} | ||
|
||
func (db *tidb) Filters() []core.Filter { | ||
return []core.Filter{&core.IdFilter{}} | ||
} |
Oops, something went wrong.