github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/server/util_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 server
    15  
    16  import (
    17  	"time"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    20  	. "github.com/whtcorpsinc/check"
    21  	"github.com/whtcorpsinc/errors"
    22  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    23  	"github.com/whtcorpsinc/milevadb/config"
    24  	"github.com/whtcorpsinc/milevadb/ekv"
    25  	"github.com/whtcorpsinc/milevadb/petri"
    26  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    27  	"github.com/whtcorpsinc/milevadb/soliton/mock"
    28  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    29  	"github.com/whtcorpsinc/milevadb/stochastik"
    30  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    31  	"github.com/whtcorpsinc/milevadb/types"
    32  	"github.com/whtcorpsinc/milevadb/types/json"
    33  )
    34  
    35  var _ = Suite(&testUtilSuite{})
    36  
    37  func newStoreWithBootstrap() (ekv.CausetStorage, *petri.Petri, error) {
    38  	causetstore, err := mockstore.NewMockStore()
    39  	if err != nil {
    40  		return nil, nil, errors.Trace(err)
    41  	}
    42  	stochastik.SetSchemaLease(0)
    43  	dom, err := stochastik.BootstrapStochastik(causetstore)
    44  	return causetstore, dom, errors.Trace(err)
    45  }
    46  
    47  type testUtilSuite struct {
    48  	causetstore ekv.CausetStorage
    49  	dom         *petri.Petri
    50  }
    51  
    52  func (s *testUtilSuite) SetUpSuite(c *C) {
    53  	testleak.BeforeTest()
    54  
    55  	var err error
    56  	s.causetstore, s.dom, err = newStoreWithBootstrap()
    57  	c.Assert(err, IsNil)
    58  }
    59  
    60  func (s *testUtilSuite) TearDownSuite(c *C) {
    61  	s.dom.Close()
    62  	s.causetstore.Close()
    63  
    64  	testleak.AfterTest(c)()
    65  }
    66  
    67  func (s *testUtilSuite) TestDumpBinaryTime(c *C) {
    68  	t, err := types.ParseTimestamp(nil, "0000-00-00 00:00:00.000000")
    69  	c.Assert(err, IsNil)
    70  	d := dumpBinaryDateTime(nil, t)
    71  	c.Assert(d, DeepEquals, []byte{0})
    72  
    73  	t, err = types.ParseTimestamp(&stmtctx.StatementContext{TimeZone: time.Local}, "1991-05-01 01:01:01.100001")
    74  	c.Assert(err, IsNil)
    75  	d = dumpBinaryDateTime(nil, t)
    76  	// 199 & 7 composed to uint16 1991 (litter-endian)
    77  	// 160 & 134 & 1 & 0 composed to uint32 1000001 (litter-endian)
    78  	c.Assert(d, DeepEquals, []byte{11, 199, 7, 5, 1, 1, 1, 1, 161, 134, 1, 0})
    79  
    80  	t, err = types.ParseDatetime(nil, "0000-00-00 00:00:00.000000")
    81  	c.Assert(err, IsNil)
    82  	d = dumpBinaryDateTime(nil, t)
    83  	c.Assert(d, DeepEquals, []byte{0})
    84  	t, err = types.ParseDatetime(nil, "1993-07-13 01:01:01.000000")
    85  	c.Assert(err, IsNil)
    86  	d = dumpBinaryDateTime(nil, t)
    87  	// 201 & 7 composed to uint16 1993 (litter-endian)
    88  	c.Assert(d, DeepEquals, []byte{11, 201, 7, 7, 13, 1, 1, 1, 0, 0, 0, 0})
    89  
    90  	t, err = types.ParseDate(nil, "0000-00-00")
    91  	c.Assert(err, IsNil)
    92  	d = dumpBinaryDateTime(nil, t)
    93  	c.Assert(d, DeepEquals, []byte{0})
    94  	t, err = types.ParseDate(nil, "1992-06-01")
    95  	c.Assert(err, IsNil)
    96  	d = dumpBinaryDateTime(nil, t)
    97  	// 200 & 7 composed to uint16 1992 (litter-endian)
    98  	c.Assert(d, DeepEquals, []byte{4, 200, 7, 6, 1})
    99  
   100  	t, err = types.ParseDate(nil, "0000-00-00")
   101  	c.Assert(err, IsNil)
   102  	d = dumpBinaryDateTime(nil, t)
   103  	c.Assert(d, DeepEquals, []byte{0})
   104  
   105  	myDuration, err := types.ParseDuration(nil, "0000-00-00 00:00:00.000000", 6)
   106  	c.Assert(err, IsNil)
   107  	d = dumpBinaryTime(myDuration.Duration)
   108  	c.Assert(d, DeepEquals, []byte{0})
   109  
   110  	d = dumpBinaryTime(0)
   111  	c.Assert(d, DeepEquals, []byte{0})
   112  
   113  	d = dumpBinaryTime(-1)
   114  	c.Assert(d, DeepEquals, []byte{12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
   115  
   116  	d = dumpBinaryTime(time.Nanosecond + 86400*1000*time.Microsecond)
   117  	c.Assert(d, DeepEquals, []byte{12, 0, 0, 0, 0, 0, 0, 1, 26, 128, 26, 6, 0})
   118  }
   119  
   120  func (s *testUtilSuite) TestDumpTextValue(c *C) {
   121  	defCausumns := []*DeferredCausetInfo{{
   122  		Type:    allegrosql.TypeLonglong,
   123  		Decimal: allegrosql.NotFixedDec,
   124  	}}
   125  
   126  	null := types.NewIntCauset(0)
   127  	null.SetNull()
   128  	bs, err := dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{null}).ToRow())
   129  	c.Assert(err, IsNil)
   130  	_, isNull, _, err := parseLengthEncodedBytes(bs)
   131  	c.Assert(err, IsNil)
   132  	c.Assert(isNull, IsTrue)
   133  
   134  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{types.NewIntCauset(10)}).ToRow())
   135  	c.Assert(err, IsNil)
   136  	c.Assert(mustDecodeStr(c, bs), Equals, "10")
   137  
   138  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{types.NewUintCauset(11)}).ToRow())
   139  	c.Assert(err, IsNil)
   140  	c.Assert(mustDecodeStr(c, bs), Equals, "11")
   141  
   142  	defCausumns[0].Flag = defCausumns[0].Flag | uint16(allegrosql.UnsignedFlag)
   143  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{types.NewUintCauset(11)}).ToRow())
   144  	c.Assert(err, IsNil)
   145  	c.Assert(mustDecodeStr(c, bs), Equals, "11")
   146  
   147  	defCausumns[0].Type = allegrosql.TypeFloat
   148  	defCausumns[0].Decimal = 1
   149  	f32 := types.NewFloat32Causet(1.2)
   150  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{f32}).ToRow())
   151  	c.Assert(err, IsNil)
   152  	c.Assert(mustDecodeStr(c, bs), Equals, "1.2")
   153  
   154  	defCausumns[0].Decimal = 2
   155  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{f32}).ToRow())
   156  	c.Assert(err, IsNil)
   157  	c.Assert(mustDecodeStr(c, bs), Equals, "1.20")
   158  
   159  	f64 := types.NewFloat64Causet(2.2)
   160  	defCausumns[0].Type = allegrosql.TypeDouble
   161  	defCausumns[0].Decimal = 1
   162  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{f64}).ToRow())
   163  	c.Assert(err, IsNil)
   164  	c.Assert(mustDecodeStr(c, bs), Equals, "2.2")
   165  
   166  	defCausumns[0].Decimal = 2
   167  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{f64}).ToRow())
   168  	c.Assert(err, IsNil)
   169  	c.Assert(mustDecodeStr(c, bs), Equals, "2.20")
   170  
   171  	defCausumns[0].Type = allegrosql.TypeBlob
   172  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{types.NewBytesCauset([]byte("foo"))}).ToRow())
   173  	c.Assert(err, IsNil)
   174  	c.Assert(mustDecodeStr(c, bs), Equals, "foo")
   175  
   176  	defCausumns[0].Type = allegrosql.TypeVarchar
   177  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{types.NewStringCauset("bar")}).ToRow())
   178  	c.Assert(err, IsNil)
   179  	c.Assert(mustDecodeStr(c, bs), Equals, "bar")
   180  
   181  	var d types.Causet
   182  
   183  	sc := mock.NewContext().GetStochastikVars().StmtCtx
   184  	sc.IgnoreZeroInDate = true
   185  	losAngelesTz, err := time.LoadLocation("America/Los_Angeles")
   186  	c.Assert(err, IsNil)
   187  	sc.TimeZone = losAngelesTz
   188  
   189  	time, err := types.ParseTime(sc, "2020-01-05 23:59:59.575601", allegrosql.TypeDatetime, 0)
   190  	c.Assert(err, IsNil)
   191  	d.SetMysqlTime(time)
   192  	defCausumns[0].Type = allegrosql.TypeDatetime
   193  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{d}).ToRow())
   194  	c.Assert(err, IsNil)
   195  	c.Assert(mustDecodeStr(c, bs), Equals, "2020-01-06 00:00:00")
   196  
   197  	duration, err := types.ParseDuration(sc, "11:30:45", 0)
   198  	c.Assert(err, IsNil)
   199  	d.SetMysqlDuration(duration)
   200  	defCausumns[0].Type = allegrosql.TypeDuration
   201  	defCausumns[0].Decimal = 0
   202  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{d}).ToRow())
   203  	c.Assert(err, IsNil)
   204  	c.Assert(mustDecodeStr(c, bs), Equals, "11:30:45")
   205  
   206  	d.SetMysqlDecimal(types.NewDecFromStringForTest("1.23"))
   207  	defCausumns[0].Type = allegrosql.TypeNewDecimal
   208  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{d}).ToRow())
   209  	c.Assert(err, IsNil)
   210  	c.Assert(mustDecodeStr(c, bs), Equals, "1.23")
   211  
   212  	year := types.NewIntCauset(0)
   213  	defCausumns[0].Type = allegrosql.TypeYear
   214  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{year}).ToRow())
   215  	c.Assert(err, IsNil)
   216  	c.Assert(mustDecodeStr(c, bs), Equals, "0000")
   217  
   218  	year.SetInt64(1984)
   219  	defCausumns[0].Type = allegrosql.TypeYear
   220  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{year}).ToRow())
   221  	c.Assert(err, IsNil)
   222  	c.Assert(mustDecodeStr(c, bs), Equals, "1984")
   223  
   224  	enum := types.NewMysqlEnumCauset(types.Enum{Name: "ename", Value: 0})
   225  	defCausumns[0].Type = allegrosql.TypeEnum
   226  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{enum}).ToRow())
   227  	c.Assert(err, IsNil)
   228  	c.Assert(mustDecodeStr(c, bs), Equals, "ename")
   229  
   230  	set := types.Causet{}
   231  	set.SetMysqlSet(types.Set{Name: "sname", Value: 0}, allegrosql.DefaultDefCauslationName)
   232  	defCausumns[0].Type = allegrosql.TypeSet
   233  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{set}).ToRow())
   234  	c.Assert(err, IsNil)
   235  	c.Assert(mustDecodeStr(c, bs), Equals, "sname")
   236  
   237  	js := types.Causet{}
   238  	binaryJSON, err := json.ParseBinaryFromString(`{"a": 1, "b": 2}`)
   239  	c.Assert(err, IsNil)
   240  	js.SetMysqlJSON(binaryJSON)
   241  	defCausumns[0].Type = allegrosql.TypeJSON
   242  	bs, err = dumpTextRow(nil, defCausumns, chunk.MutRowFromCausets([]types.Causet{js}).ToRow())
   243  	c.Assert(err, IsNil)
   244  	c.Assert(mustDecodeStr(c, bs), Equals, `{"a": 1, "b": 2}`)
   245  }
   246  
   247  func mustDecodeStr(c *C, b []byte) string {
   248  	str, _, _, err := parseLengthEncodedBytes(b)
   249  	c.Assert(err, IsNil)
   250  	return string(str)
   251  }
   252  
   253  func (s *testUtilSuite) TestAppendFormatFloat(c *C) {
   254  	tests := []struct {
   255  		fVal    float64
   256  		out     string
   257  		prec    int
   258  		bitSize int
   259  	}{
   260  		{
   261  			99999999999999999999,
   262  			"1e20",
   263  			-1,
   264  			64,
   265  		},
   266  		{
   267  			1e15,
   268  			"1e15",
   269  			-1,
   270  			64,
   271  		},
   272  		{
   273  			9e14,
   274  			"900000000000000",
   275  			-1,
   276  			64,
   277  		},
   278  		{
   279  			-9999999999999999,
   280  			"-1e16",
   281  			-1,
   282  			64,
   283  		},
   284  		{
   285  			999999999999999,
   286  			"999999999999999",
   287  			-1,
   288  			64,
   289  		},
   290  		{
   291  			0.000000000000001,
   292  			"0.000000000000001",
   293  			-1,
   294  			64,
   295  		},
   296  		{
   297  			0.0000000000000009,
   298  			"9e-16",
   299  			-1,
   300  			64,
   301  		},
   302  		{
   303  			-0.0000000000000009,
   304  			"-9e-16",
   305  			-1,
   306  			64,
   307  		},
   308  		{
   309  			0.11111,
   310  			"0.111",
   311  			3,
   312  			64,
   313  		},
   314  		{
   315  			0.11111,
   316  			"0.111",
   317  			3,
   318  			64,
   319  		},
   320  		{
   321  			0.1111111111111111111,
   322  			"0.11111111",
   323  			-1,
   324  			32,
   325  		},
   326  		{
   327  			0.1111111111111111111,
   328  			"0.1111111111111111",
   329  			-1,
   330  			64,
   331  		},
   332  		{
   333  			0.0000000000000009,
   334  			"0.000",
   335  			3,
   336  			64,
   337  		},
   338  		{
   339  			0,
   340  			"0",
   341  			-1,
   342  			64,
   343  		},
   344  	}
   345  	for _, t := range tests {
   346  		c.Assert(string(appendFormatFloat(nil, t.fVal, t.prec, t.bitSize)), Equals, t.out)
   347  	}
   348  }
   349  
   350  func (s *testUtilSuite) TestDumpLengthEncodedInt(c *C) {
   351  	testCases := []struct {
   352  		num    uint64
   353  		buffer []byte
   354  	}{
   355  		{
   356  			uint64(0),
   357  			[]byte{0x00},
   358  		},
   359  		{
   360  			uint64(513),
   361  			[]byte{'\xfc', '\x01', '\x02'},
   362  		},
   363  		{
   364  			uint64(197121),
   365  			[]byte{'\xfd', '\x01', '\x02', '\x03'},
   366  		},
   367  		{
   368  			uint64(578437695752307201),
   369  			[]byte{'\xfe', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08'},
   370  		},
   371  	}
   372  	for _, tc := range testCases {
   373  		b := dumpLengthEncodedInt(nil, tc.num)
   374  		c.Assert(b, DeepEquals, tc.buffer)
   375  	}
   376  }
   377  
   378  func (s *testUtilSuite) TestParseLengthEncodedInt(c *C) {
   379  	testCases := []struct {
   380  		buffer []byte
   381  		num    uint64
   382  		isNull bool
   383  		n      int
   384  	}{
   385  		{
   386  			[]byte{'\xfb'},
   387  			uint64(0),
   388  			true,
   389  			1,
   390  		},
   391  		{
   392  			[]byte{'\x00'},
   393  			uint64(0),
   394  			false,
   395  			1,
   396  		},
   397  		{
   398  			[]byte{'\xfc', '\x01', '\x02'},
   399  			uint64(513),
   400  			false,
   401  			3,
   402  		},
   403  		{
   404  			[]byte{'\xfd', '\x01', '\x02', '\x03'},
   405  			uint64(197121),
   406  			false,
   407  			4,
   408  		},
   409  		{
   410  			[]byte{'\xfe', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08'},
   411  			uint64(578437695752307201),
   412  			false,
   413  			9,
   414  		},
   415  	}
   416  
   417  	for _, tc := range testCases {
   418  		num, isNull, n := parseLengthEncodedInt(tc.buffer)
   419  		c.Assert(num, Equals, tc.num)
   420  		c.Assert(isNull, Equals, tc.isNull)
   421  		c.Assert(n, Equals, tc.n)
   422  
   423  		c.Assert(lengthEncodedIntSize(tc.num), Equals, tc.n)
   424  	}
   425  }
   426  
   427  func (s *testUtilSuite) TestDumpUint(c *C) {
   428  	testCases := []uint64{
   429  		0,
   430  		1,
   431  		1<<64 - 1,
   432  	}
   433  	parseUint64 := func(b []byte) uint64 {
   434  		return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 |
   435  			uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 |
   436  			uint64(b[6])<<48 | uint64(b[7])<<56
   437  	}
   438  	for _, tc := range testCases {
   439  		b := dumpUint64(nil, tc)
   440  		c.Assert(len(b), Equals, 8)
   441  		c.Assert(parseUint64(b), Equals, tc)
   442  	}
   443  }
   444  
   445  func (s *testUtilSuite) TestParseLengthEncodedBytes(c *C) {
   446  	buffer := []byte{'\xfb'}
   447  	b, isNull, n, err := parseLengthEncodedBytes(buffer)
   448  	c.Assert(b, IsNil)
   449  	c.Assert(isNull, IsTrue)
   450  	c.Assert(n, Equals, 1)
   451  	c.Assert(err, IsNil)
   452  
   453  	buffer = []byte{0}
   454  	b, isNull, n, err = parseLengthEncodedBytes(buffer)
   455  	c.Assert(b, IsNil)
   456  	c.Assert(isNull, IsFalse)
   457  	c.Assert(n, Equals, 1)
   458  	c.Assert(err, IsNil)
   459  
   460  	buffer = []byte{'\x01'}
   461  	b, isNull, n, err = parseLengthEncodedBytes(buffer)
   462  	c.Assert(b, IsNil)
   463  	c.Assert(isNull, IsFalse)
   464  	c.Assert(n, Equals, 2)
   465  	c.Assert(err.Error(), Equals, "EOF")
   466  }
   467  
   468  func (s *testUtilSuite) TestParseNullTermString(c *C) {
   469  	for _, t := range []struct {
   470  		input  string
   471  		str    string
   472  		remain string
   473  	}{
   474  		{
   475  			"abc\x00def",
   476  			"abc",
   477  			"def",
   478  		},
   479  		{
   480  			"\x00def",
   481  			"",
   482  			"def",
   483  		},
   484  		{
   485  			"def\x00hig\x00k",
   486  			"def",
   487  			"hig\x00k",
   488  		},
   489  		{
   490  			"abcdef",
   491  			"",
   492  			"abcdef",
   493  		},
   494  	} {
   495  		str, remain := parseNullTermString([]byte(t.input))
   496  		c.Assert(string(str), Equals, t.str)
   497  		c.Assert(string(remain), Equals, t.remain)
   498  	}
   499  }
   500  
   501  func newTestConfig() *config.Config {
   502  	cfg := config.NewConfig()
   503  	cfg.Host = "127.0.0.1"
   504  	cfg.Status.StatusHost = "127.0.0.1"
   505  	return cfg
   506  }