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  )