github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/rowcodec/rowcodec_test.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_test 15 16 import ( 17 "math" 18 "strings" 19 "testing" 20 "time" 21 22 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 23 . "github.com/whtcorpsinc/check" 24 "github.com/whtcorpsinc/milevadb/blockcodec" 25 "github.com/whtcorpsinc/milevadb/ekv" 26 "github.com/whtcorpsinc/milevadb/soliton/chunk" 27 "github.com/whtcorpsinc/milevadb/soliton/codec" 28 "github.com/whtcorpsinc/milevadb/soliton/defCauslate" 29 "github.com/whtcorpsinc/milevadb/soliton/rowcodec" 30 "github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx" 31 "github.com/whtcorpsinc/milevadb/types" 32 "github.com/whtcorpsinc/milevadb/types/json" 33 ) 34 35 func TestT(t *testing.T) { 36 TestingT(t) 37 } 38 39 var _ = Suite(&testSuite{}) 40 41 type testSuite struct{} 42 43 type testData struct { 44 id int64 45 ft *types.FieldType 46 dt types.Causet 47 bt types.Causet 48 def *types.Causet 49 handle bool 50 } 51 52 func (s *testSuite) TestEncodeLargeSmallReuseBug(c *C) { 53 // reuse one rowcodec.CausetEncoder. 54 var causetCausetEncoder rowcodec.CausetEncoder 55 defCausFt := types.NewFieldType(allegrosql.TypeString) 56 57 largeDefCausID := int64(300) 58 b, err := causetCausetEncoder.Encode(&stmtctx.StatementContext{}, []int64{largeDefCausID}, []types.Causet{types.NewBytesCauset([]byte(""))}, nil) 59 c.Assert(err, IsNil) 60 61 bCausetDecoder := rowcodec.NewCausetFIDelioecoder([]rowcodec.DefCausInfo{ 62 { 63 ID: largeDefCausID, 64 Ft: defCausFt, 65 IsPKHandle: false, 66 }, 67 }, nil) 68 m, err := bCausetDecoder.DecodeToCausetMap(b, nil) 69 c.Assert(err, IsNil) 70 v := m[largeDefCausID] 71 72 defCausFt = types.NewFieldType(allegrosql.TypeLonglong) 73 smallDefCausID := int64(1) 74 b, err = causetCausetEncoder.Encode(&stmtctx.StatementContext{}, []int64{smallDefCausID}, []types.Causet{types.NewIntCauset(2)}, nil) 75 c.Assert(err, IsNil) 76 77 bCausetDecoder = rowcodec.NewCausetFIDelioecoder([]rowcodec.DefCausInfo{ 78 { 79 ID: smallDefCausID, 80 Ft: defCausFt, 81 IsPKHandle: false, 82 }, 83 }, nil) 84 m, err = bCausetDecoder.DecodeToCausetMap(b, nil) 85 c.Assert(err, IsNil) 86 v = m[smallDefCausID] 87 c.Assert(v.GetInt64(), Equals, int64(2)) 88 } 89 90 func (s *testSuite) TestDecodeRowWithHandle(c *C) { 91 handleID := int64(-1) 92 handleValue := int64(10000) 93 94 encodeAndDecodeHandle := func(c *C, testData []testData) { 95 // transform test data into input. 96 defCausIDs := make([]int64, 0, len(testData)) 97 dts := make([]types.Causet, 0, len(testData)) 98 fts := make([]*types.FieldType, 0, len(testData)) 99 defcaus := make([]rowcodec.DefCausInfo, 0, len(testData)) 100 handleDefCausFtMap := make(map[int64]*types.FieldType) 101 for i := range testData { 102 t := testData[i] 103 if t.handle { 104 handleDefCausFtMap[handleID] = t.ft 105 } else { 106 defCausIDs = append(defCausIDs, t.id) 107 dts = append(dts, t.dt) 108 } 109 fts = append(fts, t.ft) 110 defcaus = append(defcaus, rowcodec.DefCausInfo{ 111 ID: t.id, 112 IsPKHandle: t.handle, 113 Ft: t.ft, 114 }) 115 } 116 117 // test encode input. 118 var causetCausetEncoder rowcodec.CausetEncoder 119 sc := new(stmtctx.StatementContext) 120 sc.TimeZone = time.UTC 121 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 122 c.Assert(err, IsNil) 123 124 // decode to causet map. 125 mCausetDecoder := rowcodec.NewCausetFIDelioecoder(defcaus, sc.TimeZone) 126 dm, err := mCausetDecoder.DecodeToCausetMap(newRow, nil) 127 c.Assert(err, IsNil) 128 dm, err = blockcodec.DecodeHandleToCausetMap(ekv.IntHandle(handleValue), 129 []int64{handleID}, handleDefCausFtMap, sc.TimeZone, dm) 130 c.Assert(err, IsNil) 131 for _, t := range testData { 132 d, exists := dm[t.id] 133 c.Assert(exists, IsTrue) 134 c.Assert(d, DeepEquals, t.dt) 135 } 136 137 // decode to chunk. 138 cCausetDecoder := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 139 chk := chunk.New(fts, 1, 1) 140 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(handleValue), chk) 141 c.Assert(err, IsNil) 142 chkRow := chk.GetRow(0) 143 cdt := chkRow.GetCausetRow(fts) 144 for i, t := range testData { 145 d := cdt[i] 146 if d.HoTT() == types.HoTTMysqlDecimal { 147 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 148 } else { 149 c.Assert(d, DeepEquals, t.bt) 150 } 151 } 152 153 // decode to old event bytes. 154 defCausOffset := make(map[int64]int) 155 for i, t := range testData { 156 defCausOffset[t.id] = i 157 } 158 bCausetDecoder := rowcodec.NewByteCausetDecoder(defcaus, []int64{-1}, nil, nil) 159 oldRow, err := bCausetDecoder.DecodeToBytes(defCausOffset, ekv.IntHandle(handleValue), newRow, nil) 160 c.Assert(err, IsNil) 161 for i, t := range testData { 162 remain, d, err := codec.DecodeOne(oldRow[i]) 163 c.Assert(err, IsNil) 164 c.Assert(len(remain), Equals, 0) 165 if d.HoTT() == types.HoTTMysqlDecimal { 166 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 167 } else { 168 c.Assert(d, DeepEquals, t.bt) 169 } 170 } 171 } 172 173 // encode & decode signed int. 174 testDataSigned := []testData{ 175 { 176 handleID, 177 types.NewFieldType(allegrosql.TypeLonglong), 178 types.NewIntCauset(handleValue), 179 types.NewIntCauset(handleValue), 180 nil, 181 true, 182 }, 183 { 184 10, 185 types.NewFieldType(allegrosql.TypeLonglong), 186 types.NewIntCauset(1), 187 types.NewIntCauset(1), 188 nil, 189 false, 190 }, 191 } 192 encodeAndDecodeHandle(c, testDataSigned) 193 194 // encode & decode unsigned int. 195 testDataUnsigned := []testData{ 196 { 197 handleID, 198 withUnsigned(types.NewFieldType(allegrosql.TypeLonglong)), 199 types.NewUintCauset(uint64(handleValue)), 200 types.NewUintCauset(uint64(handleValue)), // decode as bytes will uint if unsigned. 201 nil, 202 true, 203 }, 204 { 205 10, 206 types.NewFieldType(allegrosql.TypeLonglong), 207 types.NewIntCauset(1), 208 types.NewIntCauset(1), 209 nil, 210 false, 211 }, 212 } 213 encodeAndDecodeHandle(c, testDataUnsigned) 214 } 215 216 func (s *testSuite) TestEncodeHoTTNullCauset(c *C) { 217 var causetCausetEncoder rowcodec.CausetEncoder 218 sc := new(stmtctx.StatementContext) 219 sc.TimeZone = time.UTC 220 defCausIDs := []int64{ 221 1, 222 2, 223 } 224 var nilDt types.Causet 225 nilDt.SetNull() 226 dts := []types.Causet{nilDt, types.NewIntCauset(2)} 227 ft := types.NewFieldType(allegrosql.TypeLonglong) 228 fts := []*types.FieldType{ft, ft} 229 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 230 c.Assert(err, IsNil) 231 232 defcaus := []rowcodec.DefCausInfo{{ 233 ID: 1, 234 Ft: ft, 235 }, 236 { 237 ID: 2, 238 Ft: ft, 239 }} 240 cCausetDecoder := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 241 chk := chunk.New(fts, 1, 1) 242 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 243 c.Assert(err, IsNil) 244 chkRow := chk.GetRow(0) 245 cdt := chkRow.GetCausetRow(fts) 246 c.Assert(cdt[0].IsNull(), Equals, true) 247 c.Assert(cdt[1].GetInt64(), Equals, int64(2)) 248 } 249 250 func (s *testSuite) TestDecodeDecimalFspNotMatch(c *C) { 251 var causetCausetEncoder rowcodec.CausetEncoder 252 sc := new(stmtctx.StatementContext) 253 sc.TimeZone = time.UTC 254 defCausIDs := []int64{ 255 1, 256 } 257 dec := withFrac(4)(withLen(6)(types.NewDecimalCauset(types.NewDecFromStringForTest("11.9900")))) 258 dts := []types.Causet{dec} 259 ft := types.NewFieldType(allegrosql.TypeNewDecimal) 260 ft.Decimal = 4 261 fts := []*types.FieldType{ft} 262 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 263 c.Assert(err, IsNil) 264 265 // decode to chunk. 266 ft = types.NewFieldType(allegrosql.TypeNewDecimal) 267 ft.Decimal = 3 268 defcaus := make([]rowcodec.DefCausInfo, 0) 269 defcaus = append(defcaus, rowcodec.DefCausInfo{ 270 ID: 1, 271 Ft: ft, 272 }) 273 cCausetDecoder := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 274 chk := chunk.New(fts, 1, 1) 275 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 276 c.Assert(err, IsNil) 277 chkRow := chk.GetRow(0) 278 cdt := chkRow.GetCausetRow(fts) 279 dec = withFrac(3)(withLen(6)(types.NewDecimalCauset(types.NewDecFromStringForTest("11.990")))) 280 c.Assert(cdt[0].GetMysqlDecimal().String(), DeepEquals, dec.GetMysqlDecimal().String()) 281 } 282 283 func (s *testSuite) TestTypesNewRowCodec(c *C) { 284 getJSONCauset := func(value string) types.Causet { 285 j, err := json.ParseBinaryFromString(value) 286 c.Assert(err, IsNil) 287 var d types.Causet 288 d.SetMysqlJSON(j) 289 return d 290 } 291 getSetCauset := func(name string, value uint64) types.Causet { 292 var d types.Causet 293 d.SetMysqlSet(types.Set{Name: name, Value: value}, allegrosql.DefaultDefCauslationName) 294 return d 295 } 296 getTime := func(value string) types.Time { 297 t, err := types.ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC}, value, allegrosql.TypeTimestamp, 6) 298 c.Assert(err, IsNil) 299 return t 300 } 301 302 var causetCausetEncoder rowcodec.CausetEncoder 303 encodeAndDecode := func(c *C, testData []testData) { 304 // transform test data into input. 305 defCausIDs := make([]int64, 0, len(testData)) 306 dts := make([]types.Causet, 0, len(testData)) 307 fts := make([]*types.FieldType, 0, len(testData)) 308 defcaus := make([]rowcodec.DefCausInfo, 0, len(testData)) 309 for i := range testData { 310 t := testData[i] 311 defCausIDs = append(defCausIDs, t.id) 312 dts = append(dts, t.dt) 313 fts = append(fts, t.ft) 314 defcaus = append(defcaus, rowcodec.DefCausInfo{ 315 ID: t.id, 316 IsPKHandle: t.handle, 317 Ft: t.ft, 318 }) 319 } 320 321 // test encode input. 322 sc := new(stmtctx.StatementContext) 323 sc.TimeZone = time.UTC 324 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 325 c.Assert(err, IsNil) 326 327 // decode to causet map. 328 mCausetDecoder := rowcodec.NewCausetFIDelioecoder(defcaus, sc.TimeZone) 329 dm, err := mCausetDecoder.DecodeToCausetMap(newRow, nil) 330 c.Assert(err, IsNil) 331 for _, t := range testData { 332 d, exists := dm[t.id] 333 c.Assert(exists, IsTrue) 334 c.Assert(d, DeepEquals, t.dt) 335 } 336 337 // decode to chunk. 338 cCausetDecoder := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 339 chk := chunk.New(fts, 1, 1) 340 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 341 c.Assert(err, IsNil) 342 chkRow := chk.GetRow(0) 343 cdt := chkRow.GetCausetRow(fts) 344 for i, t := range testData { 345 d := cdt[i] 346 if d.HoTT() == types.HoTTMysqlDecimal { 347 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 348 } else { 349 c.Assert(d, DeepEquals, t.dt) 350 } 351 } 352 353 // decode to old event bytes. 354 defCausOffset := make(map[int64]int) 355 for i, t := range testData { 356 defCausOffset[t.id] = i 357 } 358 bCausetDecoder := rowcodec.NewByteCausetDecoder(defcaus, []int64{-1}, nil, nil) 359 oldRow, err := bCausetDecoder.DecodeToBytes(defCausOffset, ekv.IntHandle(-1), newRow, nil) 360 c.Assert(err, IsNil) 361 for i, t := range testData { 362 remain, d, err := codec.DecodeOne(oldRow[i]) 363 c.Assert(err, IsNil) 364 c.Assert(len(remain), Equals, 0) 365 if d.HoTT() == types.HoTTMysqlDecimal { 366 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 367 } else { 368 c.Assert(d, DeepEquals, t.bt) 369 } 370 } 371 } 372 373 testData := []testData{ 374 { 375 1, 376 types.NewFieldType(allegrosql.TypeLonglong), 377 types.NewIntCauset(1), 378 types.NewIntCauset(1), 379 nil, 380 false, 381 }, 382 { 383 22, 384 withUnsigned(types.NewFieldType(allegrosql.TypeShort)), 385 types.NewUintCauset(1), 386 types.NewUintCauset(1), 387 nil, 388 false, 389 }, 390 { 391 3, 392 types.NewFieldType(allegrosql.TypeDouble), 393 types.NewFloat64Causet(2), 394 types.NewFloat64Causet(2), 395 nil, 396 false, 397 }, 398 { 399 24, 400 types.NewFieldType(allegrosql.TypeBlob), 401 types.NewBytesCauset([]byte("abc")), 402 types.NewBytesCauset([]byte("abc")), 403 nil, 404 false, 405 }, 406 { 407 25, 408 &types.FieldType{Tp: allegrosql.TypeString, DefCauslate: allegrosql.DefaultDefCauslationName}, 409 types.NewStringCauset("ab"), 410 types.NewBytesCauset([]byte("ab")), 411 nil, 412 false, 413 }, 414 { 415 5, 416 withFsp(6)(types.NewFieldType(allegrosql.TypeTimestamp)), 417 types.NewTimeCauset(getTime("2011-11-10 11:11:11.999999")), 418 types.NewUintCauset(1840446893366133311), 419 nil, 420 false, 421 }, 422 { 423 16, 424 withFsp(0)(types.NewFieldType(allegrosql.TypeDuration)), 425 types.NewDurationCauset(getDuration("4:00:00")), 426 types.NewIntCauset(14400000000000), 427 nil, 428 false, 429 }, 430 { 431 8, 432 types.NewFieldType(allegrosql.TypeNewDecimal), 433 withFrac(4)(withLen(6)(types.NewDecimalCauset(types.NewDecFromStringForTest("11.9900")))), 434 withFrac(4)(withLen(6)(types.NewDecimalCauset(types.NewDecFromStringForTest("11.9900")))), 435 nil, 436 false, 437 }, 438 { 439 12, 440 types.NewFieldType(allegrosql.TypeYear), 441 types.NewIntCauset(1999), 442 types.NewIntCauset(1999), 443 nil, 444 false, 445 }, 446 { 447 9, 448 withEnumElems("y", "n")(types.NewFieldTypeWithDefCauslation(allegrosql.TypeEnum, allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)), 449 types.NewMysqlEnumCauset(types.Enum{Name: "n", Value: 2}), 450 types.NewUintCauset(2), 451 nil, 452 false, 453 }, 454 { 455 14, 456 types.NewFieldType(allegrosql.TypeJSON), 457 getJSONCauset(`{"a":2}`), 458 getJSONCauset(`{"a":2}`), 459 nil, 460 false, 461 }, 462 { 463 11, 464 types.NewFieldType(allegrosql.TypeNull), 465 types.NewCauset(nil), 466 types.NewCauset(nil), 467 nil, 468 false, 469 }, 470 { 471 2, 472 types.NewFieldType(allegrosql.TypeNull), 473 types.NewCauset(nil), 474 types.NewCauset(nil), 475 nil, 476 false, 477 }, 478 { 479 100, 480 types.NewFieldType(allegrosql.TypeNull), 481 types.NewCauset(nil), 482 types.NewCauset(nil), 483 nil, 484 false, 485 }, 486 { 487 116, 488 types.NewFieldType(allegrosql.TypeFloat), 489 types.NewFloat32Causet(6), 490 types.NewFloat64Causet(6), 491 nil, 492 false, 493 }, 494 { 495 117, 496 withEnumElems("n1", "n2")(types.NewFieldTypeWithDefCauslation(allegrosql.TypeSet, allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)), 497 getSetCauset("n1", 1), 498 types.NewUintCauset(1), 499 nil, 500 false, 501 }, 502 { 503 118, 504 withFlen(24)(types.NewFieldType(allegrosql.TypeBit)), // 3 bit 505 types.NewMysqlBitCauset(types.NewBinaryLiteralFromUint(3223600, 3)), 506 types.NewUintCauset(3223600), 507 nil, 508 false, 509 }, 510 { 511 119, 512 &types.FieldType{Tp: allegrosql.TypeVarString, DefCauslate: allegrosql.DefaultDefCauslationName}, 513 types.NewStringCauset(""), 514 types.NewBytesCauset([]byte("")), 515 nil, 516 false, 517 }, 518 } 519 520 // test small 521 encodeAndDecode(c, testData) 522 523 // test large defCausID 524 testData[0].id = 300 525 encodeAndDecode(c, testData) 526 testData[0].id = 1 527 528 // test large data 529 testData[3].dt = types.NewBytesCauset([]byte(strings.Repeat("a", math.MaxUint16+1))) 530 testData[3].bt = types.NewBytesCauset([]byte(strings.Repeat("a", math.MaxUint16+1))) 531 encodeAndDecode(c, testData) 532 } 533 534 func (s *testSuite) TestNilAndDefault(c *C) { 535 encodeAndDecode := func(c *C, testData []testData) { 536 // transform test data into input. 537 defCausIDs := make([]int64, 0, len(testData)) 538 dts := make([]types.Causet, 0, len(testData)) 539 defcaus := make([]rowcodec.DefCausInfo, 0, len(testData)) 540 fts := make([]*types.FieldType, 0, len(testData)) 541 for i := range testData { 542 t := testData[i] 543 if t.def == nil { 544 defCausIDs = append(defCausIDs, t.id) 545 dts = append(dts, t.dt) 546 } 547 fts = append(fts, t.ft) 548 defcaus = append(defcaus, rowcodec.DefCausInfo{ 549 ID: t.id, 550 IsPKHandle: t.handle, 551 Ft: t.ft, 552 }) 553 } 554 ddf := func(i int, chk *chunk.Chunk) error { 555 t := testData[i] 556 if t.def == nil { 557 chk.AppendNull(i) 558 return nil 559 } 560 chk.AppendCauset(i, t.def) 561 return nil 562 } 563 bdf := func(i int) ([]byte, error) { 564 t := testData[i] 565 if t.def == nil { 566 return nil, nil 567 } 568 return getOldCausetByte(*t.def), nil 569 } 570 // test encode input. 571 var causetCausetEncoder rowcodec.CausetEncoder 572 sc := new(stmtctx.StatementContext) 573 sc.TimeZone = time.UTC 574 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 575 c.Assert(err, IsNil) 576 577 // decode to causet map. 578 mCausetDecoder := rowcodec.NewCausetFIDelioecoder(defcaus, sc.TimeZone) 579 dm, err := mCausetDecoder.DecodeToCausetMap(newRow, nil) 580 c.Assert(err, IsNil) 581 for _, t := range testData { 582 d, exists := dm[t.id] 583 if t.def != nil { 584 // for causet should not fill default value. 585 c.Assert(exists, IsFalse) 586 } else { 587 c.Assert(exists, IsTrue) 588 c.Assert(d, DeepEquals, t.bt) 589 } 590 } 591 592 //decode to chunk. 593 chk := chunk.New(fts, 1, 1) 594 cCausetDecoder := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, ddf, sc.TimeZone) 595 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 596 c.Assert(err, IsNil) 597 chkRow := chk.GetRow(0) 598 cdt := chkRow.GetCausetRow(fts) 599 for i, t := range testData { 600 d := cdt[i] 601 if d.HoTT() == types.HoTTMysqlDecimal { 602 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 603 } else { 604 c.Assert(d, DeepEquals, t.bt) 605 } 606 } 607 608 chk = chunk.New(fts, 1, 1) 609 cCausetDecoder = rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 610 err = cCausetDecoder.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 611 c.Assert(err, IsNil) 612 chkRow = chk.GetRow(0) 613 cdt = chkRow.GetCausetRow(fts) 614 for i := range testData { 615 if i == 0 { 616 continue 617 } 618 d := cdt[i] 619 c.Assert(d.IsNull(), Equals, true) 620 } 621 622 // decode to old event bytes. 623 defCausOffset := make(map[int64]int) 624 for i, t := range testData { 625 defCausOffset[t.id] = i 626 } 627 bCausetDecoder := rowcodec.NewByteCausetDecoder(defcaus, []int64{-1}, bdf, sc.TimeZone) 628 oldRow, err := bCausetDecoder.DecodeToBytes(defCausOffset, ekv.IntHandle(-1), newRow, nil) 629 c.Assert(err, IsNil) 630 for i, t := range testData { 631 remain, d, err := codec.DecodeOne(oldRow[i]) 632 c.Assert(err, IsNil) 633 c.Assert(len(remain), Equals, 0) 634 if d.HoTT() == types.HoTTMysqlDecimal { 635 c.Assert(d.GetMysqlDecimal(), DeepEquals, t.bt.GetMysqlDecimal()) 636 } else { 637 c.Assert(d, DeepEquals, t.bt) 638 } 639 } 640 } 641 dtNilData := []testData{ 642 { 643 1, 644 types.NewFieldType(allegrosql.TypeLonglong), 645 types.NewIntCauset(1), 646 types.NewIntCauset(1), 647 nil, 648 false, 649 }, 650 { 651 2, 652 withUnsigned(types.NewFieldType(allegrosql.TypeLonglong)), 653 types.NewUintCauset(1), 654 types.NewUintCauset(9), 655 getCausetPoint(types.NewUintCauset(9)), 656 false, 657 }, 658 } 659 encodeAndDecode(c, dtNilData) 660 } 661 662 func (s *testSuite) TestVarintCompatibility(c *C) { 663 encodeAndDecodeByte := func(c *C, testData []testData) { 664 // transform test data into input. 665 defCausIDs := make([]int64, 0, len(testData)) 666 dts := make([]types.Causet, 0, len(testData)) 667 fts := make([]*types.FieldType, 0, len(testData)) 668 defcaus := make([]rowcodec.DefCausInfo, 0, len(testData)) 669 for i := range testData { 670 t := testData[i] 671 defCausIDs = append(defCausIDs, t.id) 672 dts = append(dts, t.dt) 673 fts = append(fts, t.ft) 674 defcaus = append(defcaus, rowcodec.DefCausInfo{ 675 ID: t.id, 676 IsPKHandle: t.handle, 677 Ft: t.ft, 678 }) 679 } 680 681 // test encode input. 682 var causetCausetEncoder rowcodec.CausetEncoder 683 sc := new(stmtctx.StatementContext) 684 sc.TimeZone = time.UTC 685 newRow, err := causetCausetEncoder.Encode(sc, defCausIDs, dts, nil) 686 c.Assert(err, IsNil) 687 causetDecoder := rowcodec.NewByteCausetDecoder(defcaus, []int64{-1}, nil, sc.TimeZone) 688 // decode to old event bytes. 689 defCausOffset := make(map[int64]int) 690 for i, t := range testData { 691 defCausOffset[t.id] = i 692 } 693 oldRow, err := causetDecoder.DecodeToBytes(defCausOffset, ekv.IntHandle(1), newRow, nil) 694 c.Assert(err, IsNil) 695 for i, t := range testData { 696 oldVarint, err := blockcodec.EncodeValue(nil, nil, t.bt) // blockcodec will encode as varint/varuint 697 c.Assert(err, IsNil) 698 c.Assert(oldVarint, DeepEquals, oldRow[i]) 699 } 700 } 701 702 testDataValue := []testData{ 703 { 704 1, 705 types.NewFieldType(allegrosql.TypeLonglong), 706 types.NewIntCauset(1), 707 types.NewIntCauset(1), 708 nil, 709 false, 710 }, 711 { 712 2, 713 withUnsigned(types.NewFieldType(allegrosql.TypeLonglong)), 714 types.NewUintCauset(1), 715 types.NewUintCauset(1), 716 nil, 717 false, 718 }, 719 } 720 encodeAndDecodeByte(c, testDataValue) 721 } 722 723 func (s *testSuite) TestCodecUtil(c *C) { 724 defCausIDs := []int64{1, 2, 3, 4} 725 tps := make([]*types.FieldType, 4) 726 for i := 0; i < 3; i++ { 727 tps[i] = types.NewFieldType(allegrosql.TypeLonglong) 728 } 729 tps[3] = types.NewFieldType(allegrosql.TypeNull) 730 sc := new(stmtctx.StatementContext) 731 oldRow, err := blockcodec.EncodeOldRow(sc, types.MakeCausets(1, 2, 3, nil), defCausIDs, nil, nil) 732 c.Check(err, IsNil) 733 var ( 734 rb rowcodec.CausetEncoder 735 newRow []byte 736 ) 737 newRow, err = rowcodec.EncodeFromOldRow(&rb, nil, oldRow, nil) 738 c.Assert(err, IsNil) 739 c.Assert(rowcodec.IsNewFormat(newRow), IsTrue) 740 c.Assert(rowcodec.IsNewFormat(oldRow), IsFalse) 741 742 // test stringer for causetDecoder. 743 var defcaus []rowcodec.DefCausInfo 744 for i, ft := range tps { 745 defcaus = append(defcaus, rowcodec.DefCausInfo{ 746 ID: defCausIDs[i], 747 IsPKHandle: false, 748 Ft: ft, 749 }) 750 } 751 d := rowcodec.NewCausetDecoder(defcaus, []int64{-1}, nil) 752 753 // test DeferredCausetIsNull 754 isNil, err := d.DeferredCausetIsNull(newRow, 4, nil) 755 c.Assert(err, IsNil) 756 c.Assert(isNil, IsTrue) 757 isNil, err = d.DeferredCausetIsNull(newRow, 1, nil) 758 c.Assert(err, IsNil) 759 c.Assert(isNil, IsFalse) 760 isNil, err = d.DeferredCausetIsNull(newRow, 5, nil) 761 c.Assert(err, IsNil) 762 c.Assert(isNil, IsTrue) 763 isNil, err = d.DeferredCausetIsNull(newRow, 5, []byte{1}) 764 c.Assert(err, IsNil) 765 c.Assert(isNil, IsFalse) 766 767 // test isRowKey 768 c.Assert(rowcodec.IsRowKey([]byte{'b', 't'}), IsFalse) 769 c.Assert(rowcodec.IsRowKey([]byte{'t', 'r'}), IsFalse) 770 } 771 772 func (s *testSuite) TestOldRowCodec(c *C) { 773 defCausIDs := []int64{1, 2, 3, 4} 774 tps := make([]*types.FieldType, 4) 775 for i := 0; i < 3; i++ { 776 tps[i] = types.NewFieldType(allegrosql.TypeLonglong) 777 } 778 tps[3] = types.NewFieldType(allegrosql.TypeNull) 779 sc := new(stmtctx.StatementContext) 780 oldRow, err := blockcodec.EncodeOldRow(sc, types.MakeCausets(1, 2, 3, nil), defCausIDs, nil, nil) 781 c.Check(err, IsNil) 782 783 var ( 784 rb rowcodec.CausetEncoder 785 newRow []byte 786 ) 787 newRow, err = rowcodec.EncodeFromOldRow(&rb, nil, oldRow, nil) 788 c.Check(err, IsNil) 789 defcaus := make([]rowcodec.DefCausInfo, len(tps)) 790 for i, tp := range tps { 791 defcaus[i] = rowcodec.DefCausInfo{ 792 ID: defCausIDs[i], 793 Ft: tp, 794 } 795 } 796 rd := rowcodec.NewChunkCausetDecoder(defcaus, []int64{-1}, nil, time.Local) 797 chk := chunk.NewChunkWithCapacity(tps, 1) 798 err = rd.DecodeToChunk(newRow, ekv.IntHandle(-1), chk) 799 c.Assert(err, IsNil) 800 event := chk.GetRow(0) 801 for i := 0; i < 3; i++ { 802 c.Assert(event.GetInt64(i), Equals, int64(i)+1) 803 } 804 } 805 806 func (s *testSuite) Test65535Bug(c *C) { 807 defCausIds := []int64{1} 808 tps := make([]*types.FieldType, 1) 809 tps[0] = types.NewFieldType(allegrosql.TypeString) 810 sc := new(stmtctx.StatementContext) 811 text65535 := strings.Repeat("a", 65535) 812 encode := rowcodec.CausetEncoder{} 813 bd, err := encode.Encode(sc, defCausIds, []types.Causet{types.NewStringCauset(text65535)}, nil) 814 c.Check(err, IsNil) 815 816 defcaus := make([]rowcodec.DefCausInfo, 1) 817 defcaus[0] = rowcodec.DefCausInfo{ 818 ID: 1, 819 Ft: tps[0], 820 } 821 dc := rowcodec.NewCausetFIDelioecoder(defcaus, nil) 822 result, err := dc.DecodeToCausetMap(bd, nil) 823 c.Check(err, IsNil) 824 rs := result[1] 825 c.Check(rs.GetString(), Equals, text65535) 826 } 827 828 var ( 829 withUnsigned = func(ft *types.FieldType) *types.FieldType { 830 ft.Flag = ft.Flag | allegrosql.UnsignedFlag 831 return ft 832 } 833 withEnumElems = func(elem ...string) func(ft *types.FieldType) *types.FieldType { 834 return func(ft *types.FieldType) *types.FieldType { 835 ft.Elems = elem 836 return ft 837 } 838 } 839 withFsp = func(fsp int) func(ft *types.FieldType) *types.FieldType { 840 return func(ft *types.FieldType) *types.FieldType { 841 ft.Decimal = fsp 842 return ft 843 } 844 } 845 withFlen = func(flen int) func(ft *types.FieldType) *types.FieldType { 846 return func(ft *types.FieldType) *types.FieldType { 847 ft.Flen = flen 848 return ft 849 } 850 } 851 getDuration = func(value string) types.Duration { 852 dur, _ := types.ParseDuration(nil, value, 0) 853 return dur 854 } 855 getOldCausetByte = func(d types.Causet) []byte { 856 b, err := blockcodec.EncodeValue(nil, nil, d) 857 if err != nil { 858 panic(err) 859 } 860 return b 861 } 862 getCausetPoint = func(d types.Causet) *types.Causet { 863 return &d 864 } 865 withFrac = func(f int) func(d types.Causet) types.Causet { 866 return func(d types.Causet) types.Causet { 867 d.SetFrac(f) 868 return d 869 } 870 } 871 withLen = func(len int) func(d types.Causet) types.Causet { 872 return func(d types.Causet) types.Causet { 873 d.SetLength(len) 874 return d 875 } 876 } 877 )