github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/xapi/tablecodec/tablecodec.go (about)

     1  // Copyright 2016 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain 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,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package tablecodec
    15  
    16  import (
    17  	"bytes"
    18  	"time"
    19  
    20  	"github.com/insionng/yougam/libraries/golang/protobuf/proto"
    21  	"github.com/insionng/yougam/libraries/juju/errors"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/mysql"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/codec"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    27  	"github.com/insionng/yougam/libraries/pingcap/tipb/go-tipb"
    28  )
    29  
    30  var (
    31  	tablePrefix     = []byte{'t'}
    32  	recordPrefixSep = []byte("_r")
    33  	indexPrefixSep  = []byte("_i")
    34  )
    35  
    36  const (
    37  	idLen           = 8
    38  	prefixLen       = 1 + idLen /*tableID*/ + 2
    39  	recordRowKeyLen = prefixLen + idLen /*handle*/
    40  )
    41  
    42  // EncodeRowKey encodes the table id and record handle into a kv.Key
    43  func EncodeRowKey(tableID int64, encodedHandle []byte) kv.Key {
    44  	buf := make([]byte, 0, recordRowKeyLen)
    45  	buf = appendTableRecordPrefix(buf, tableID)
    46  	buf = append(buf, encodedHandle...)
    47  	return buf
    48  }
    49  
    50  // EncodeColumnKey encodes the table id, row handle and columnID into a kv.Key
    51  func EncodeColumnKey(tableID int64, handle int64, columnID int64) kv.Key {
    52  	buf := make([]byte, 0, recordRowKeyLen+idLen)
    53  	buf = appendTableRecordPrefix(buf, tableID)
    54  	buf = codec.EncodeInt(buf, handle)
    55  	buf = codec.EncodeInt(buf, columnID)
    56  	return buf
    57  }
    58  
    59  // DecodeRowKey decodes the key and gets the handle.
    60  func DecodeRowKey(key kv.Key) (handle int64, err error) {
    61  	k := key
    62  	if !key.HasPrefix(tablePrefix) {
    63  		return 0, errors.Errorf("invalid record key - %q", k)
    64  	}
    65  
    66  	key = key[len(tablePrefix):]
    67  	// Table ID is not needed.
    68  	key, _, err = codec.DecodeInt(key)
    69  	if err != nil {
    70  		return 0, errors.Trace(err)
    71  	}
    72  
    73  	if !key.HasPrefix(recordPrefixSep) {
    74  		return 0, errors.Errorf("invalid record key - %q", k)
    75  	}
    76  
    77  	key = key[len(recordPrefixSep):]
    78  
    79  	key, handle, err = codec.DecodeInt(key)
    80  	if err != nil {
    81  		return 0, errors.Trace(err)
    82  	}
    83  	return
    84  }
    85  
    86  // DecodeValues decodes a byte slice into datums with column types.
    87  func DecodeValues(data []byte, fts []*types.FieldType, inIndex bool) ([]types.Datum, error) {
    88  	if data == nil {
    89  		return nil, nil
    90  	}
    91  	values, err := codec.Decode(data)
    92  	if err != nil {
    93  		return nil, errors.Trace(err)
    94  	}
    95  	if len(values) > len(fts) {
    96  		return nil, errors.Errorf("invalid column count %d is less than value count %d", len(fts), len(values))
    97  	}
    98  	if inIndex {
    99  		// We don't need to unflatten index columns for now.
   100  		return values, nil
   101  	}
   102  
   103  	for i := range values {
   104  		values[i], err = unflatten(values[i], fts[i])
   105  		if err != nil {
   106  			return nil, errors.Trace(err)
   107  		}
   108  	}
   109  	return values, nil
   110  }
   111  
   112  // unflatten converts a raw datum to a column datum.
   113  func unflatten(datum types.Datum, ft *types.FieldType) (types.Datum, error) {
   114  	if datum.Kind() == types.KindNull {
   115  		return datum, nil
   116  	}
   117  	switch ft.Tp {
   118  	case mysql.TypeFloat:
   119  		datum.SetFloat32(float32(datum.GetFloat64()))
   120  		return datum, nil
   121  	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24,
   122  		mysql.TypeLong, mysql.TypeLonglong, mysql.TypeDouble, mysql.TypeTinyBlob,
   123  		mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob, mysql.TypeVarchar,
   124  		mysql.TypeString:
   125  		return datum, nil
   126  	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
   127  		var t mysql.Time
   128  		t.Type = ft.Tp
   129  		t.Fsp = ft.Decimal
   130  		err := t.Unmarshal(datum.GetBytes())
   131  		if err != nil {
   132  			return datum, errors.Trace(err)
   133  		}
   134  		datum.SetMysqlTime(t)
   135  		return datum, nil
   136  	case mysql.TypeDuration:
   137  		dur := mysql.Duration{Duration: time.Duration(datum.GetInt64())}
   138  		datum.SetValue(dur)
   139  		return datum, nil
   140  	case mysql.TypeNewDecimal:
   141  		dec, err := mysql.ParseDecimal(datum.GetString())
   142  		if err != nil {
   143  			return datum, errors.Trace(err)
   144  		}
   145  		datum.SetValue(dec)
   146  		return datum, nil
   147  	case mysql.TypeEnum:
   148  		enum, err := mysql.ParseEnumValue(ft.Elems, datum.GetUint64())
   149  		if err != nil {
   150  			return datum, errors.Trace(err)
   151  		}
   152  		datum.SetValue(enum)
   153  		return datum, nil
   154  	case mysql.TypeSet:
   155  		set, err := mysql.ParseSetValue(ft.Elems, datum.GetUint64())
   156  		if err != nil {
   157  			return datum, errors.Trace(err)
   158  		}
   159  		datum.SetValue(set)
   160  		return datum, nil
   161  	case mysql.TypeBit:
   162  		bit := mysql.Bit{Value: datum.GetUint64(), Width: ft.Flen}
   163  		datum.SetValue(bit)
   164  		return datum, nil
   165  	}
   166  	return datum, nil
   167  }
   168  
   169  // EncodeIndexSeekKey encodes an index value to kv.Key.
   170  func EncodeIndexSeekKey(tableID int64, idxID int64, encodedValue []byte) kv.Key {
   171  	key := make([]byte, 0, prefixLen+len(encodedValue))
   172  	key = appendTableIndexPrefix(key, tableID)
   173  	key = codec.EncodeInt(key, idxID)
   174  	key = append(key, encodedValue...)
   175  	return key
   176  }
   177  
   178  // DecodeIndexKey decodes datums from an index key.
   179  func DecodeIndexKey(key kv.Key) ([]types.Datum, error) {
   180  	b := key[prefixLen+idLen:]
   181  	return codec.Decode(b)
   182  }
   183  
   184  // Record prefix is "t[tableID]_r".
   185  func appendTableRecordPrefix(buf []byte, tableID int64) []byte {
   186  	buf = append(buf, tablePrefix...)
   187  	buf = codec.EncodeInt(buf, tableID)
   188  	buf = append(buf, recordPrefixSep...)
   189  	return buf
   190  }
   191  
   192  // Index prefix is "t[tableID]_i".
   193  func appendTableIndexPrefix(buf []byte, tableID int64) []byte {
   194  	buf = append(buf, tablePrefix...)
   195  	buf = codec.EncodeInt(buf, tableID)
   196  	buf = append(buf, indexPrefixSep...)
   197  	return buf
   198  }
   199  
   200  func columnToProto(c *model.ColumnInfo) *tipb.ColumnInfo {
   201  	pc := &tipb.ColumnInfo{
   202  		ColumnId:  proto.Int64(c.ID),
   203  		Collation: proto.Int32(collationToProto(c.FieldType.Collate)),
   204  		ColumnLen: proto.Int32(int32(c.FieldType.Flen)),
   205  		Decimal:   proto.Int32(int32(c.FieldType.Decimal)),
   206  		Flag:      proto.Int32(int32(c.Flag)),
   207  		Elems:     c.Elems,
   208  	}
   209  	t := int32(c.FieldType.Tp)
   210  	pc.Tp = &t
   211  	return pc
   212  }
   213  
   214  func collationToProto(c string) int32 {
   215  	v, ok := mysql.CollationNames[c]
   216  	if ok {
   217  		return int32(v)
   218  	}
   219  	return int32(mysql.DefaultCollationID)
   220  }
   221  
   222  // ColumnsToProto converts a slice of model.ColumnInfo to a slice of tipb.ColumnInfo.
   223  func ColumnsToProto(columns []*model.ColumnInfo, pkIsHandle bool) []*tipb.ColumnInfo {
   224  	cols := make([]*tipb.ColumnInfo, 0, len(columns))
   225  	for _, c := range columns {
   226  		col := columnToProto(c)
   227  		if pkIsHandle && mysql.HasPriKeyFlag(c.Flag) {
   228  			col.PkHandle = proto.Bool(true)
   229  		} else {
   230  			col.PkHandle = proto.Bool(false)
   231  		}
   232  		cols = append(cols, col)
   233  	}
   234  	return cols
   235  }
   236  
   237  // ProtoColumnsToFieldTypes converts tipb column info slice to FieldTyps slice.
   238  func ProtoColumnsToFieldTypes(pColumns []*tipb.ColumnInfo) []*types.FieldType {
   239  	fields := make([]*types.FieldType, len(pColumns))
   240  	for i, v := range pColumns {
   241  		field := new(types.FieldType)
   242  		field.Tp = byte(v.GetTp())
   243  		field.Collate = mysql.Collations[byte(v.GetCollation())]
   244  		field.Decimal = int(v.GetDecimal())
   245  		field.Flen = int(v.GetColumnLen())
   246  		field.Flag = uint(v.GetFlag())
   247  		field.Elems = v.GetElems()
   248  		fields[i] = field
   249  	}
   250  	return fields
   251  }
   252  
   253  // IndexToProto converts a model.IndexInfo to a tipb.IndexInfo.
   254  func IndexToProto(t *model.TableInfo, idx *model.IndexInfo) *tipb.IndexInfo {
   255  	pi := &tipb.IndexInfo{
   256  		TableId: proto.Int64(t.ID),
   257  		IndexId: proto.Int64(idx.ID),
   258  		Unique:  proto.Bool(idx.Unique),
   259  	}
   260  	cols := make([]*tipb.ColumnInfo, 0, len(idx.Columns))
   261  	for _, c := range idx.Columns {
   262  		cols = append(cols, columnToProto(t.Columns[c.Offset]))
   263  	}
   264  	pi.Columns = cols
   265  	return pi
   266  }
   267  
   268  // EncodeTableRanges encodes table ranges into kv.KeyRanges.
   269  func EncodeTableRanges(tid int64, rans []*tipb.KeyRange) []kv.KeyRange {
   270  	keyRanges := make([]kv.KeyRange, 0, len(rans))
   271  	for _, r := range rans {
   272  		start := EncodeRowKey(tid, r.Low)
   273  		end := EncodeRowKey(tid, r.High)
   274  		nr := kv.KeyRange{
   275  			StartKey: start,
   276  			EndKey:   end,
   277  		}
   278  		keyRanges = append(keyRanges, nr)
   279  	}
   280  	return keyRanges
   281  }
   282  
   283  // EncodeIndexRanges encodes index ranges into kv.KeyRanges.
   284  func EncodeIndexRanges(tid, idxID int64, rans []*tipb.KeyRange) []kv.KeyRange {
   285  	keyRanges := make([]kv.KeyRange, 0, len(rans))
   286  	for _, r := range rans {
   287  		// Convert range to kv.KeyRange
   288  		start := EncodeIndexSeekKey(tid, idxID, r.Low)
   289  		end := EncodeIndexSeekKey(tid, idxID, r.High)
   290  		nr := kv.KeyRange{
   291  			StartKey: start,
   292  			EndKey:   end,
   293  		}
   294  		keyRanges = append(keyRanges, nr)
   295  	}
   296  	return keyRanges
   297  }
   298  
   299  // TruncateToRowKeyLen truncates the key to row key length if the key is longer than row key.
   300  func TruncateToRowKeyLen(key kv.Key) kv.Key {
   301  	if len(key) > recordRowKeyLen {
   302  		return key[:recordRowKeyLen]
   303  	}
   304  	return key
   305  }
   306  
   307  type keyRangeSorter struct {
   308  	ranges []kv.KeyRange
   309  }
   310  
   311  func (r *keyRangeSorter) Len() int {
   312  	return len(r.ranges)
   313  }
   314  
   315  func (r *keyRangeSorter) Less(i, j int) bool {
   316  	a := r.ranges[i]
   317  	b := r.ranges[j]
   318  	cmp := bytes.Compare(a.StartKey, b.StartKey)
   319  	return cmp < 0
   320  }
   321  
   322  func (r *keyRangeSorter) Swap(i, j int) {
   323  	r.ranges[i], r.ranges[j] = r.ranges[j], r.ranges[i]
   324  }