func removeIncompatibleWords(sql string) string {
	re := regexp.MustCompile(` ON UPDATE CASCADE`)
	sql = re.ReplaceAllString(sql, "")
	re = regexp.MustCompile(`/\*!5`)
	sql = re.ReplaceAllString(sql, "/* 5")
	re = regexp.MustCompile(`CHARACTER SET [a-z_0-9]* `)
	sql = re.ReplaceAllString(sql, "")
	return sql
}
removeIncompatibleWords remove pingcap/parser not support words from schema
Note: only for MySQL `SHOW CREATE TABLE` hand-writing SQL not compatible
package rebuild
import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"github.com/juju/errors"
	"github.com/LianjiaTech/lightning/common"
	_ "github.com/go-sql-driver/mysql"
	"github.com/pingcap/parser/ast"
	"github.com/pingcap/parser/model"
	"github.com/pingcap/parser/mysql"
)
var Schemas []*ast.CreateTableStmt
var Columns map[string][]string
var PrimaryKeys map[string][]string
func LoadSchemaInfo() {
	if common.Config.MySQL.SchemaFile != "" {
		err := loadSchemaFromFile()
		if err != nil {
			common.Log.Error(errors.Trace(err).Error())
		}
		return
	} else {
		err := loadSchemaFromMySQL()
		if err != nil {
			common.Log.Error(errors.Trace(err).Error())
		}
	}
}
func loadSchemaFromFile() error {
	common.Log.Debug("loadSchemaFromFile %s", common.Config.MySQL.SchemaFile)
	if _, err := os.Stat(common.Config.MySQL.SchemaFile); err != nil {
		return err
	}
	buf, err := ioutil.ReadFile(common.Config.MySQL.SchemaFile)
	if err != nil {
		return err
	}
	err = schemaAppend("", string(buf))
	buildColumns()
	buildPrimaryKeys()
	return err
}
func loadSchemaFromMySQL() error {
	var databases []string
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=%s&timeout=5s",
		common.MasterInfo.MasterUser,
		common.MasterInfo.MasterPassword,
		common.MasterInfo.MasterHost,
		common.MasterInfo.MasterPort,
		common.Config.Global.Charset,
	)
	common.Log.Debug("loadSchemaFromMySQL %s", dsn)
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	defer db.Close()
	res, err := db.Query("SHOW DATABASES;")
	if err != nil {
		return err
	}
	for res.Next() {
		var database string
		res.Scan(&database)
		switch database {
		case "information_schema", "sys", "mysql", "performance_schema":
		default:
			databases = append(databases, database)
		}
	}
	for _, database := range databases {
		res, err := db.Query(fmt.Sprintf("SHOW TABLES FROM `%s`", database))
		if err != nil {
			common.Log.Error(errors.Trace(err).Error())
			continue
		}
		for res.Next() {
			var table string
			err = res.Scan(&table)
			if err != nil {
				common.Log.Error(errors.Trace(err).Error())
				continue
			}
			tableRes, err := db.Query(fmt.Sprintf("SHOW CREATE TABLE `%s`.`%s`;", database, table))
			if err != nil {
				common.Log.Error(errors.Trace(err).Error())
				continue
			}
			cols, err := tableRes.Columns()
			if err != nil {
				common.Log.Error(errors.Trace(err).Error())
				continue
			}
			if len(cols) != 2 {
				common.Log.Info("by pass host: %s, port: %d, database: %s, table: %s",
					common.MasterInfo.MasterHost,
					common.MasterInfo.MasterPort,
					database, table)
				continue
			}
			for tableRes.Next() {
				var name, schema string
				err = tableRes.Scan(&name, &schema)
				if err != nil {
					common.Log.Error("host: %s, port: %d, database: %s, table: %s, error: %s",
						common.MasterInfo.MasterHost,
						common.MasterInfo.MasterPort,
						database, table, errors.Trace(err).Error())
					continue
				}
				err = schemaAppend(database, schema)
				if err != nil {
					common.Log.Error("host: %s, port: %d, database: %s, table: %s, sql: %s, error: %s",
						common.MasterInfo.MasterHost,
						common.MasterInfo.MasterPort,
						database, table,
						schema,
						errors.Trace(err).Error())
					schemaAppend(database, buildFakeTable(db, fmt.Sprintf("`%s`.`%s`", database, table)))
				}
			}
			tableRes.Close()
		}
		res.Close()
	}
	buildColumns()
	buildPrimaryKeys()
	return nil
}
func schemaAppend(database, sql string) error {
	sql = removeIncompatibleWords(sql)
	stmts, err := TiParse(sql, common.Config.Global.Charset, mysql.Charsets[common.Config.Global.Charset])
	if err != nil {
		return err
	}
	if database == "" {
		database = "%"
	}
	for _, stmt := range stmts {
		switch node := stmt.(type) {
		case *ast.CreateTableStmt:
			if node.Table.Schema.String() == "" {
				node.Table.Schema = model.NewCIStr(database)
			}
			Schemas = append(Schemas, node)
		case *ast.UseStmt:
			database = node.DBName
		}
	}
	return nil
}