forked from pingcap/tidb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtablecodec.go
1595 lines (1482 loc) · 50.9 KB
/
tablecodec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tablecodec
import (
"bytes"
"encoding/binary"
"math"
"strings"
"time"
"unicode/utf8"
"github.com/pingcap/errors"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/structure"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/codec"
"github.com/pingcap/tidb/util/collate"
"github.com/pingcap/tidb/util/dbterror"
"github.com/pingcap/tidb/util/rowcodec"
"github.com/pingcap/tidb/util/stringutil"
)
var (
errInvalidKey = dbterror.ClassXEval.NewStd(errno.ErrInvalidKey)
errInvalidRecordKey = dbterror.ClassXEval.NewStd(errno.ErrInvalidRecordKey)
errInvalidIndexKey = dbterror.ClassXEval.NewStd(errno.ErrInvalidIndexKey)
)
var (
tablePrefix = []byte{'t'}
recordPrefixSep = []byte("_r")
indexPrefixSep = []byte("_i")
metaPrefix = []byte{'m'}
)
const (
idLen = 8
prefixLen = 1 + idLen /*tableID*/ + 2
// RecordRowKeyLen is public for calculating average row size.
RecordRowKeyLen = prefixLen + idLen /*handle*/
tablePrefixLength = 1
recordPrefixSepLength = 2
metaPrefixLength = 1
// MaxOldEncodeValueLen is the maximum len of the old encoding of index value.
MaxOldEncodeValueLen = 9
// CommonHandleFlag is the flag used to decode the common handle in an unique index value.
CommonHandleFlag byte = 127
// PartitionIDFlag is the flag used to decode the partition ID in global index value.
PartitionIDFlag byte = 126
// IndexVersionFlag is the flag used to decode the index's version info.
IndexVersionFlag byte = 125
// RestoreDataFlag is the flag that RestoreData begin with.
// See rowcodec.Encoder.Encode and rowcodec.row.toBytes
RestoreDataFlag byte = rowcodec.CodecVer
)
// TableSplitKeyLen is the length of key 't{table_id}' which is used for table split.
const TableSplitKeyLen = 1 + idLen
// TablePrefix returns table's prefix 't'.
func TablePrefix() []byte {
return tablePrefix
}
// MetaPrefix returns meta prefix 'm'.
func MetaPrefix() []byte {
return metaPrefix
}
// EncodeRowKey encodes the table id and record handle into a kv.Key
func EncodeRowKey(tableID int64, encodedHandle []byte) kv.Key {
buf := make([]byte, 0, prefixLen+len(encodedHandle))
buf = appendTableRecordPrefix(buf, tableID)
buf = append(buf, encodedHandle...)
return buf
}
// EncodeRowKeyWithHandle encodes the table id, row handle into a kv.Key
func EncodeRowKeyWithHandle(tableID int64, handle kv.Handle) kv.Key {
return EncodeRowKey(tableID, handle.Encoded())
}
// CutRowKeyPrefix cuts the row key prefix.
func CutRowKeyPrefix(key kv.Key) []byte {
return key[prefixLen:]
}
// EncodeRecordKey encodes the recordPrefix, row handle into a kv.Key.
func EncodeRecordKey(recordPrefix kv.Key, h kv.Handle) kv.Key {
buf := make([]byte, 0, len(recordPrefix)+h.Len())
buf = append(buf, recordPrefix...)
buf = append(buf, h.Encoded()...)
return buf
}
func hasTablePrefix(key kv.Key) bool {
return key[0] == tablePrefix[0]
}
func hasRecordPrefixSep(key kv.Key) bool {
return key[0] == recordPrefixSep[0] && key[1] == recordPrefixSep[1]
}
// DecodeRecordKey decodes the key and gets the tableID, handle.
func DecodeRecordKey(key kv.Key) (tableID int64, handle kv.Handle, err error) {
if len(key) <= prefixLen {
return 0, nil, errInvalidRecordKey.GenWithStack("invalid record key - %q", key)
}
k := key
if !hasTablePrefix(key) {
return 0, nil, errInvalidRecordKey.GenWithStack("invalid record key - %q", k)
}
key = key[tablePrefixLength:]
key, tableID, err = codec.DecodeInt(key)
if err != nil {
return 0, nil, errors.Trace(err)
}
if !hasRecordPrefixSep(key) {
return 0, nil, errInvalidRecordKey.GenWithStack("invalid record key - %q", k)
}
key = key[recordPrefixSepLength:]
if len(key) == 8 {
var intHandle int64
key, intHandle, err = codec.DecodeInt(key)
if err != nil {
return 0, nil, errors.Trace(err)
}
return tableID, kv.IntHandle(intHandle), nil
}
h, err := kv.NewCommonHandle(key)
if err != nil {
return 0, nil, errInvalidRecordKey.GenWithStack("invalid record key - %q %v", k, err)
}
return tableID, h, nil
}
// DecodeIndexKey decodes the key and gets the tableID, indexID, indexValues.
func DecodeIndexKey(key kv.Key) (tableID int64, indexID int64, indexValues []string, err error) {
k := key
tableID, indexID, isRecord, err := DecodeKeyHead(key)
if err != nil {
return 0, 0, nil, errors.Trace(err)
}
if isRecord {
err = errInvalidIndexKey.GenWithStack("invalid index key - %q", k)
return 0, 0, nil, err
}
indexKey := key[prefixLen+idLen:]
indexValues, err = DecodeValuesBytesToStrings(indexKey)
if err != nil {
err = errInvalidIndexKey.GenWithStack("invalid index key - %q %v", k, err)
return 0, 0, nil, err
}
return tableID, indexID, indexValues, nil
}
// DecodeValuesBytesToStrings decode the raw bytes to strings for each columns.
// FIXME: Without the schema information, we can only decode the raw kind of
// the column. For instance, MysqlTime is internally saved as uint64.
func DecodeValuesBytesToStrings(b []byte) ([]string, error) {
var datumValues []string
for len(b) > 0 {
remain, d, e := codec.DecodeOne(b)
if e != nil {
return nil, e
}
str, e1 := d.ToString()
if e1 != nil {
return nil, e
}
datumValues = append(datumValues, str)
b = remain
}
return datumValues, nil
}
// EncodeMetaKey encodes the key and field into meta key.
func EncodeMetaKey(key []byte, field []byte) kv.Key {
ek := make([]byte, 0, len(metaPrefix)+codec.EncodedBytesLength(len(key))+8+codec.EncodedBytesLength(len(field)))
ek = append(ek, metaPrefix...)
ek = codec.EncodeBytes(ek, key)
ek = codec.EncodeUint(ek, uint64(structure.HashData))
ek = codec.EncodeBytes(ek, field)
return ek
}
// DecodeMetaKey decodes the key and get the meta key and meta field.
func DecodeMetaKey(ek kv.Key) (key []byte, field []byte, err error) {
var tp uint64
if !bytes.HasPrefix(ek, metaPrefix) {
return nil, nil, errors.New("invalid encoded hash data key prefix")
}
ek = ek[metaPrefixLength:]
ek, key, err = codec.DecodeBytes(ek, nil)
if err != nil {
return nil, nil, errors.Trace(err)
}
ek, tp, err = codec.DecodeUint(ek)
if err != nil {
return nil, nil, errors.Trace(err)
} else if structure.TypeFlag(tp) != structure.HashData {
return nil, nil, errors.Errorf("invalid encoded hash data key flag %c", byte(tp))
}
_, field, err = codec.DecodeBytes(ek, nil)
return key, field, errors.Trace(err)
}
// DecodeKeyHead decodes the key's head and gets the tableID, indexID. isRecordKey is true when is a record key.
func DecodeKeyHead(key kv.Key) (tableID int64, indexID int64, isRecordKey bool, err error) {
isRecordKey = false
k := key
if !key.HasPrefix(tablePrefix) {
err = errInvalidKey.GenWithStack("invalid key - %q", k)
return
}
key = key[len(tablePrefix):]
key, tableID, err = codec.DecodeInt(key)
if err != nil {
err = errors.Trace(err)
return
}
if key.HasPrefix(recordPrefixSep) {
isRecordKey = true
return
}
if !key.HasPrefix(indexPrefixSep) {
err = errInvalidKey.GenWithStack("invalid key - %q", k)
return
}
key = key[len(indexPrefixSep):]
key, indexID, err = codec.DecodeInt(key)
if err != nil {
err = errors.Trace(err)
return
}
return
}
// DecodeTableID decodes the table ID of the key, if the key is not table key, returns 0.
func DecodeTableID(key kv.Key) int64 {
if !key.HasPrefix(tablePrefix) {
return 0
}
key = key[len(tablePrefix):]
_, tableID, err := codec.DecodeInt(key)
// TODO: return error.
terror.Log(errors.Trace(err))
return tableID
}
// DecodeRowKey decodes the key and gets the handle.
func DecodeRowKey(key kv.Key) (kv.Handle, error) {
if len(key) < RecordRowKeyLen || !hasTablePrefix(key) || !hasRecordPrefixSep(key[prefixLen-2:]) {
return kv.IntHandle(0), errInvalidKey.GenWithStack("invalid key - %q", key)
}
if len(key) == RecordRowKeyLen {
u := binary.BigEndian.Uint64(key[prefixLen:])
return kv.IntHandle(codec.DecodeCmpUintToInt(u)), nil
}
return kv.NewCommonHandle(key[prefixLen:])
}
// EncodeValue encodes a go value to bytes.
func EncodeValue(sc *stmtctx.StatementContext, b []byte, raw types.Datum) ([]byte, error) {
var v types.Datum
err := flatten(sc, raw, &v)
if err != nil {
return nil, err
}
return codec.EncodeValue(sc, b, v)
}
// EncodeRow encode row data and column ids into a slice of byte.
// valBuf and values pass by caller, for reducing EncodeRow allocates temporary bufs. If you pass valBuf and values as nil,
// EncodeRow will allocate it.
func EncodeRow(sc *stmtctx.StatementContext, row []types.Datum, colIDs []int64, valBuf []byte, values []types.Datum, e *rowcodec.Encoder) ([]byte, error) {
if len(row) != len(colIDs) {
return nil, errors.Errorf("EncodeRow error: data and columnID count not match %d vs %d", len(row), len(colIDs))
}
if e.Enable {
return e.Encode(sc, colIDs, row, valBuf)
}
return EncodeOldRow(sc, row, colIDs, valBuf, values)
}
// EncodeOldRow encode row data and column ids into a slice of byte.
// Row layout: colID1, value1, colID2, value2, .....
// valBuf and values pass by caller, for reducing EncodeOldRow allocates temporary bufs. If you pass valBuf and values as nil,
// EncodeOldRow will allocate it.
func EncodeOldRow(sc *stmtctx.StatementContext, row []types.Datum, colIDs []int64, valBuf []byte, values []types.Datum) ([]byte, error) {
if len(row) != len(colIDs) {
return nil, errors.Errorf("EncodeRow error: data and columnID count not match %d vs %d", len(row), len(colIDs))
}
valBuf = valBuf[:0]
if values == nil {
values = make([]types.Datum, len(row)*2)
}
for i, c := range row {
id := colIDs[i]
values[2*i].SetInt64(id)
err := flatten(sc, c, &values[2*i+1])
if err != nil {
return valBuf, errors.Trace(err)
}
}
if len(values) == 0 {
// We could not set nil value into kv.
return append(valBuf, codec.NilFlag), nil
}
return codec.EncodeValue(sc, valBuf, values...)
}
func flatten(sc *stmtctx.StatementContext, data types.Datum, ret *types.Datum) error {
switch data.Kind() {
case types.KindMysqlTime:
// for mysql datetime, timestamp and date type
t := data.GetMysqlTime()
if t.Type() == mysql.TypeTimestamp && sc.TimeZone != time.UTC {
err := t.ConvertTimeZone(sc.TimeZone, time.UTC)
if err != nil {
return errors.Trace(err)
}
}
v, err := t.ToPackedUint()
ret.SetUint64(v)
return errors.Trace(err)
case types.KindMysqlDuration:
// for mysql time type
ret.SetInt64(int64(data.GetMysqlDuration().Duration))
return nil
case types.KindMysqlEnum:
ret.SetUint64(data.GetMysqlEnum().Value)
return nil
case types.KindMysqlSet:
ret.SetUint64(data.GetMysqlSet().Value)
return nil
case types.KindBinaryLiteral, types.KindMysqlBit:
// We don't need to handle errors here since the literal is ensured to be able to store in uint64 in convertToMysqlBit.
val, err := data.GetBinaryLiteral().ToInt(sc)
if err != nil {
return errors.Trace(err)
}
ret.SetUint64(val)
return nil
default:
*ret = data
return nil
}
}
// DecodeColumnValue decodes data to a Datum according to the column info.
func DecodeColumnValue(data []byte, ft *types.FieldType, loc *time.Location) (types.Datum, error) {
_, d, err := codec.DecodeOne(data)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
colDatum, err := Unflatten(d, ft, loc)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return colDatum, nil
}
// DecodeColumnValueWithDatum decodes data to an existing Datum according to the column info.
func DecodeColumnValueWithDatum(data []byte, ft *types.FieldType, loc *time.Location, result *types.Datum) error {
var err error
_, *result, err = codec.DecodeOne(data)
if err != nil {
return errors.Trace(err)
}
*result, err = Unflatten(*result, ft, loc)
if err != nil {
return errors.Trace(err)
}
return nil
}
// DecodeRowWithMapNew decode a row to datum map.
func DecodeRowWithMapNew(b []byte, cols map[int64]*types.FieldType,
loc *time.Location, row map[int64]types.Datum) (map[int64]types.Datum, error) {
if row == nil {
row = make(map[int64]types.Datum, len(cols))
}
if b == nil {
return row, nil
}
if len(b) == 1 && b[0] == codec.NilFlag {
return row, nil
}
reqCols := make([]rowcodec.ColInfo, len(cols))
var idx int
for id, tp := range cols {
reqCols[idx] = rowcodec.ColInfo{
ID: id,
Ft: tp,
}
idx++
}
rd := rowcodec.NewDatumMapDecoder(reqCols, loc)
return rd.DecodeToDatumMap(b, row)
}
// DecodeRowWithMap decodes a byte slice into datums with an existing row map.
// Row layout: colID1, value1, colID2, value2, .....
func DecodeRowWithMap(b []byte, cols map[int64]*types.FieldType, loc *time.Location, row map[int64]types.Datum) (map[int64]types.Datum, error) {
if row == nil {
row = make(map[int64]types.Datum, len(cols))
}
if b == nil {
return row, nil
}
if len(b) == 1 && b[0] == codec.NilFlag {
return row, nil
}
cnt := 0
var (
data []byte
err error
)
for len(b) > 0 {
// Get col id.
data, b, err = codec.CutOne(b)
if err != nil {
return nil, errors.Trace(err)
}
_, cid, err := codec.DecodeOne(data)
if err != nil {
return nil, errors.Trace(err)
}
// Get col value.
data, b, err = codec.CutOne(b)
if err != nil {
return nil, errors.Trace(err)
}
id := cid.GetInt64()
ft, ok := cols[id]
if ok {
_, v, err := codec.DecodeOne(data)
if err != nil {
return nil, errors.Trace(err)
}
v, err = Unflatten(v, ft, loc)
if err != nil {
return nil, errors.Trace(err)
}
row[id] = v
cnt++
if cnt == len(cols) {
// Get enough data.
break
}
}
}
return row, nil
}
// DecodeRowToDatumMap decodes a byte slice into datums.
// Row layout: colID1, value1, colID2, value2, .....
// Default value columns, generated columns and handle columns are unprocessed.
func DecodeRowToDatumMap(b []byte, cols map[int64]*types.FieldType, loc *time.Location) (map[int64]types.Datum, error) {
if !rowcodec.IsNewFormat(b) {
return DecodeRowWithMap(b, cols, loc, nil)
}
return DecodeRowWithMapNew(b, cols, loc, nil)
}
// DecodeHandleToDatumMap decodes a handle into datum map.
func DecodeHandleToDatumMap(handle kv.Handle, handleColIDs []int64,
cols map[int64]*types.FieldType, loc *time.Location, row map[int64]types.Datum) (map[int64]types.Datum, error) {
if handle == nil || len(handleColIDs) == 0 {
return row, nil
}
if row == nil {
row = make(map[int64]types.Datum, len(cols))
}
for id, ft := range cols {
for idx, hid := range handleColIDs {
if id != hid {
continue
}
if types.NeedRestoredData(ft) {
continue
}
d, err := decodeHandleToDatum(handle, ft, idx)
if err != nil {
return row, err
}
d, err = Unflatten(d, ft, loc)
if err != nil {
return row, err
}
if _, exists := row[id]; !exists {
row[id] = d
}
break
}
}
return row, nil
}
// decodeHandleToDatum decodes a handle to a specific column datum.
func decodeHandleToDatum(handle kv.Handle, ft *types.FieldType, idx int) (types.Datum, error) {
var d types.Datum
var err error
if handle.IsInt() {
if mysql.HasUnsignedFlag(ft.GetFlag()) {
d = types.NewUintDatum(uint64(handle.IntValue()))
} else {
d = types.NewIntDatum(handle.IntValue())
}
return d, nil
}
// Decode common handle to Datum.
_, d, err = codec.DecodeOne(handle.EncodedCol(idx))
return d, err
}
// CutRowNew cuts encoded row into byte slices and return columns' byte slice.
// Row layout: colID1, value1, colID2, value2, .....
func CutRowNew(data []byte, colIDs map[int64]int) ([][]byte, error) {
if data == nil {
return nil, nil
}
if len(data) == 1 && data[0] == codec.NilFlag {
return nil, nil
}
var (
cnt int
b []byte
err error
cid int64
)
row := make([][]byte, len(colIDs))
for len(data) > 0 && cnt < len(colIDs) {
// Get col id.
data, cid, err = codec.CutColumnID(data)
if err != nil {
return nil, errors.Trace(err)
}
// Get col value.
b, data, err = codec.CutOne(data)
if err != nil {
return nil, errors.Trace(err)
}
offset, ok := colIDs[cid]
if ok {
row[offset] = b
cnt++
}
}
return row, nil
}
// UnflattenDatums converts raw datums to column datums.
func UnflattenDatums(datums []types.Datum, fts []*types.FieldType, loc *time.Location) ([]types.Datum, error) {
for i, datum := range datums {
ft := fts[i]
uDatum, err := Unflatten(datum, ft, loc)
if err != nil {
return datums, errors.Trace(err)
}
datums[i] = uDatum
}
return datums, nil
}
// Unflatten converts a raw datum to a column datum.
func Unflatten(datum types.Datum, ft *types.FieldType, loc *time.Location) (types.Datum, error) {
if datum.IsNull() {
return datum, nil
}
switch ft.GetType() {
case mysql.TypeFloat:
datum.SetFloat32(float32(datum.GetFloat64()))
return datum, nil
case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString, mysql.TypeTinyBlob,
mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob:
datum.SetString(datum.GetString(), ft.GetCollate())
case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24,
mysql.TypeLong, mysql.TypeLonglong, mysql.TypeDouble:
return datum, nil
case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
t := types.NewTime(types.ZeroCoreTime, ft.GetType(), ft.GetDecimal())
var err error
err = t.FromPackedUint(datum.GetUint64())
if err != nil {
return datum, errors.Trace(err)
}
if ft.GetType() == mysql.TypeTimestamp && !t.IsZero() {
err = t.ConvertTimeZone(time.UTC, loc)
if err != nil {
return datum, errors.Trace(err)
}
}
datum.SetUint64(0)
datum.SetMysqlTime(t)
return datum, nil
case mysql.TypeDuration: // duration should read fsp from column meta data
dur := types.Duration{Duration: time.Duration(datum.GetInt64()), Fsp: ft.GetDecimal()}
datum.SetMysqlDuration(dur)
return datum, nil
case mysql.TypeEnum:
// ignore error deliberately, to read empty enum value.
enum, err := types.ParseEnumValue(ft.GetElems(), datum.GetUint64())
if err != nil {
enum = types.Enum{}
}
datum.SetMysqlEnum(enum, ft.GetCollate())
return datum, nil
case mysql.TypeSet:
set, err := types.ParseSetValue(ft.GetElems(), datum.GetUint64())
if err != nil {
return datum, errors.Trace(err)
}
datum.SetMysqlSet(set, ft.GetCollate())
return datum, nil
case mysql.TypeBit:
val := datum.GetUint64()
byteSize := (ft.GetFlen() + 7) >> 3
datum.SetUint64(0)
datum.SetMysqlBit(types.NewBinaryLiteralFromUint(val, byteSize))
}
return datum, nil
}
// EncodeIndexSeekKey encodes an index value to kv.Key.
func EncodeIndexSeekKey(tableID int64, idxID int64, encodedValue []byte) kv.Key {
key := make([]byte, 0, RecordRowKeyLen+len(encodedValue))
key = appendTableIndexPrefix(key, tableID)
key = codec.EncodeInt(key, idxID)
key = append(key, encodedValue...)
return key
}
// CutIndexKey cuts encoded index key into colIDs to bytes slices map.
// The returned value b is the remaining bytes of the key which would be empty if it is unique index or handle data
// if it is non-unique index.
func CutIndexKey(key kv.Key, colIDs []int64) (values map[int64][]byte, b []byte, err error) {
b = key[prefixLen+idLen:]
values = make(map[int64][]byte, len(colIDs))
for _, id := range colIDs {
var val []byte
val, b, err = codec.CutOne(b)
if err != nil {
return nil, nil, errors.Trace(err)
}
values[id] = val
}
return
}
// CutIndexPrefix cuts the index prefix.
func CutIndexPrefix(key kv.Key) []byte {
return key[prefixLen+idLen:]
}
// CutIndexKeyNew cuts encoded index key into colIDs to bytes slices.
// The returned value b is the remaining bytes of the key which would be empty if it is unique index or handle data
// if it is non-unique index.
func CutIndexKeyNew(key kv.Key, length int) (values [][]byte, b []byte, err error) {
b = key[prefixLen+idLen:]
values = make([][]byte, 0, length)
for i := 0; i < length; i++ {
var val []byte
val, b, err = codec.CutOne(b)
if err != nil {
return nil, nil, errors.Trace(err)
}
values = append(values, val)
}
return
}
// CutCommonHandle cuts encoded common handle key into colIDs to bytes slices.
// The returned value b is the remaining bytes of the key which would be empty if it is unique index or handle data
// if it is non-unique index.
func CutCommonHandle(key kv.Key, length int) (values [][]byte, b []byte, err error) {
b = key[prefixLen:]
values = make([][]byte, 0, length)
for i := 0; i < length; i++ {
var val []byte
val, b, err = codec.CutOne(b)
if err != nil {
return nil, nil, errors.Trace(err)
}
values = append(values, val)
}
return
}
// HandleStatus is the handle status in index.
type HandleStatus int
const (
// HandleDefault means decode handle value as int64 or bytes when DecodeIndexKV.
HandleDefault HandleStatus = iota
// HandleIsUnsigned means decode handle value as uint64 when DecodeIndexKV.
HandleIsUnsigned
// HandleNotNeeded means no need to decode handle value when DecodeIndexKV.
HandleNotNeeded
)
// reEncodeHandle encodes the handle as a Datum so it can be properly decoded later.
// If it is common handle, it returns the encoded column values.
// If it is int handle, it is encoded as int Datum or uint Datum decided by the unsigned.
func reEncodeHandle(handle kv.Handle, unsigned bool) ([][]byte, error) {
if !handle.IsInt() {
handleColLen := handle.NumCols()
cHandleBytes := make([][]byte, 0, handleColLen)
for i := 0; i < handleColLen; i++ {
cHandleBytes = append(cHandleBytes, handle.EncodedCol(i))
}
return cHandleBytes, nil
}
handleDatum := types.NewIntDatum(handle.IntValue())
if unsigned {
handleDatum.SetUint64(handleDatum.GetUint64())
}
intHandleBytes, err := codec.EncodeValue(nil, nil, handleDatum)
return [][]byte{intHandleBytes}, err
}
// reEncodeHandleConsiderNewCollation encodes the handle as a Datum so it can be properly decoded later.
func reEncodeHandleConsiderNewCollation(handle kv.Handle, columns []rowcodec.ColInfo, restoreData []byte) ([][]byte, error) {
handleColLen := handle.NumCols()
cHandleBytes := make([][]byte, 0, handleColLen)
for i := 0; i < handleColLen; i++ {
cHandleBytes = append(cHandleBytes, handle.EncodedCol(i))
}
if len(restoreData) == 0 {
return cHandleBytes, nil
}
return decodeRestoredValuesV5(columns, cHandleBytes, restoreData)
}
func decodeRestoredValues(columns []rowcodec.ColInfo, restoredVal []byte) ([][]byte, error) {
colIDs := make(map[int64]int, len(columns))
for i, col := range columns {
colIDs[col.ID] = i
}
// We don't need to decode handle here, and colIDs >= 0 always.
rd := rowcodec.NewByteDecoder(columns, []int64{-1}, nil, nil)
resultValues, err := rd.DecodeToBytesNoHandle(colIDs, restoredVal)
if err != nil {
return nil, errors.Trace(err)
}
return resultValues, nil
}
// decodeRestoredValuesV5 decodes index values whose format is introduced in TiDB 5.0.
// Unlike the format in TiDB 4.0, the new format is optimized for storage space:
// 1. If the index is a composed index, only the non-binary string column's value need to write to value, not all.
// 2. If a string column's collation is _bin, then we only write the number of the truncated spaces to value.
// 3. If a string column is char, not varchar, then we use the sortKey directly.
func decodeRestoredValuesV5(columns []rowcodec.ColInfo, results [][]byte, restoredVal []byte) ([][]byte, error) {
colIDOffsets := buildColumnIDOffsets(columns)
colInfosNeedRestore := buildRestoredColumn(columns)
rd := rowcodec.NewByteDecoder(colInfosNeedRestore, nil, nil, nil)
newResults, err := rd.DecodeToBytesNoHandle(colIDOffsets, restoredVal)
if err != nil {
return nil, errors.Trace(err)
}
for i := range newResults {
noRestoreData := len(newResults[i]) == 0
if noRestoreData {
newResults[i] = results[i]
continue
}
if collate.IsBinCollation(columns[i].Ft.GetCollate()) {
noPaddingDatum, err := DecodeColumnValue(results[i], columns[i].Ft, nil)
if err != nil {
return nil, errors.Trace(err)
}
paddingCountDatum, err := DecodeColumnValue(newResults[i], types.NewFieldType(mysql.TypeLonglong), nil)
if err != nil {
return nil, errors.Trace(err)
}
noPaddingStr, paddingCount := noPaddingDatum.GetString(), int(paddingCountDatum.GetInt64())
// Skip if padding count is 0.
if paddingCount == 0 {
newResults[i] = results[i]
continue
}
newDatum := &noPaddingDatum
newDatum.SetString(noPaddingStr+strings.Repeat(" ", paddingCount), newDatum.Collation())
newResults[i] = newResults[i][:0]
newResults[i] = append(newResults[i], rowcodec.BytesFlag)
newResults[i] = codec.EncodeBytes(newResults[i], newDatum.GetBytes())
}
}
return newResults, nil
}
func buildColumnIDOffsets(allCols []rowcodec.ColInfo) map[int64]int {
colIDOffsets := make(map[int64]int, len(allCols))
for i, col := range allCols {
colIDOffsets[col.ID] = i
}
return colIDOffsets
}
func buildRestoredColumn(allCols []rowcodec.ColInfo) []rowcodec.ColInfo {
restoredColumns := make([]rowcodec.ColInfo, 0, len(allCols))
for i, col := range allCols {
if !types.NeedRestoredData(col.Ft) {
continue
}
copyColInfo := rowcodec.ColInfo{
ID: col.ID,
}
if collate.IsBinCollation(col.Ft.GetCollate()) {
// Change the fieldType from string to uint since we store the number of the truncated spaces.
copyColInfo.Ft = types.NewFieldType(mysql.TypeLonglong)
} else {
copyColInfo.Ft = allCols[i].Ft
}
restoredColumns = append(restoredColumns, copyColInfo)
}
return restoredColumns
}
func decodeIndexKvOldCollation(key, value []byte, colsLen int, hdStatus HandleStatus) ([][]byte, error) {
resultValues, b, err := CutIndexKeyNew(key, colsLen)
if err != nil {
return nil, errors.Trace(err)
}
if hdStatus == HandleNotNeeded {
return resultValues, nil
}
var handle kv.Handle
if len(b) > 0 {
// non-unique index
handle, err = decodeHandleInIndexKey(b)
if err != nil {
return nil, err
}
handleBytes, err := reEncodeHandle(handle, hdStatus == HandleIsUnsigned)
if err != nil {
return nil, errors.Trace(err)
}
resultValues = append(resultValues, handleBytes...)
} else {
// In unique int handle index.
handle = decodeIntHandleInIndexValue(value)
handleBytes, err := reEncodeHandle(handle, hdStatus == HandleIsUnsigned)
if err != nil {
return nil, errors.Trace(err)
}
resultValues = append(resultValues, handleBytes...)
}
return resultValues, nil
}
func getIndexVersion(value []byte) int {
if len(value) <= MaxOldEncodeValueLen {
return 0
}
tailLen := int(value[0])
if (tailLen == 0 || tailLen == 1) && value[1] == IndexVersionFlag {
return int(value[2])
}
return 0
}
// DecodeIndexKV uses to decode index key values.
// `colsLen` is expected to be index columns count.
// `columns` is expected to be index columns + handle columns(if hdStatus is not HandleNotNeeded).
func DecodeIndexKV(key, value []byte, colsLen int, hdStatus HandleStatus, columns []rowcodec.ColInfo) ([][]byte, error) {
if len(value) <= MaxOldEncodeValueLen {
return decodeIndexKvOldCollation(key, value, colsLen, hdStatus)
}
if getIndexVersion(value) == 1 {
return decodeIndexKvForClusteredIndexVersion1(key, value, colsLen, hdStatus, columns)
}
return decodeIndexKvGeneral(key, value, colsLen, hdStatus, columns)
}
// DecodeIndexHandle uses to decode the handle from index key/value.
func DecodeIndexHandle(key, value []byte, colsLen int) (kv.Handle, error) {
_, b, err := CutIndexKeyNew(key, colsLen)
if err != nil {
return nil, errors.Trace(err)
}
if len(b) > 0 {
return decodeHandleInIndexKey(b)
} else if len(value) >= 8 {
return decodeHandleInIndexValue(value)
}
// Should never execute to here.
return nil, errors.Errorf("no handle in index key: %v, value: %v", key, value)
}
func decodeHandleInIndexKey(keySuffix []byte) (kv.Handle, error) {
remain, d, err := codec.DecodeOne(keySuffix)
if err != nil {
return nil, errors.Trace(err)
}
if len(remain) == 0 && d.Kind() == types.KindInt64 {
return kv.IntHandle(d.GetInt64()), nil
}
return kv.NewCommonHandle(keySuffix)
}
func decodeHandleInIndexValue(value []byte) (kv.Handle, error) {
if getIndexVersion(value) == 1 {
seg := SplitIndexValueForClusteredIndexVersion1(value)
return kv.NewCommonHandle(seg.CommonHandle)
}
if len(value) > MaxOldEncodeValueLen {
tailLen := value[0]
if tailLen >= 8 {
return decodeIntHandleInIndexValue(value[len(value)-int(tailLen):]), nil
}
handleLen := uint16(value[2])<<8 + uint16(value[3])
return kv.NewCommonHandle(value[4 : 4+handleLen])
}
return decodeIntHandleInIndexValue(value), nil
}
// decodeIntHandleInIndexValue uses to decode index value as int handle id.
func decodeIntHandleInIndexValue(data []byte) kv.Handle {
return kv.IntHandle(binary.BigEndian.Uint64(data))
}
// EncodeTableIndexPrefix encodes index prefix with tableID and idxID.
func EncodeTableIndexPrefix(tableID, idxID int64) kv.Key {
key := make([]byte, 0, prefixLen)
key = appendTableIndexPrefix(key, tableID)
key = codec.EncodeInt(key, idxID)
return key
}
// EncodeTablePrefix encodes the table prefix to generate a key
func EncodeTablePrefix(tableID int64) kv.Key {
key := make([]byte, 0, tablePrefixLength+idLen)
key = append(key, tablePrefix...)
key = codec.EncodeInt(key, tableID)
return key
}
// EncodeTablePrefixSeekKey encodes the table prefix and encodecValue into a kv.Key.
// It used for seek justly.
func EncodeTablePrefixSeekKey(tableID int64, encodecValue []byte) kv.Key {
key := make([]byte, 0, tablePrefixLength+idLen+len(encodecValue))
key = appendTablePrefix(key, tableID)
key = append(key, encodecValue...)
return key
}
// appendTablePrefix appends table prefix "t[tableID]" into buf.
func appendTablePrefix(buf []byte, tableID int64) []byte {
buf = append(buf, tablePrefix...)
buf = codec.EncodeInt(buf, tableID)
return buf
}
// appendTableRecordPrefix appends table record prefix "t[tableID]_r".
func appendTableRecordPrefix(buf []byte, tableID int64) []byte {
buf = append(buf, tablePrefix...)
buf = codec.EncodeInt(buf, tableID)
buf = append(buf, recordPrefixSep...)
return buf
}
// appendTableIndexPrefix appends table index prefix "t[tableID]_i".
func appendTableIndexPrefix(buf []byte, tableID int64) []byte {
buf = append(buf, tablePrefix...)