github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/rowcodec/decoder.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 rowcodec 15 16 import ( 17 "fmt" 18 "time" 19 20 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 21 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 22 "github.com/whtcorpsinc/errors" 23 "github.com/whtcorpsinc/milevadb/ekv" 24 "github.com/whtcorpsinc/milevadb/soliton/chunk" 25 "github.com/whtcorpsinc/milevadb/soliton/codec" 26 "github.com/whtcorpsinc/milevadb/types" 27 "github.com/whtcorpsinc/milevadb/types/json" 28 ) 29 30 // causetDecoder contains base soliton for decode event. 31 type causetDecoder struct { 32 event 33 defCausumns []DefCausInfo 34 handleDefCausIDs []int64 35 loc *time.Location 36 } 37 38 // NewCausetDecoder creates a causetDecoder. 39 func NewCausetDecoder(defCausumns []DefCausInfo, handleDefCausIDs []int64, loc *time.Location) *causetDecoder { 40 return &causetDecoder{ 41 defCausumns: defCausumns, 42 handleDefCausIDs: handleDefCausIDs, 43 loc: loc, 44 } 45 } 46 47 // DefCausInfo is used as defCausumn spacetime info for event causetDecoder. 48 type DefCausInfo struct { 49 ID int64 50 IsPKHandle bool 51 VirtualGenDefCaus bool 52 Ft *types.FieldType 53 } 54 55 // CausetFIDeliocoderdecodes the event to causet map. 56 type CausetFIDeliocoderstruct { 57 causetDecoder 58 } 59 60 // NewCausetFIDeliocodercreates a CausetFIDelioecoder. 61 func NewCausetFIDelioecoder(defCausumns []DefCausInfo, loc *time.Location) *CausetFIDeliocoder{ 62 return &CausetFIDelioecoder{causetDecoder{ 63 defCausumns: defCausumns, 64 loc: loc, 65 }} 66 } 67 68 // DecodeToCausetMap decodes byte slices to causet map. 69 func (causetDecoder *CausetFIDelioecoder) DecodeToCausetMap(rowData []byte, event map[int64]types.Causet) (map[int64]types.Causet, error) { 70 if event == nil { 71 event = make(map[int64]types.Causet, len(causetDecoder.defCausumns)) 72 } 73 err := causetDecoder.fromBytes(rowData) 74 if err != nil { 75 return nil, err 76 } 77 for i := range causetDecoder.defCausumns { 78 defCaus := &causetDecoder.defCausumns[i] 79 idx, isNil, notFound := causetDecoder.event.findDefCausID(defCaus.ID) 80 if !notFound && !isNil { 81 defCausData := causetDecoder.getData(idx) 82 d, err := causetDecoder.decodeDefCausCauset(defCaus, defCausData) 83 if err != nil { 84 return nil, err 85 } 86 event[defCaus.ID] = d 87 continue 88 } 89 90 if isNil { 91 var d types.Causet 92 d.SetNull() 93 event[defCaus.ID] = d 94 continue 95 } 96 } 97 return event, nil 98 } 99 100 func (causetDecoder *CausetFIDelioecoder) decodeDefCausCauset(defCaus *DefCausInfo, defCausData []byte) (types.Causet, error) { 101 var d types.Causet 102 switch defCaus.Ft.Tp { 103 case allegrosql.TypeLonglong, allegrosql.TypeLong, allegrosql.TypeInt24, allegrosql.TypeShort, allegrosql.TypeTiny: 104 if allegrosql.HasUnsignedFlag(defCaus.Ft.Flag) { 105 d.SetUint64(decodeUint(defCausData)) 106 } else { 107 d.SetInt64(decodeInt(defCausData)) 108 } 109 case allegrosql.TypeYear: 110 d.SetInt64(decodeInt(defCausData)) 111 case allegrosql.TypeFloat: 112 _, fVal, err := codec.DecodeFloat(defCausData) 113 if err != nil { 114 return d, err 115 } 116 d.SetFloat32(float32(fVal)) 117 case allegrosql.TypeDouble: 118 _, fVal, err := codec.DecodeFloat(defCausData) 119 if err != nil { 120 return d, err 121 } 122 d.SetFloat64(fVal) 123 case allegrosql.TypeVarString, allegrosql.TypeVarchar, allegrosql.TypeString: 124 d.SetString(string(defCausData), defCaus.Ft.DefCauslate) 125 case allegrosql.TypeBlob, allegrosql.TypeTinyBlob, allegrosql.TypeMediumBlob, allegrosql.TypeLongBlob: 126 d.SetBytes(defCausData) 127 case allegrosql.TypeNewDecimal: 128 _, dec, precision, frac, err := codec.DecodeDecimal(defCausData) 129 if err != nil { 130 return d, err 131 } 132 d.SetMysqlDecimal(dec) 133 d.SetLength(precision) 134 d.SetFrac(frac) 135 case allegrosql.TypeDate, allegrosql.TypeDatetime, allegrosql.TypeTimestamp: 136 var t types.Time 137 t.SetType(defCaus.Ft.Tp) 138 t.SetFsp(int8(defCaus.Ft.Decimal)) 139 err := t.FromPackedUint(decodeUint(defCausData)) 140 if err != nil { 141 return d, err 142 } 143 if defCaus.Ft.Tp == allegrosql.TypeTimestamp && !t.IsZero() { 144 err = t.ConvertTimeZone(time.UTC, causetDecoder.loc) 145 if err != nil { 146 return d, err 147 } 148 } 149 d.SetMysqlTime(t) 150 case allegrosql.TypeDuration: 151 var dur types.Duration 152 dur.Duration = time.Duration(decodeInt(defCausData)) 153 dur.Fsp = int8(defCaus.Ft.Decimal) 154 d.SetMysqlDuration(dur) 155 case allegrosql.TypeEnum: 156 // ignore error deliberately, to read empty enum value. 157 enum, err := types.ParseEnumValue(defCaus.Ft.Elems, decodeUint(defCausData)) 158 if err != nil { 159 enum = types.Enum{} 160 } 161 d.SetMysqlEnum(enum, defCaus.Ft.DefCauslate) 162 case allegrosql.TypeSet: 163 set, err := types.ParseSetValue(defCaus.Ft.Elems, decodeUint(defCausData)) 164 if err != nil { 165 return d, err 166 } 167 d.SetMysqlSet(set, defCaus.Ft.DefCauslate) 168 case allegrosql.TypeBit: 169 byteSize := (defCaus.Ft.Flen + 7) >> 3 170 d.SetMysqlBit(types.NewBinaryLiteralFromUint(decodeUint(defCausData), byteSize)) 171 case allegrosql.TypeJSON: 172 var j json.BinaryJSON 173 j.TypeCode = defCausData[0] 174 j.Value = defCausData[1:] 175 d.SetMysqlJSON(j) 176 default: 177 return d, errors.Errorf("unknown type %d", defCaus.Ft.Tp) 178 } 179 return d, nil 180 } 181 182 // ChunkCausetDecoder decodes the event to chunk.Chunk. 183 type ChunkCausetDecoder struct { 184 causetDecoder 185 defCauset func(i int, chk *chunk.Chunk) error 186 } 187 188 // NewChunkCausetDecoder creates a NewChunkCausetDecoder. 189 func NewChunkCausetDecoder(defCausumns []DefCausInfo, handleDefCausIDs []int64, defCauset func(i int, chk *chunk.Chunk) error, loc *time.Location) *ChunkCausetDecoder { 190 return &ChunkCausetDecoder{ 191 causetDecoder: causetDecoder{ 192 defCausumns: defCausumns, 193 handleDefCausIDs: handleDefCausIDs, 194 loc: loc, 195 }, 196 defCauset: defCauset, 197 } 198 } 199 200 // DecodeToChunk decodes a event to chunk. 201 func (causetDecoder *ChunkCausetDecoder) DecodeToChunk(rowData []byte, handle ekv.Handle, chk *chunk.Chunk) error { 202 err := causetDecoder.fromBytes(rowData) 203 if err != nil { 204 return err 205 } 206 207 for defCausIdx := range causetDecoder.defCausumns { 208 defCaus := &causetDecoder.defCausumns[defCausIdx] 209 // fill the virtual defCausumn value after event calculation 210 if defCaus.VirtualGenDefCaus { 211 chk.AppendNull(defCausIdx) 212 continue 213 } 214 215 idx, isNil, notFound := causetDecoder.event.findDefCausID(defCaus.ID) 216 if !notFound && !isNil { 217 defCausData := causetDecoder.getData(idx) 218 err := causetDecoder.decodeDefCausToChunk(defCausIdx, defCaus, defCausData, chk) 219 if err != nil { 220 return err 221 } 222 continue 223 } 224 225 if causetDecoder.tryAppendHandleDeferredCauset(defCausIdx, defCaus, handle, chk) { 226 continue 227 } 228 229 if isNil { 230 chk.AppendNull(defCausIdx) 231 continue 232 } 233 234 if causetDecoder.defCauset == nil { 235 chk.AppendNull(defCausIdx) 236 continue 237 } 238 239 err := causetDecoder.defCauset(defCausIdx, chk) 240 if err != nil { 241 return err 242 } 243 } 244 return nil 245 } 246 247 func (causetDecoder *ChunkCausetDecoder) tryAppendHandleDeferredCauset(defCausIdx int, defCaus *DefCausInfo, handle ekv.Handle, chk *chunk.Chunk) bool { 248 if handle == nil { 249 return false 250 } 251 if handle.IsInt() && defCaus.ID == causetDecoder.handleDefCausIDs[0] { 252 chk.AppendInt64(defCausIdx, handle.IntValue()) 253 return true 254 } 255 for i, id := range causetDecoder.handleDefCausIDs { 256 if defCaus.ID == id { 257 coder := codec.NewCausetDecoder(chk, causetDecoder.loc) 258 _, err := coder.DecodeOne(handle.EncodedDefCaus(i), defCausIdx, defCaus.Ft) 259 if err != nil { 260 return false 261 } 262 return true 263 } 264 } 265 return false 266 } 267 268 func (causetDecoder *ChunkCausetDecoder) decodeDefCausToChunk(defCausIdx int, defCaus *DefCausInfo, defCausData []byte, chk *chunk.Chunk) error { 269 switch defCaus.Ft.Tp { 270 case allegrosql.TypeLonglong, allegrosql.TypeLong, allegrosql.TypeInt24, allegrosql.TypeShort, allegrosql.TypeTiny: 271 if allegrosql.HasUnsignedFlag(defCaus.Ft.Flag) { 272 chk.AppendUint64(defCausIdx, decodeUint(defCausData)) 273 } else { 274 chk.AppendInt64(defCausIdx, decodeInt(defCausData)) 275 } 276 case allegrosql.TypeYear: 277 chk.AppendInt64(defCausIdx, decodeInt(defCausData)) 278 case allegrosql.TypeFloat: 279 _, fVal, err := codec.DecodeFloat(defCausData) 280 if err != nil { 281 return err 282 } 283 chk.AppendFloat32(defCausIdx, float32(fVal)) 284 case allegrosql.TypeDouble: 285 _, fVal, err := codec.DecodeFloat(defCausData) 286 if err != nil { 287 return err 288 } 289 chk.AppendFloat64(defCausIdx, fVal) 290 case allegrosql.TypeVarString, allegrosql.TypeVarchar, allegrosql.TypeString, 291 allegrosql.TypeBlob, allegrosql.TypeTinyBlob, allegrosql.TypeMediumBlob, allegrosql.TypeLongBlob: 292 chk.AppendBytes(defCausIdx, defCausData) 293 case allegrosql.TypeNewDecimal: 294 _, dec, _, frac, err := codec.DecodeDecimal(defCausData) 295 if err != nil { 296 return err 297 } 298 if defCaus.Ft.Decimal != types.UnspecifiedLength && frac > defCaus.Ft.Decimal { 299 to := new(types.MyDecimal) 300 err := dec.Round(to, defCaus.Ft.Decimal, types.ModeHalfEven) 301 if err != nil { 302 return errors.Trace(err) 303 } 304 dec = to 305 } 306 chk.AppendMyDecimal(defCausIdx, dec) 307 case allegrosql.TypeDate, allegrosql.TypeDatetime, allegrosql.TypeTimestamp: 308 var t types.Time 309 t.SetType(defCaus.Ft.Tp) 310 t.SetFsp(int8(defCaus.Ft.Decimal)) 311 err := t.FromPackedUint(decodeUint(defCausData)) 312 if err != nil { 313 return err 314 } 315 if defCaus.Ft.Tp == allegrosql.TypeTimestamp && causetDecoder.loc != nil && !t.IsZero() { 316 err = t.ConvertTimeZone(time.UTC, causetDecoder.loc) 317 if err != nil { 318 return err 319 } 320 } 321 chk.AppendTime(defCausIdx, t) 322 case allegrosql.TypeDuration: 323 var dur types.Duration 324 dur.Duration = time.Duration(decodeInt(defCausData)) 325 dur.Fsp = int8(defCaus.Ft.Decimal) 326 chk.AppendDuration(defCausIdx, dur) 327 case allegrosql.TypeEnum: 328 // ignore error deliberately, to read empty enum value. 329 enum, err := types.ParseEnumValue(defCaus.Ft.Elems, decodeUint(defCausData)) 330 if err != nil { 331 enum = types.Enum{} 332 } 333 chk.AppendEnum(defCausIdx, enum) 334 case allegrosql.TypeSet: 335 set, err := types.ParseSetValue(defCaus.Ft.Elems, decodeUint(defCausData)) 336 if err != nil { 337 return err 338 } 339 chk.AppendSet(defCausIdx, set) 340 case allegrosql.TypeBit: 341 byteSize := (defCaus.Ft.Flen + 7) >> 3 342 chk.AppendBytes(defCausIdx, types.NewBinaryLiteralFromUint(decodeUint(defCausData), byteSize)) 343 case allegrosql.TypeJSON: 344 var j json.BinaryJSON 345 j.TypeCode = defCausData[0] 346 j.Value = defCausData[1:] 347 chk.AppendJSON(defCausIdx, j) 348 default: 349 return errors.Errorf("unknown type %d", defCaus.Ft.Tp) 350 } 351 return nil 352 } 353 354 // BytesCausetDecoder decodes the event to old datums bytes. 355 type BytesCausetDecoder struct { 356 causetDecoder 357 defBytes func(i int) ([]byte, error) 358 } 359 360 // NewByteCausetDecoder creates a BytesCausetDecoder. 361 // defBytes: provided default value bytes in old causet format(flag+defCausData). 362 func NewByteCausetDecoder(defCausumns []DefCausInfo, handleDefCausIDs []int64, defBytes func(i int) ([]byte, error), loc *time.Location) *BytesCausetDecoder { 363 return &BytesCausetDecoder{ 364 causetDecoder: causetDecoder{ 365 defCausumns: defCausumns, 366 handleDefCausIDs: handleDefCausIDs, 367 loc: loc, 368 }, 369 defBytes: defBytes, 370 } 371 } 372 373 func (causetDecoder *BytesCausetDecoder) decodeToBytesInternal(outputOffset map[int64]int, handle ekv.Handle, value []byte, cacheBytes []byte) ([][]byte, error) { 374 var r event 375 err := r.fromBytes(value) 376 if err != nil { 377 return nil, err 378 } 379 values := make([][]byte, len(outputOffset)) 380 for i := range causetDecoder.defCausumns { 381 defCaus := &causetDecoder.defCausumns[i] 382 tp := fieldType2Flag(defCaus.Ft.Tp, defCaus.Ft.Flag&allegrosql.UnsignedFlag == 0) 383 defCausID := defCaus.ID 384 offset := outputOffset[defCausID] 385 if causetDecoder.tryDecodeHandle(values, offset, defCaus, handle, cacheBytes) { 386 continue 387 } 388 389 idx, isNil, notFound := r.findDefCausID(defCausID) 390 if !notFound && !isNil { 391 val := r.getData(idx) 392 values[offset] = causetDecoder.encodeOldCauset(tp, val) 393 continue 394 } 395 396 if isNil { 397 values[offset] = []byte{NilFlag} 398 continue 399 } 400 401 if causetDecoder.defBytes != nil { 402 defVal, err := causetDecoder.defBytes(i) 403 if err != nil { 404 return nil, err 405 } 406 if len(defVal) > 0 { 407 values[offset] = defVal 408 continue 409 } 410 } 411 412 values[offset] = []byte{NilFlag} 413 } 414 return values, nil 415 } 416 417 func (causetDecoder *BytesCausetDecoder) tryDecodeHandle(values [][]byte, offset int, defCaus *DefCausInfo, 418 handle ekv.Handle, cacheBytes []byte) bool { 419 if handle == nil { 420 return false 421 } 422 if defCaus.IsPKHandle || defCaus.ID == perceptron.ExtraHandleID { 423 handleData := cacheBytes 424 if allegrosql.HasUnsignedFlag(defCaus.Ft.Flag) { 425 handleData = append(handleData, UintFlag) 426 handleData = codec.EncodeUint(handleData, uint64(handle.IntValue())) 427 } else { 428 handleData = append(handleData, IntFlag) 429 handleData = codec.EncodeInt(handleData, handle.IntValue()) 430 } 431 values[offset] = handleData 432 return true 433 } 434 var handleData []byte 435 for i, hid := range causetDecoder.handleDefCausIDs { 436 if defCaus.ID == hid { 437 handleData = append(handleData, handle.EncodedDefCaus(i)...) 438 } 439 } 440 if len(handleData) > 0 { 441 values[offset] = handleData 442 return true 443 } 444 return false 445 } 446 447 // DecodeToBytesNoHandle decodes raw byte slice to event dat without handle. 448 func (causetDecoder *BytesCausetDecoder) DecodeToBytesNoHandle(outputOffset map[int64]int, value []byte) ([][]byte, error) { 449 return causetDecoder.decodeToBytesInternal(outputOffset, nil, value, nil) 450 } 451 452 // DecodeToBytes decodes raw byte slice to event data. 453 func (causetDecoder *BytesCausetDecoder) DecodeToBytes(outputOffset map[int64]int, handle ekv.Handle, value []byte, cacheBytes []byte) ([][]byte, error) { 454 return causetDecoder.decodeToBytesInternal(outputOffset, handle, value, cacheBytes) 455 } 456 457 func (causetDecoder *BytesCausetDecoder) encodeOldCauset(tp byte, val []byte) []byte { 458 var buf []byte 459 switch tp { 460 case BytesFlag: 461 buf = append(buf, CompactBytesFlag) 462 buf = codec.EncodeCompactBytes(buf, val) 463 case IntFlag: 464 buf = append(buf, VarintFlag) 465 buf = codec.EncodeVarint(buf, decodeInt(val)) 466 case UintFlag: 467 buf = append(buf, VaruintFlag) 468 buf = codec.EncodeUvarint(buf, decodeUint(val)) 469 default: 470 buf = append(buf, tp) 471 buf = append(buf, val...) 472 } 473 return buf 474 } 475 476 // fieldType2Flag transforms field type into ekv type flag. 477 func fieldType2Flag(tp byte, signed bool) (flag byte) { 478 switch tp { 479 case allegrosql.TypeTiny, allegrosql.TypeShort, allegrosql.TypeInt24, allegrosql.TypeLong, allegrosql.TypeLonglong: 480 if signed { 481 flag = IntFlag 482 } else { 483 flag = UintFlag 484 } 485 case allegrosql.TypeFloat, allegrosql.TypeDouble: 486 flag = FloatFlag 487 case allegrosql.TypeBlob, allegrosql.TypeTinyBlob, allegrosql.TypeMediumBlob, allegrosql.TypeLongBlob, 488 allegrosql.TypeString, allegrosql.TypeVarchar, allegrosql.TypeVarString: 489 flag = BytesFlag 490 case allegrosql.TypeDatetime, allegrosql.TypeDate, allegrosql.TypeTimestamp: 491 flag = UintFlag 492 case allegrosql.TypeDuration: 493 flag = IntFlag 494 case allegrosql.TypeNewDecimal: 495 flag = DecimalFlag 496 case allegrosql.TypeYear: 497 flag = IntFlag 498 case allegrosql.TypeEnum, allegrosql.TypeBit, allegrosql.TypeSet: 499 flag = UintFlag 500 case allegrosql.TypeJSON: 501 flag = JSONFlag 502 case allegrosql.TypeNull: 503 flag = NilFlag 504 default: 505 panic(fmt.Sprintf("unknown field type %d", tp)) 506 } 507 return 508 }