github.com/XiaoMi/Gaea@v1.2.5/proxy/router/rule.go (about)

     1  // Copyright 2016 The kingshard Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  // Copyright 2019 The Gaea Authors. All Rights Reserved.
    16  //
    17  // Licensed under the Apache License, Version 2.0 (the "License");
    18  // you may not use this file except in compliance with the License.
    19  // You may obtain a copy of the License at
    20  //
    21  //     http://www.apache.org/licenses/LICENSE-2.0
    22  //
    23  // Unless required by applicable law or agreed to in writing, software
    24  // distributed under the License is distributed on an "AS IS" BASIS,
    25  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    26  // See the License for the specific language governing permissions and
    27  // limitations under the License.
    28  
    29  package router
    30  
    31  import (
    32  	"fmt"
    33  	"regexp"
    34  	"strconv"
    35  	"strings"
    36  
    37  	"github.com/XiaoMi/Gaea/core/errors"
    38  	"github.com/XiaoMi/Gaea/models"
    39  )
    40  
    41  const (
    42  	DefaultRuleType         = models.ShardDefault
    43  	GlobalTableRuleType     = models.ShardGlobal
    44  	LinkedTableRuleType     = models.ShardLinked // this type only exists in conf, then transfer to LinkedRule
    45  	HashRuleType            = models.ShardHash
    46  	RangeRuleType           = models.ShardRange
    47  	ModRuleType             = models.ShardMod
    48  	DateYearRuleType        = models.ShardYear
    49  	DateMonthRuleType       = models.ShardMonth
    50  	DateDayRuleType         = models.ShardDay
    51  	MycatModRuleType        = models.ShardMycatMod
    52  	MycatLongRuleType       = models.ShardMycatLong
    53  	MycatStringRuleType     = models.ShardMycatString
    54  	MycatMurmurRuleType     = models.ShardMycatMURMUR
    55  	MycatPaddingModRuleType = models.ShardMycatPaddingMod
    56  
    57  	MinMonthDaysCount = 28
    58  	MaxMonthDaysCount = 31
    59  	MonthsCount       = 12
    60  )
    61  
    62  type Rule interface {
    63  	GetDB() string
    64  	GetTable() string
    65  	GetShardingColumn() string
    66  	IsLinkedRule() bool
    67  	GetShard() Shard
    68  	FindTableIndex(key interface{}) (int, error)
    69  	GetSlice(i int) string // i is slice index
    70  	GetSliceIndexFromTableIndex(i int) int
    71  	GetSlices() []string
    72  	GetSubTableIndexes() []int
    73  	GetFirstTableIndex() int
    74  	GetLastTableIndex() int
    75  	GetType() string
    76  	GetDatabaseNameByTableIndex(index int) (string, error)
    77  }
    78  
    79  type MycatRule interface {
    80  	Rule
    81  	GetDatabases() []string
    82  	GetTableIndexByDatabaseName(phyDB string) (int, bool)
    83  }
    84  
    85  type BaseRule struct {
    86  	db             string
    87  	table          string
    88  	shardingColumn string
    89  
    90  	ruleType        string
    91  	slices          []string    // not the namespace slices
    92  	subTableIndexes []int       //subTableIndexes store all the index of sharding sub-table
    93  	tableToSlice    map[int]int //key is table index, and value is slice index
    94  	shard           Shard
    95  
    96  	// TODO: 目前全局表也借用这两个field存放默认分片的物理DB名
    97  	mycatDatabases               []string
    98  	mycatDatabaseToTableIndexMap map[string]int // key: phy db name, value: table index
    99  }
   100  
   101  type LinkedRule struct {
   102  	db             string
   103  	table          string
   104  	shardingColumn string
   105  
   106  	linkToRule *BaseRule
   107  }
   108  
   109  func NewDefaultRule(slice string) *BaseRule {
   110  	var r *BaseRule = &BaseRule{
   111  		ruleType:     DefaultRuleType,
   112  		slices:       []string{slice},
   113  		shard:        new(DefaultShard),
   114  		tableToSlice: nil,
   115  	}
   116  	return r
   117  }
   118  
   119  func (r *BaseRule) GetDB() string {
   120  	return r.db
   121  }
   122  
   123  func (r *BaseRule) GetTable() string {
   124  	return r.table
   125  }
   126  
   127  func (r *BaseRule) GetShardingColumn() string {
   128  	return r.shardingColumn
   129  }
   130  
   131  func (r *BaseRule) IsLinkedRule() bool {
   132  	return false
   133  }
   134  
   135  func (r *BaseRule) GetShard() Shard {
   136  	return r.shard
   137  }
   138  
   139  func (r *BaseRule) FindTableIndex(key interface{}) (int, error) {
   140  	return r.shard.FindForKey(key)
   141  }
   142  
   143  // The confs should be verified before use to avoid panic.
   144  func (r *BaseRule) GetSlice(i int) string {
   145  	return r.slices[i]
   146  }
   147  
   148  func (r *BaseRule) GetSliceIndexFromTableIndex(i int) int {
   149  	sliceIndex, ok := r.tableToSlice[i]
   150  	if !ok {
   151  		return -1
   152  	}
   153  	return sliceIndex
   154  }
   155  
   156  // This is dangerous since the caller can change the value in slices.
   157  // It is better to return a iterator instead of exposing the origin slices.
   158  func (r *BaseRule) GetSlices() []string {
   159  	return r.slices
   160  }
   161  
   162  func (r *BaseRule) GetSubTableIndexes() []int {
   163  	return r.subTableIndexes
   164  }
   165  
   166  func (r *BaseRule) GetFirstTableIndex() int {
   167  	return r.subTableIndexes[0]
   168  }
   169  
   170  func (r *BaseRule) GetLastTableIndex() int {
   171  	return r.subTableIndexes[len(r.subTableIndexes)-1]
   172  }
   173  
   174  func (r *BaseRule) GetType() string {
   175  	return r.ruleType
   176  }
   177  
   178  func (r *BaseRule) GetDatabaseNameByTableIndex(index int) (string, error) {
   179  	if IsMycatShardingRule(r.ruleType) || r.ruleType == GlobalTableRuleType {
   180  		if index > len(r.subTableIndexes) {
   181  			return "", errors.ErrInvalidArgument
   182  		}
   183  		return r.mycatDatabases[index], nil
   184  	}
   185  	return r.db, nil
   186  }
   187  
   188  func (r *BaseRule) GetTableIndexByDatabaseName(phyDB string) (int, bool) {
   189  	idx, ok := r.mycatDatabaseToTableIndexMap[phyDB]
   190  	return idx, ok
   191  }
   192  
   193  func (r *BaseRule) GetDatabases() []string {
   194  	return r.mycatDatabases
   195  }
   196  
   197  func (l *LinkedRule) GetDB() string {
   198  	return l.db
   199  }
   200  
   201  func (l *LinkedRule) GetTable() string {
   202  	return l.table
   203  }
   204  
   205  func (l *LinkedRule) GetParentDB() string {
   206  	return l.linkToRule.GetDB()
   207  }
   208  
   209  func (l *LinkedRule) GetParentTable() string {
   210  	return l.linkToRule.GetTable()
   211  }
   212  
   213  func (l *LinkedRule) GetShardingColumn() string {
   214  	return l.shardingColumn
   215  }
   216  
   217  func (l *LinkedRule) IsLinkedRule() bool {
   218  	return true
   219  }
   220  
   221  func (l *LinkedRule) GetShard() Shard {
   222  	return l.linkToRule.GetShard()
   223  }
   224  
   225  func (l *LinkedRule) FindTableIndex(key interface{}) (int, error) {
   226  	return l.linkToRule.FindTableIndex(key)
   227  }
   228  
   229  func (l *LinkedRule) GetFirstTableIndex() int {
   230  	return l.linkToRule.GetFirstTableIndex()
   231  }
   232  
   233  func (l *LinkedRule) GetLastTableIndex() int {
   234  	return l.linkToRule.GetLastTableIndex()
   235  }
   236  
   237  func (l *LinkedRule) GetSlice(i int) string {
   238  	return l.linkToRule.GetSlice(i)
   239  }
   240  
   241  func (l *LinkedRule) GetSliceIndexFromTableIndex(i int) int {
   242  	return l.linkToRule.GetSliceIndexFromTableIndex(i)
   243  }
   244  
   245  func (l *LinkedRule) GetSlices() []string {
   246  	return l.linkToRule.GetSlices()
   247  }
   248  
   249  func (l *LinkedRule) GetSubTableIndexes() []int {
   250  	return l.linkToRule.GetSubTableIndexes()
   251  }
   252  
   253  func (l *LinkedRule) GetType() string {
   254  	return l.linkToRule.GetType()
   255  }
   256  
   257  func (l *LinkedRule) GetDatabaseNameByTableIndex(index int) (string, error) {
   258  	return l.linkToRule.GetDatabaseNameByTableIndex(index)
   259  }
   260  
   261  func (l *LinkedRule) GetDatabases() []string {
   262  	return l.linkToRule.GetDatabases()
   263  }
   264  
   265  func (l *LinkedRule) GetTableIndexByDatabaseName(phyDB string) (int, bool) {
   266  	return l.linkToRule.GetTableIndexByDatabaseName(phyDB)
   267  }
   268  
   269  func createLinkedRule(rules map[string]map[string]Rule, shard *models.Shard) (*LinkedRule, error) {
   270  	if shard.Type != LinkedTableRuleType {
   271  		return nil, fmt.Errorf("LinkedRule type is not linked: %v", shard)
   272  	}
   273  
   274  	tableRules, ok := rules[shard.DB]
   275  	if !ok {
   276  		return nil, fmt.Errorf("db of LinkedRule is not found in parent rules")
   277  	}
   278  	dbRule, ok := tableRules[strings.ToLower(shard.ParentTable)]
   279  	if !ok {
   280  		return nil, fmt.Errorf("parent table of LinkedRule is not found in parent rules")
   281  	}
   282  	if dbRule.GetType() == LinkedTableRuleType {
   283  		return nil, fmt.Errorf("LinkedRule cannot link to another LinkedRule")
   284  	}
   285  	linkToRule, ok := dbRule.(*BaseRule)
   286  	if !ok {
   287  		return nil, fmt.Errorf("LinkedRule must link to a BaseRule")
   288  	}
   289  
   290  	linkedRule := &LinkedRule{
   291  		db:             shard.DB,
   292  		table:          strings.ToLower(shard.Table),
   293  		shardingColumn: strings.ToLower(shard.Key),
   294  		linkToRule:     linkToRule,
   295  	}
   296  
   297  	return linkedRule, nil
   298  }
   299  
   300  func parseRule(cfg *models.Shard) (*BaseRule, error) {
   301  	r := new(BaseRule)
   302  	r.db = cfg.DB
   303  	r.table = strings.ToLower(cfg.Table)
   304  	r.shardingColumn = strings.ToLower(cfg.Key) //ignore case
   305  	r.ruleType = cfg.Type
   306  	r.slices = cfg.Slices //将rule model中的slices赋值给rule
   307  	r.mycatDatabaseToTableIndexMap = make(map[string]int)
   308  
   309  	subTableIndexs, tableToSlice, shard, err := parseRuleSliceInfos(cfg)
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  
   314  	r.subTableIndexes = subTableIndexs
   315  	r.tableToSlice = tableToSlice
   316  	r.shard = shard
   317  
   318  	if IsMycatShardingRule(cfg.Type) {
   319  		r.mycatDatabases, err = getRealDatabases(cfg.Databases)
   320  		if err != nil {
   321  			return nil, err
   322  		}
   323  		for i, db := range r.mycatDatabases {
   324  			r.mycatDatabaseToTableIndexMap[db] = i
   325  		}
   326  	}
   327  
   328  	if cfg.Type == GlobalTableRuleType {
   329  		// 如果全局表指定了物理库名, 则使用mycatDatabases存储这一信息, 否则使用逻辑库名作为物理库名.
   330  		if len(cfg.Databases) != 0 {
   331  			r.mycatDatabases, err = getRealDatabases(cfg.Databases)
   332  			if err != nil {
   333  				return nil, err
   334  			}
   335  		} else {
   336  			for i := 0; i < len(r.subTableIndexes); i++ {
   337  				r.mycatDatabases = append(r.mycatDatabases, r.db)
   338  			}
   339  		}
   340  		for i, db := range r.mycatDatabases {
   341  			r.mycatDatabaseToTableIndexMap[db] = i
   342  		}
   343  	}
   344  
   345  	return r, nil
   346  }
   347  
   348  func parseRuleSliceInfos(cfg *models.Shard) ([]int, map[int]int, Shard, error) {
   349  	switch cfg.Type {
   350  	case HashRuleType:
   351  		subTableIndexs, tableToSlice, err := parseHashRuleSliceInfos(cfg.Locations, cfg.Slices)
   352  		if err != nil {
   353  			return nil, nil, nil, err
   354  		}
   355  		shard := &HashShard{ShardNum: len(tableToSlice)}
   356  		return subTableIndexs, tableToSlice, shard, nil
   357  	case ModRuleType:
   358  		subTableIndexs, tableToSlice, err := parseHashRuleSliceInfos(cfg.Locations, cfg.Slices)
   359  		if err != nil {
   360  			return nil, nil, nil, err
   361  		}
   362  		shard := &ModShard{ShardNum: len(tableToSlice)}
   363  		return subTableIndexs, tableToSlice, shard, nil
   364  	case RangeRuleType:
   365  		subTableIndexs, tableToSlice, err := parseHashRuleSliceInfos(cfg.Locations, cfg.Slices)
   366  		if err != nil {
   367  			return nil, nil, nil, err
   368  		}
   369  		rs, err := ParseNumSharding(cfg.Locations, cfg.TableRowLimit)
   370  		if err != nil {
   371  			return nil, nil, nil, err
   372  		}
   373  		if len(rs) != len(tableToSlice) {
   374  			return nil, nil, nil, fmt.Errorf("range space %d not equal tables %d", len(rs), len(tableToSlice))
   375  		}
   376  		shard := &NumRangeShard{Shards: rs}
   377  		return subTableIndexs, tableToSlice, shard, nil
   378  	case DateDayRuleType:
   379  		subTableIndexs, tableToSlice, err := parseDateDayRuleSliceInfos(cfg.DateRange, cfg.Slices)
   380  		if err != nil {
   381  			return nil, nil, nil, err
   382  		}
   383  		shard := &DateDayShard{}
   384  		return subTableIndexs, tableToSlice, shard, nil
   385  	case DateMonthRuleType:
   386  		subTableIndexs, tableToSlice, err := parseDateMonthRuleSliceInfos(cfg.DateRange, cfg.Slices)
   387  		if err != nil {
   388  			return nil, nil, nil, err
   389  		}
   390  		shard := &DateMonthShard{}
   391  		return subTableIndexs, tableToSlice, shard, nil
   392  	case DateYearRuleType:
   393  		subTableIndexs, tableToSlice, err := parseDateYearRuleSliceInfos(cfg.DateRange, cfg.Slices)
   394  		if err != nil {
   395  			return nil, nil, nil, err
   396  		}
   397  		shard := &DateYearShard{}
   398  		return subTableIndexs, tableToSlice, shard, nil
   399  	case MycatModRuleType:
   400  		subTableIndexs, tableToSlice, err := parseMycatHashRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   401  		if err != nil {
   402  			return nil, nil, nil, err
   403  		}
   404  		shard := NewMycatPartitionModShard(len(tableToSlice))
   405  		return subTableIndexs, tableToSlice, shard, nil
   406  	case MycatLongRuleType:
   407  		subTableIndexs, tableToSlice, err := parseMycatHashRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   408  		if err != nil {
   409  			return nil, nil, nil, err
   410  		}
   411  		shard := NewMycatPartitionLongShard(len(tableToSlice), cfg.PartitionCount, cfg.PartitionLength)
   412  		if err = shard.Init(); err != nil {
   413  			return nil, nil, nil, err
   414  		}
   415  		return subTableIndexs, tableToSlice, shard, nil
   416  	case MycatStringRuleType:
   417  		subTableIndexs, tableToSlice, err := parseMycatHashRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   418  		if err != nil {
   419  			return nil, nil, nil, err
   420  		}
   421  		shard := NewMycatPartitionStringShard(len(tableToSlice), cfg.PartitionCount, cfg.PartitionLength, cfg.HashSlice)
   422  		if err = shard.Init(); err != nil {
   423  			return nil, nil, nil, err
   424  		}
   425  		return subTableIndexs, tableToSlice, shard, nil
   426  	case MycatMurmurRuleType:
   427  		subTableIndexs, tableToSlice, err := parseMycatHashRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   428  		if err != nil {
   429  			return nil, nil, nil, err
   430  		}
   431  
   432  		shard, err := NewMycatPartitionMurmurHashShard(cfg.Seed, cfg.VirtualBucketTimes, len(tableToSlice))
   433  		if err != nil {
   434  			return nil, nil, nil, err
   435  		}
   436  		if err = shard.Init(); err != nil {
   437  			return nil, nil, nil, err
   438  		}
   439  		return subTableIndexs, tableToSlice, shard, nil
   440  	case MycatPaddingModRuleType:
   441  		subTableIndexs, tableToSlice, err := parseMycatHashRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   442  		if err != nil {
   443  			return nil, nil, nil, err
   444  		}
   445  
   446  		shard, err := GetMycatPartitionPaddingModShard(cfg.PadFrom, cfg.PadLength, cfg.ModBegin, cfg.ModEnd, len(tableToSlice))
   447  		if err != nil {
   448  			return nil, nil, nil, err
   449  		}
   450  		if err = shard.Init(); err != nil {
   451  			return nil, nil, nil, err
   452  		}
   453  		return subTableIndexs, tableToSlice, shard, nil
   454  	case GlobalTableRuleType:
   455  		subTableIndexs, tableToSlice, err := parseGlobalTableRuleSliceInfos(cfg.Locations, cfg.Slices, cfg.Databases)
   456  		if err != nil {
   457  			return nil, nil, nil, err
   458  		}
   459  		shard := NewGlobalTableShard()
   460  		return subTableIndexs, tableToSlice, shard, nil
   461  	default:
   462  		return nil, nil, nil, errors.ErrUnknownRuleType
   463  	}
   464  }
   465  
   466  func parseHashRuleSliceInfos(locations []int, slices []string) ([]int, map[int]int, error) {
   467  	var sumTables int
   468  	var subTableIndexs []int
   469  	tableToSlice := make(map[int]int, 0)
   470  
   471  	if len(locations) != len(slices) {
   472  		return nil, nil, errors.ErrLocationsCount
   473  	}
   474  	for i := 0; i < len(locations); i++ {
   475  		for j := 0; j < locations[i]; j++ {
   476  			subTableIndexs = append(subTableIndexs, j+sumTables)
   477  			tableToSlice[j+sumTables] = i
   478  		}
   479  		sumTables += locations[i]
   480  	}
   481  	return subTableIndexs, tableToSlice, nil
   482  }
   483  
   484  func parseMycatHashRuleSliceInfos(locations []int, slices []string, databases []string) ([]int, map[int]int, error) {
   485  	subTableIndexs, tableToSlice, err := parseHashRuleSliceInfos(locations, slices)
   486  	if err != nil {
   487  		return nil, nil, err
   488  	}
   489  
   490  	realDatabaseList, err := getRealDatabases(databases)
   491  	if err != nil {
   492  		return nil, nil, err
   493  	}
   494  
   495  	if len(tableToSlice) != len(realDatabaseList) {
   496  		return nil, nil, errors.ErrLocationsCount
   497  	}
   498  
   499  	return subTableIndexs, tableToSlice, nil
   500  }
   501  
   502  func parseDateDayRuleSliceInfos(dateRange []string, slices []string) ([]int, map[int]int, error) {
   503  	var subTableIndexs []int
   504  	tableToSlice := make(map[int]int, 0)
   505  
   506  	if len(dateRange) != len(slices) {
   507  		return nil, nil, errors.ErrDateRangeCount
   508  	}
   509  	for i := 0; i < len(dateRange); i++ {
   510  		dayNumbers, err := ParseDayRange(dateRange[i])
   511  		if err != nil {
   512  			return nil, nil, err
   513  		}
   514  		if len(subTableIndexs) > 0 && dayNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] {
   515  			return nil, nil, errors.ErrDateRangeOverlap
   516  		}
   517  		for _, v := range dayNumbers {
   518  			subTableIndexs = append(subTableIndexs, v)
   519  			tableToSlice[v] = i
   520  		}
   521  	}
   522  	return subTableIndexs, tableToSlice, nil
   523  }
   524  
   525  func parseDateMonthRuleSliceInfos(dateRange []string, slices []string) ([]int, map[int]int, error) {
   526  	var subTableIndexs []int
   527  	tableToSlice := make(map[int]int, 0)
   528  
   529  	if len(dateRange) != len(slices) {
   530  		return nil, nil, errors.ErrDateRangeCount
   531  	}
   532  	for i := 0; i < len(dateRange); i++ {
   533  		monthNumbers, err := ParseMonthRange(dateRange[i])
   534  		if err != nil {
   535  			return nil, nil, err
   536  		}
   537  		if len(subTableIndexs) > 0 && monthNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] {
   538  			return nil, nil, errors.ErrDateRangeOverlap
   539  		}
   540  		for _, v := range monthNumbers {
   541  			subTableIndexs = append(subTableIndexs, v)
   542  			tableToSlice[v] = i
   543  		}
   544  	}
   545  	return subTableIndexs, tableToSlice, nil
   546  }
   547  
   548  func parseDateYearRuleSliceInfos(dateRange []string, slices []string) ([]int, map[int]int, error) {
   549  	var subTableIndexs []int
   550  	tableToSlice := make(map[int]int, 0)
   551  
   552  	if len(dateRange) != len(slices) {
   553  		return nil, nil, errors.ErrDateRangeCount
   554  	}
   555  	for i := 0; i < len(dateRange); i++ {
   556  		yearNumbers, err := ParseYearRange(dateRange[i])
   557  		if err != nil {
   558  			return nil, nil, err
   559  		}
   560  		if len(subTableIndexs) > 0 && yearNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] {
   561  			return nil, nil, errors.ErrDateRangeOverlap
   562  		}
   563  		for _, v := range yearNumbers {
   564  			tableToSlice[v] = i
   565  			subTableIndexs = append(subTableIndexs, v)
   566  		}
   567  	}
   568  	return subTableIndexs, tableToSlice, nil
   569  }
   570  
   571  func parseGlobalTableRuleSliceInfos(locations []int, slices []string, databases []string) ([]int, map[int]int, error) {
   572  	subTableIndexs, tableToSlice, err := parseHashRuleSliceInfos(locations, slices)
   573  	if err != nil {
   574  		return nil, nil, err
   575  	}
   576  
   577  	if len(databases) != 0 {
   578  		realDatabaseList, err := getRealDatabases(databases)
   579  		if err != nil {
   580  			return nil, nil, err
   581  		}
   582  		if len(tableToSlice) != len(realDatabaseList) {
   583  			return nil, nil, errors.ErrLocationsCount
   584  		}
   585  	}
   586  
   587  	return subTableIndexs, tableToSlice, nil
   588  }
   589  
   590  func includeSlice(slices []string, sliceName string) bool {
   591  	for _, s := range slices {
   592  		if s == sliceName {
   593  			return true
   594  		}
   595  	}
   596  	return false
   597  }
   598  
   599  var rangeDatabaseRegex = regexp.MustCompile(`^(\S+?)\[(\d+)-(\d+)\]$`)
   600  
   601  // if a dbname is a database list, then parse the real dbnames and add to the result.
   602  // the range contains left bound and right bound, which means [left, right].
   603  func getRealDatabases(dbs []string) ([]string, error) {
   604  	var ret []string
   605  	for _, db := range dbs {
   606  		if rangeDatabaseRegex.MatchString(db) {
   607  			matches := rangeDatabaseRegex.FindStringSubmatch(db)
   608  			if len(matches) != 4 {
   609  				return nil, fmt.Errorf("invalid database list: %s", db)
   610  			}
   611  			dbPrefix := matches[1]
   612  			leftBoundStr := matches[2]
   613  			rightBoundStr := matches[3]
   614  			leftBound, err := strconv.Atoi(leftBoundStr)
   615  			if err != nil {
   616  				return nil, fmt.Errorf("invalid left bound value of database list: %s", db)
   617  			}
   618  			rightBound, err := strconv.Atoi(rightBoundStr)
   619  			if err != nil {
   620  				return nil, fmt.Errorf("invalid right bound value of database list: %s", db)
   621  			}
   622  			if rightBound <= leftBound {
   623  				return nil, fmt.Errorf("invalid bound value of database list: %s", db)
   624  			}
   625  			for i := leftBound; i <= rightBound; i++ {
   626  				realDB := dbPrefix + strconv.Itoa(i)
   627  				ret = append(ret, realDB)
   628  			}
   629  		} else {
   630  			ret = append(ret, db)
   631  		}
   632  	}
   633  	return ret, nil
   634  }
   635  
   636  func IsMycatShardingRule(ruleType string) bool {
   637  	return ruleType == MycatModRuleType || ruleType == MycatLongRuleType || ruleType == MycatMurmurRuleType || ruleType == MycatPaddingModRuleType || ruleType == MycatStringRuleType
   638  }