github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/convert_test.go (about)

     1  // Copyright 2015 PingCAP, 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 types
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"strconv"
    20  	"time"
    21  
    22  	. "github.com/pingcap/check"
    23  	"github.com/pingcap/errors"
    24  
    25  	"github.com/XiaoMi/Gaea/mysql"
    26  	"github.com/XiaoMi/Gaea/parser/stmtctx"
    27  	"github.com/XiaoMi/Gaea/parser/terror"
    28  	"github.com/XiaoMi/Gaea/parser/tidb-types/json"
    29  	"github.com/XiaoMi/Gaea/util/testleak"
    30  )
    31  
    32  var _ = Suite(&testTypeConvertSuite{})
    33  
    34  type testTypeConvertSuite struct {
    35  }
    36  
    37  type invalidMockType struct {
    38  }
    39  
    40  // Convert converts the val with type tp.
    41  func Convert(val interface{}, target *FieldType) (v interface{}, err error) {
    42  	d := NewDatum(val)
    43  	sc := new(stmtctx.StatementContext)
    44  	sc.TimeZone = time.UTC
    45  	ret, err := d.ConvertTo(sc, target)
    46  	if err != nil {
    47  		return ret.GetValue(), errors.Trace(err)
    48  	}
    49  	return ret.GetValue(), nil
    50  }
    51  
    52  func (s *testTypeConvertSuite) TestConvertType(c *C) {
    53  	defer testleak.AfterTest(c)()
    54  	ft := NewFieldType(mysql.TypeBlob)
    55  	ft.Flen = 4
    56  	ft.Charset = "utf8"
    57  	v, err := Convert("123456", ft)
    58  	c.Assert(ErrDataTooLong.Equal(err), IsTrue)
    59  	c.Assert(v, Equals, "1234")
    60  	ft = NewFieldType(mysql.TypeString)
    61  	ft.Flen = 4
    62  	ft.Charset = mysql.CharsetBin
    63  	v, err = Convert("12345", ft)
    64  	c.Assert(ErrDataTooLong.Equal(err), IsTrue)
    65  	c.Assert(v, DeepEquals, []byte("1234"))
    66  
    67  	ft = NewFieldType(mysql.TypeFloat)
    68  	ft.Flen = 5
    69  	ft.Decimal = 2
    70  	v, err = Convert(111.114, ft)
    71  	c.Assert(err, IsNil)
    72  	c.Assert(v, Equals, float32(111.11))
    73  
    74  	ft = NewFieldType(mysql.TypeFloat)
    75  	ft.Flen = 5
    76  	ft.Decimal = 2
    77  	v, err = Convert(999.999, ft)
    78  	c.Assert(err, NotNil)
    79  	c.Assert(v, Equals, float32(999.99))
    80  
    81  	ft = NewFieldType(mysql.TypeFloat)
    82  	ft.Flen = 5
    83  	ft.Decimal = 2
    84  	v, err = Convert(-999.999, ft)
    85  	c.Assert(err, NotNil)
    86  	c.Assert(v, Equals, float32(-999.99))
    87  
    88  	ft = NewFieldType(mysql.TypeFloat)
    89  	ft.Flen = 5
    90  	ft.Decimal = 2
    91  	v, err = Convert(1111.11, ft)
    92  	c.Assert(err, NotNil)
    93  	c.Assert(v, Equals, float32(999.99))
    94  
    95  	ft = NewFieldType(mysql.TypeFloat)
    96  	ft.Flen = 5
    97  	ft.Decimal = 2
    98  	v, err = Convert(999.916, ft)
    99  	c.Assert(err, IsNil)
   100  	c.Assert(v, Equals, float32(999.92))
   101  
   102  	ft = NewFieldType(mysql.TypeFloat)
   103  	ft.Flen = 5
   104  	ft.Decimal = 2
   105  	v, err = Convert(999.914, ft)
   106  	c.Assert(err, IsNil)
   107  	c.Assert(v, Equals, float32(999.91))
   108  
   109  	ft = NewFieldType(mysql.TypeFloat)
   110  	ft.Flen = 5
   111  	ft.Decimal = 2
   112  	v, err = Convert(999.9155, ft)
   113  	c.Assert(err, IsNil)
   114  	c.Assert(v, Equals, float32(999.92))
   115  
   116  	// For TypeBlob
   117  	ft = NewFieldType(mysql.TypeBlob)
   118  	_, err = Convert(&invalidMockType{}, ft)
   119  	c.Assert(err, NotNil)
   120  
   121  	// Nil
   122  	ft = NewFieldType(mysql.TypeBlob)
   123  	v, err = Convert(nil, ft)
   124  	c.Assert(err, IsNil)
   125  	c.Assert(v, IsNil)
   126  
   127  	// TypeDouble
   128  	ft = NewFieldType(mysql.TypeDouble)
   129  	ft.Flen = 5
   130  	ft.Decimal = 2
   131  	v, err = Convert(999.9155, ft)
   132  	c.Assert(err, IsNil)
   133  	c.Assert(v, Equals, float64(999.92))
   134  
   135  	// For TypeString
   136  	ft = NewFieldType(mysql.TypeString)
   137  	ft.Flen = 3
   138  	v, err = Convert("12345", ft)
   139  	c.Assert(ErrDataTooLong.Equal(err), IsTrue)
   140  	c.Assert(v, Equals, "123")
   141  	ft = NewFieldType(mysql.TypeString)
   142  	ft.Flen = 3
   143  	ft.Charset = mysql.CharsetBin
   144  	v, err = Convert("12345", ft)
   145  	c.Assert(ErrDataTooLong.Equal(err), IsTrue)
   146  	c.Assert(v, DeepEquals, []byte("123"))
   147  
   148  	// For TypeDuration
   149  	ft = NewFieldType(mysql.TypeDuration)
   150  	ft.Decimal = 3
   151  	v, err = Convert("10:11:12.123456", ft)
   152  	c.Assert(err, IsNil)
   153  	c.Assert(v.(Duration).String(), Equals, "10:11:12.123")
   154  	ft.Decimal = 1
   155  	vv, err := Convert(v, ft)
   156  	c.Assert(err, IsNil)
   157  	c.Assert(vv.(Duration).String(), Equals, "10:11:12.1")
   158  
   159  	vd, err := ParseTime(nil, "2010-10-10 10:11:11.12345", mysql.TypeDatetime, 2)
   160  	c.Assert(vd.String(), Equals, "2010-10-10 10:11:11.12")
   161  	c.Assert(err, IsNil)
   162  	v, err = Convert(vd, ft)
   163  	c.Assert(err, IsNil)
   164  	c.Assert(v.(Duration).String(), Equals, "10:11:11.1")
   165  
   166  	vt, err := ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC}, "2010-10-10 10:11:11.12345", mysql.TypeTimestamp, 2)
   167  	c.Assert(vt.String(), Equals, "2010-10-10 10:11:11.12")
   168  	c.Assert(err, IsNil)
   169  	v, err = Convert(vt, ft)
   170  	c.Assert(err, IsNil)
   171  	c.Assert(v.(Duration).String(), Equals, "10:11:11.1")
   172  
   173  	// For mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate
   174  	ft = NewFieldType(mysql.TypeTimestamp)
   175  	ft.Decimal = 3
   176  	v, err = Convert("2010-10-10 10:11:11.12345", ft)
   177  	c.Assert(err, IsNil)
   178  	c.Assert(v.(Time).String(), Equals, "2010-10-10 10:11:11.123")
   179  	ft.Decimal = 1
   180  	vv, err = Convert(v, ft)
   181  	c.Assert(err, IsNil)
   182  	c.Assert(vv.(Time).String(), Equals, "2010-10-10 10:11:11.1")
   183  
   184  	// For TypeLonglong
   185  	ft = NewFieldType(mysql.TypeLonglong)
   186  	v, err = Convert("100", ft)
   187  	c.Assert(err, IsNil)
   188  	c.Assert(v, Equals, int64(100))
   189  	// issue 4287.
   190  	v, err = Convert(math.Pow(2, 63)-1, ft)
   191  	c.Assert(err, IsNil)
   192  	c.Assert(v, Equals, int64(math.MaxInt64))
   193  	ft = NewFieldType(mysql.TypeLonglong)
   194  	ft.Flag |= mysql.UnsignedFlag
   195  	v, err = Convert("100", ft)
   196  	c.Assert(err, IsNil)
   197  	c.Assert(v, Equals, uint64(100))
   198  	// issue 3470
   199  	ft = NewFieldType(mysql.TypeLonglong)
   200  	v, err = Convert(Duration{Duration: time.Duration(12*time.Hour + 59*time.Minute + 59*time.Second + 555*time.Millisecond), Fsp: 3}, ft)
   201  	c.Assert(err, IsNil)
   202  	c.Assert(v, Equals, int64(130000))
   203  	v, err = Convert(Time{
   204  		Time: FromDate(2017, 1, 1, 12, 59, 59, 555000),
   205  		Type: mysql.TypeDatetime,
   206  		Fsp:  MaxFsp}, ft)
   207  	c.Assert(err, IsNil)
   208  	c.Assert(v, Equals, int64(20170101130000))
   209  
   210  	// For TypeBit
   211  	ft = NewFieldType(mysql.TypeBit)
   212  	ft.Flen = 24 // 3 bytes.
   213  	v, err = Convert("100", ft)
   214  	c.Assert(err, IsNil)
   215  	c.Assert(v, DeepEquals, NewBinaryLiteralFromUint(3223600, 3))
   216  
   217  	v, err = Convert(NewBinaryLiteralFromUint(100, -1), ft)
   218  	c.Assert(err, IsNil)
   219  	c.Assert(v, DeepEquals, NewBinaryLiteralFromUint(100, 3))
   220  
   221  	ft.Flen = 1
   222  	v, err = Convert(1, ft)
   223  	c.Assert(err, IsNil)
   224  	c.Assert(v, DeepEquals, NewBinaryLiteralFromUint(1, 1))
   225  
   226  	_, err = Convert(2, ft)
   227  	c.Assert(err, NotNil)
   228  
   229  	ft.Flen = 0
   230  	_, err = Convert(2, ft)
   231  	c.Assert(err, NotNil)
   232  
   233  	// For TypeNewDecimal
   234  	ft = NewFieldType(mysql.TypeNewDecimal)
   235  	ft.Flen = 8
   236  	ft.Decimal = 4
   237  	v, err = Convert(3.1416, ft)
   238  	c.Assert(err, IsNil, Commentf(errors.ErrorStack(err)))
   239  	c.Assert(v.(*MyDecimal).String(), Equals, "3.1416")
   240  	v, err = Convert("3.1415926", ft)
   241  	c.Assert(terror.ErrorEqual(err, ErrTruncated), IsTrue, Commentf("err %v", err))
   242  	c.Assert(v.(*MyDecimal).String(), Equals, "3.1416")
   243  	v, err = Convert("99999", ft)
   244  	c.Assert(terror.ErrorEqual(err, ErrOverflow), IsTrue, Commentf("err %v", err))
   245  	c.Assert(v.(*MyDecimal).String(), Equals, "9999.9999")
   246  	v, err = Convert("-10000", ft)
   247  	c.Assert(terror.ErrorEqual(err, ErrOverflow), IsTrue, Commentf("err %v", err))
   248  	c.Assert(v.(*MyDecimal).String(), Equals, "-9999.9999")
   249  
   250  	// Test Datum.ToDecimal with bad number.
   251  	d := NewDatum("hello")
   252  	sc := new(stmtctx.StatementContext)
   253  	_, err = d.ToDecimal(sc)
   254  	c.Assert(terror.ErrorEqual(err, ErrBadNumber), IsTrue, Commentf("err %v", err))
   255  
   256  	sc.IgnoreTruncate = true
   257  	v, err = d.ToDecimal(sc)
   258  	c.Assert(err, IsNil)
   259  	c.Assert(v.(*MyDecimal).String(), Equals, "0")
   260  
   261  	// For TypeYear
   262  	ft = NewFieldType(mysql.TypeYear)
   263  	v, err = Convert("2015", ft)
   264  	c.Assert(err, IsNil)
   265  	c.Assert(v, Equals, int64(2015))
   266  	v, err = Convert(2015, ft)
   267  	c.Assert(err, IsNil)
   268  	c.Assert(v, Equals, int64(2015))
   269  	_, err = Convert(1800, ft)
   270  	c.Assert(err, NotNil)
   271  	dt, err := ParseDate(nil, "2015-11-11")
   272  	c.Assert(err, IsNil)
   273  	v, err = Convert(dt, ft)
   274  	c.Assert(err, IsNil)
   275  	c.Assert(v, Equals, int64(2015))
   276  	v, err = Convert(ZeroDuration, ft)
   277  	c.Assert(err, IsNil)
   278  	c.Assert(v, Equals, int64(time.Now().Year()))
   279  
   280  	// For enum
   281  	ft = NewFieldType(mysql.TypeEnum)
   282  	ft.Elems = []string{"a", "b", "c"}
   283  	v, err = Convert("a", ft)
   284  	c.Assert(err, IsNil)
   285  	c.Assert(v, DeepEquals, Enum{Name: "a", Value: 1})
   286  	v, err = Convert(2, ft)
   287  	c.Log(errors.ErrorStack(err))
   288  	c.Assert(err, IsNil)
   289  	c.Assert(v, DeepEquals, Enum{Name: "b", Value: 2})
   290  	_, err = Convert("d", ft)
   291  	c.Assert(err, NotNil)
   292  	v, err = Convert(4, ft)
   293  	c.Assert(terror.ErrorEqual(err, ErrTruncated), IsTrue, Commentf("err %v", err))
   294  	c.Assert(v, DeepEquals, Enum{})
   295  
   296  	ft = NewFieldType(mysql.TypeSet)
   297  	ft.Elems = []string{"a", "b", "c"}
   298  	v, err = Convert("a", ft)
   299  	c.Assert(err, IsNil)
   300  	c.Assert(v, DeepEquals, Set{Name: "a", Value: 1})
   301  	v, err = Convert(2, ft)
   302  	c.Assert(err, IsNil)
   303  	c.Assert(v, DeepEquals, Set{Name: "b", Value: 2})
   304  	v, err = Convert(3, ft)
   305  	c.Assert(err, IsNil)
   306  	c.Assert(v, DeepEquals, Set{Name: "a,b", Value: 3})
   307  	_, err = Convert("d", ft)
   308  	c.Assert(err, NotNil)
   309  	_, err = Convert(9, ft)
   310  	c.Assert(err, NotNil)
   311  }
   312  
   313  func testToString(c *C, val interface{}, expect string) {
   314  	b, err := ToString(val)
   315  	c.Assert(err, IsNil)
   316  	c.Assert(b, Equals, expect)
   317  }
   318  
   319  func (s *testTypeConvertSuite) TestConvertToString(c *C) {
   320  	defer testleak.AfterTest(c)()
   321  	testToString(c, "0", "0")
   322  	testToString(c, true, "1")
   323  	testToString(c, "false", "false")
   324  	testToString(c, int(0), "0")
   325  	testToString(c, int64(0), "0")
   326  	testToString(c, uint64(0), "0")
   327  	testToString(c, float32(1.6), "1.6")
   328  	testToString(c, float64(-0.6), "-0.6")
   329  	testToString(c, []byte{1}, "\x01")
   330  	testToString(c, NewBinaryLiteralFromUint(0x4D7953514C, -1), "MySQL")
   331  	testToString(c, NewBinaryLiteralFromUint(0x41, -1), "A")
   332  	testToString(c, Enum{Name: "a", Value: 1}, "a")
   333  	testToString(c, Set{Name: "a", Value: 1}, "a")
   334  
   335  	t, err := ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC},
   336  		"2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
   337  	c.Assert(err, IsNil)
   338  	testToString(c, t, "2011-11-10 11:11:11.999999")
   339  
   340  	td, err := ParseDuration(nil, "11:11:11.999999", 6)
   341  	c.Assert(err, IsNil)
   342  	testToString(c, td, "11:11:11.999999")
   343  
   344  	ft := NewFieldType(mysql.TypeNewDecimal)
   345  	ft.Flen = 10
   346  	ft.Decimal = 5
   347  	v, err := Convert(3.1415926, ft)
   348  	c.Assert(terror.ErrorEqual(err, ErrTruncated), IsTrue, Commentf("err %v", err))
   349  	testToString(c, v, "3.14159")
   350  
   351  	_, err = ToString(&invalidMockType{})
   352  	c.Assert(err, NotNil)
   353  
   354  	// test truncate
   355  	tests := []struct {
   356  		flen    int
   357  		charset string
   358  		input   string
   359  		output  string
   360  	}{
   361  		{5, "utf8", "你好,世界", "你好,世界"},
   362  		{5, "utf8mb4", "你好,世界", "你好,世界"},
   363  		{4, "utf8", "你好,世界", "你好,世"},
   364  		{4, "utf8mb4", "你好,世界", "你好,世"},
   365  		{15, "binary", "你好,世界", "你好,世界"},
   366  		{12, "binary", "你好,世界", "你好,世"},
   367  		{0, "binary", "你好,世界", ""},
   368  	}
   369  	for _, tt := range tests {
   370  		ft = NewFieldType(mysql.TypeVarchar)
   371  		ft.Flen = tt.flen
   372  		ft.Charset = tt.charset
   373  		inputDatum := NewStringDatum(tt.input)
   374  		sc := new(stmtctx.StatementContext)
   375  		outputDatum, err := inputDatum.ConvertTo(sc, ft)
   376  		if tt.input != tt.output {
   377  			c.Assert(ErrDataTooLong.Equal(err), IsTrue)
   378  		} else {
   379  			c.Assert(err, IsNil)
   380  		}
   381  		c.Assert(outputDatum.GetString(), Equals, tt.output)
   382  	}
   383  }
   384  
   385  func testStrToInt(c *C, str string, expect int64, truncateAsErr bool, expectErr error) {
   386  	sc := new(stmtctx.StatementContext)
   387  	sc.IgnoreTruncate = !truncateAsErr
   388  	val, err := StrToInt(sc, str)
   389  	if expectErr != nil {
   390  		c.Assert(terror.ErrorEqual(err, expectErr), IsTrue, Commentf("err %v", err))
   391  	} else {
   392  		c.Assert(err, IsNil)
   393  		c.Assert(val, Equals, expect)
   394  	}
   395  }
   396  
   397  func testStrToUint(c *C, str string, expect uint64, truncateAsErr bool, expectErr error) {
   398  	sc := new(stmtctx.StatementContext)
   399  	sc.IgnoreTruncate = !truncateAsErr
   400  	val, err := StrToUint(sc, str)
   401  	if expectErr != nil {
   402  		c.Assert(terror.ErrorEqual(err, expectErr), IsTrue, Commentf("err %v", err))
   403  	} else {
   404  		c.Assert(err, IsNil)
   405  		c.Assert(val, Equals, expect)
   406  	}
   407  }
   408  
   409  func testStrToFloat(c *C, str string, expect float64, truncateAsErr bool, expectErr error) {
   410  	sc := new(stmtctx.StatementContext)
   411  	sc.IgnoreTruncate = !truncateAsErr
   412  	val, err := StrToFloat(sc, str)
   413  	if expectErr != nil {
   414  		c.Assert(terror.ErrorEqual(err, expectErr), IsTrue, Commentf("err %v", err))
   415  	} else {
   416  		c.Assert(err, IsNil)
   417  		c.Assert(val, Equals, expect)
   418  	}
   419  }
   420  
   421  func (s *testTypeConvertSuite) TestStrToNum(c *C) {
   422  	defer testleak.AfterTest(c)()
   423  	testStrToInt(c, "0", 0, true, nil)
   424  	testStrToInt(c, "-1", -1, true, nil)
   425  	testStrToInt(c, "100", 100, true, nil)
   426  	testStrToInt(c, "65.0", 65, false, nil)
   427  	testStrToInt(c, "65.0", 65, true, nil)
   428  	testStrToInt(c, "", 0, false, nil)
   429  	testStrToInt(c, "", 0, true, ErrTruncated)
   430  	testStrToInt(c, "xx", 0, true, ErrTruncated)
   431  	testStrToInt(c, "xx", 0, false, nil)
   432  	testStrToInt(c, "11xx", 11, true, ErrTruncated)
   433  	testStrToInt(c, "11xx", 11, false, nil)
   434  	testStrToInt(c, "xx11", 0, false, nil)
   435  
   436  	testStrToUint(c, "0", 0, true, nil)
   437  	testStrToUint(c, "", 0, false, nil)
   438  	testStrToUint(c, "", 0, false, nil)
   439  	testStrToUint(c, "-1", 0xffffffffffffffff, false, ErrOverflow)
   440  	testStrToUint(c, "100", 100, true, nil)
   441  	testStrToUint(c, "+100", 100, true, nil)
   442  	testStrToUint(c, "65.0", 65, true, nil)
   443  	testStrToUint(c, "xx", 0, true, ErrTruncated)
   444  	testStrToUint(c, "11xx", 11, true, ErrTruncated)
   445  	testStrToUint(c, "xx11", 0, true, ErrTruncated)
   446  
   447  	// TODO: makes StrToFloat return truncated value instead of zero to make it pass.
   448  	testStrToFloat(c, "", 0, true, ErrTruncated)
   449  	testStrToFloat(c, "-1", -1.0, true, nil)
   450  	testStrToFloat(c, "1.11", 1.11, true, nil)
   451  	testStrToFloat(c, "1.11.00", 1.11, false, nil)
   452  	testStrToFloat(c, "1.11.00", 1.11, true, ErrTruncated)
   453  	testStrToFloat(c, "xx", 0.0, false, nil)
   454  	testStrToFloat(c, "0x00", 0.0, false, nil)
   455  	testStrToFloat(c, "11.xx", 11.0, false, nil)
   456  	testStrToFloat(c, "11.xx", 11.0, true, ErrTruncated)
   457  	testStrToFloat(c, "xx.11", 0.0, false, nil)
   458  
   459  	// for issue #5111
   460  	testStrToFloat(c, "1e649", math.MaxFloat64, true, ErrTruncatedWrongVal)
   461  	testStrToFloat(c, "1e649", math.MaxFloat64, false, nil)
   462  	testStrToFloat(c, "-1e649", -math.MaxFloat64, true, ErrTruncatedWrongVal)
   463  	testStrToFloat(c, "-1e649", -math.MaxFloat64, false, nil)
   464  }
   465  
   466  func (s *testTypeConvertSuite) TestFieldTypeToStr(c *C) {
   467  	defer testleak.AfterTest(c)()
   468  	v := TypeToStr(mysql.TypeUnspecified, "not binary")
   469  	c.Assert(v, Equals, TypeStr(mysql.TypeUnspecified))
   470  	v = TypeToStr(mysql.TypeBlob, mysql.CharsetBin)
   471  	c.Assert(v, Equals, "blob")
   472  	v = TypeToStr(mysql.TypeString, mysql.CharsetBin)
   473  	c.Assert(v, Equals, "binary")
   474  }
   475  
   476  func accept(c *C, tp byte, value interface{}, unsigned bool, expected string) {
   477  	ft := NewFieldType(tp)
   478  	if unsigned {
   479  		ft.Flag |= mysql.UnsignedFlag
   480  	}
   481  	d := NewDatum(value)
   482  	sc := new(stmtctx.StatementContext)
   483  	sc.TimeZone = time.UTC
   484  	sc.IgnoreTruncate = true
   485  	casted, err := d.ConvertTo(sc, ft)
   486  	c.Assert(err, IsNil, Commentf("%v", ft))
   487  	if casted.IsNull() {
   488  		c.Assert(expected, Equals, "<nil>")
   489  	} else {
   490  		str, err := casted.ToString()
   491  		c.Assert(err, IsNil)
   492  		c.Assert(str, Equals, expected)
   493  	}
   494  }
   495  
   496  func unsignedAccept(c *C, tp byte, value interface{}, expected string) {
   497  	accept(c, tp, value, true, expected)
   498  }
   499  
   500  func signedAccept(c *C, tp byte, value interface{}, expected string) {
   501  	accept(c, tp, value, false, expected)
   502  }
   503  
   504  func deny(c *C, tp byte, value interface{}, unsigned bool, expected string) {
   505  	ft := NewFieldType(tp)
   506  	if unsigned {
   507  		ft.Flag |= mysql.UnsignedFlag
   508  	}
   509  	d := NewDatum(value)
   510  	sc := new(stmtctx.StatementContext)
   511  	casted, err := d.ConvertTo(sc, ft)
   512  	c.Assert(err, NotNil)
   513  	if casted.IsNull() {
   514  		c.Assert(expected, Equals, "<nil>")
   515  	} else {
   516  		str, err := casted.ToString()
   517  		c.Assert(err, IsNil)
   518  		c.Assert(str, Equals, expected)
   519  	}
   520  }
   521  
   522  func unsignedDeny(c *C, tp byte, value interface{}, expected string) {
   523  	deny(c, tp, value, true, expected)
   524  }
   525  
   526  func signedDeny(c *C, tp byte, value interface{}, expected string) {
   527  	deny(c, tp, value, false, expected)
   528  }
   529  
   530  func strvalue(v interface{}) string {
   531  	return fmt.Sprintf("%v", v)
   532  }
   533  
   534  func (s *testTypeConvertSuite) TestConvert(c *C) {
   535  	defer testleak.AfterTest(c)()
   536  	// integer ranges
   537  	signedDeny(c, mysql.TypeTiny, -129, "-128")
   538  	signedAccept(c, mysql.TypeTiny, -128, "-128")
   539  	signedAccept(c, mysql.TypeTiny, 127, "127")
   540  	signedDeny(c, mysql.TypeTiny, 128, "127")
   541  	unsignedDeny(c, mysql.TypeTiny, -1, "255")
   542  	unsignedAccept(c, mysql.TypeTiny, 0, "0")
   543  	unsignedAccept(c, mysql.TypeTiny, 255, "255")
   544  	unsignedDeny(c, mysql.TypeTiny, 256, "255")
   545  
   546  	signedDeny(c, mysql.TypeShort, int64(math.MinInt16)-1, strvalue(int64(math.MinInt16)))
   547  	signedAccept(c, mysql.TypeShort, int64(math.MinInt16), strvalue(int64(math.MinInt16)))
   548  	signedAccept(c, mysql.TypeShort, int64(math.MaxInt16), strvalue(int64(math.MaxInt16)))
   549  	signedDeny(c, mysql.TypeShort, int64(math.MaxInt16)+1, strvalue(int64(math.MaxInt16)))
   550  	unsignedDeny(c, mysql.TypeShort, -1, "65535")
   551  	unsignedAccept(c, mysql.TypeShort, 0, "0")
   552  	unsignedAccept(c, mysql.TypeShort, uint64(math.MaxUint16), strvalue(uint64(math.MaxUint16)))
   553  	unsignedDeny(c, mysql.TypeShort, uint64(math.MaxUint16)+1, strvalue(uint64(math.MaxUint16)))
   554  
   555  	signedDeny(c, mysql.TypeInt24, -1<<23-1, strvalue(-1<<23))
   556  	signedAccept(c, mysql.TypeInt24, -1<<23, strvalue(-1<<23))
   557  	signedAccept(c, mysql.TypeInt24, 1<<23-1, strvalue(1<<23-1))
   558  	signedDeny(c, mysql.TypeInt24, 1<<23, strvalue(1<<23-1))
   559  	unsignedDeny(c, mysql.TypeInt24, -1, "16777215")
   560  	unsignedAccept(c, mysql.TypeInt24, 0, "0")
   561  	unsignedAccept(c, mysql.TypeInt24, 1<<24-1, strvalue(1<<24-1))
   562  	unsignedDeny(c, mysql.TypeInt24, 1<<24, strvalue(1<<24-1))
   563  
   564  	signedDeny(c, mysql.TypeLong, int64(math.MinInt32)-1, strvalue(int64(math.MinInt32)))
   565  	signedAccept(c, mysql.TypeLong, int64(math.MinInt32), strvalue(int64(math.MinInt32)))
   566  	signedAccept(c, mysql.TypeLong, int64(math.MaxInt32), strvalue(int64(math.MaxInt32)))
   567  	signedDeny(c, mysql.TypeLong, uint64(math.MaxUint64), strvalue(uint64(math.MaxInt32)))
   568  	signedDeny(c, mysql.TypeLong, int64(math.MaxInt32)+1, strvalue(int64(math.MaxInt32)))
   569  	signedDeny(c, mysql.TypeLong, "1343545435346432587475", strvalue(int64(math.MaxInt32)))
   570  	unsignedDeny(c, mysql.TypeLong, -1, "4294967295")
   571  	unsignedAccept(c, mysql.TypeLong, 0, "0")
   572  	unsignedAccept(c, mysql.TypeLong, uint64(math.MaxUint32), strvalue(uint64(math.MaxUint32)))
   573  	unsignedDeny(c, mysql.TypeLong, uint64(math.MaxUint32)+1, strvalue(uint64(math.MaxUint32)))
   574  
   575  	signedDeny(c, mysql.TypeLonglong, math.MinInt64*1.1, strvalue(int64(math.MinInt64)))
   576  	signedAccept(c, mysql.TypeLonglong, int64(math.MinInt64), strvalue(int64(math.MinInt64)))
   577  	signedAccept(c, mysql.TypeLonglong, int64(math.MaxInt64), strvalue(int64(math.MaxInt64)))
   578  	signedDeny(c, mysql.TypeLonglong, math.MaxInt64*1.1, strvalue(int64(math.MaxInt64)))
   579  	unsignedAccept(c, mysql.TypeLonglong, -1, "18446744073709551615")
   580  	unsignedAccept(c, mysql.TypeLonglong, 0, "0")
   581  	unsignedAccept(c, mysql.TypeLonglong, uint64(math.MaxUint64), strvalue(uint64(math.MaxUint64)))
   582  	unsignedDeny(c, mysql.TypeLonglong, math.MaxUint64*1.1, strvalue(uint64(math.MaxUint64)))
   583  
   584  	// integer from string
   585  	signedAccept(c, mysql.TypeLong, "	  234  ", "234")
   586  	signedAccept(c, mysql.TypeLong, " 2.35e3  ", "2350")
   587  	signedAccept(c, mysql.TypeLong, " 2.e3  ", "2000")
   588  	signedAccept(c, mysql.TypeLong, " -2.e3  ", "-2000")
   589  	signedAccept(c, mysql.TypeLong, " 2e2  ", "200")
   590  	signedAccept(c, mysql.TypeLong, " 0.002e3  ", "2")
   591  	signedAccept(c, mysql.TypeLong, " .002e3  ", "2")
   592  	signedAccept(c, mysql.TypeLong, " 20e-2  ", "0")
   593  	signedAccept(c, mysql.TypeLong, " -20e-2  ", "0")
   594  	signedAccept(c, mysql.TypeLong, " +2.51 ", "3")
   595  	signedAccept(c, mysql.TypeLong, " -9999.5 ", "-10000")
   596  	signedAccept(c, mysql.TypeLong, " 999.4", "999")
   597  	signedAccept(c, mysql.TypeLong, " -3.58", "-4")
   598  	signedDeny(c, mysql.TypeLong, " 1a ", "1")
   599  	signedDeny(c, mysql.TypeLong, " +1+ ", "1")
   600  
   601  	// integer from float
   602  	signedAccept(c, mysql.TypeLong, 234.5456, "235")
   603  	signedAccept(c, mysql.TypeLong, -23.45, "-23")
   604  	unsignedAccept(c, mysql.TypeLonglong, 234.5456, "235")
   605  	unsignedDeny(c, mysql.TypeLonglong, -23.45, "18446744073709551593")
   606  
   607  	// float from string
   608  	signedAccept(c, mysql.TypeFloat, "23.523", "23.523")
   609  	signedAccept(c, mysql.TypeFloat, int64(123), "123")
   610  	signedAccept(c, mysql.TypeFloat, uint64(123), "123")
   611  	signedAccept(c, mysql.TypeFloat, int(123), "123")
   612  	signedAccept(c, mysql.TypeFloat, float32(123), "123")
   613  	signedAccept(c, mysql.TypeFloat, float64(123), "123")
   614  	signedAccept(c, mysql.TypeDouble, " -23.54", "-23.54")
   615  	signedDeny(c, mysql.TypeDouble, "-23.54a", "-23.54")
   616  	signedDeny(c, mysql.TypeDouble, "-23.54e2e", "-2354")
   617  	signedDeny(c, mysql.TypeDouble, "+.e", "0")
   618  	signedAccept(c, mysql.TypeDouble, "1e+1", "10")
   619  
   620  	// year
   621  	signedDeny(c, mysql.TypeYear, 123, "<nil>")
   622  	signedDeny(c, mysql.TypeYear, 3000, "<nil>")
   623  	signedAccept(c, mysql.TypeYear, "2000", "2000")
   624  
   625  	// time from string
   626  	signedAccept(c, mysql.TypeDate, "2012-08-23", "2012-08-23")
   627  	signedAccept(c, mysql.TypeDatetime, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03")
   628  	signedAccept(c, mysql.TypeDatetime, ZeroDatetime, "0000-00-00 00:00:00")
   629  	signedAccept(c, mysql.TypeDatetime, int64(0), "0000-00-00 00:00:00")
   630  	signedAccept(c, mysql.TypeTimestamp, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03")
   631  	signedAccept(c, mysql.TypeDuration, "10:11:12", "10:11:12")
   632  	signedAccept(c, mysql.TypeDuration, ZeroDatetime, "00:00:00")
   633  	signedAccept(c, mysql.TypeDuration, ZeroDuration, "00:00:00")
   634  	signedAccept(c, mysql.TypeDuration, 0, "00:00:00")
   635  
   636  	signedDeny(c, mysql.TypeDate, "2012-08-x", "0000-00-00")
   637  	signedDeny(c, mysql.TypeDatetime, "2012-08-x", "0000-00-00 00:00:00")
   638  	signedDeny(c, mysql.TypeTimestamp, "2012-08-x", "0000-00-00 00:00:00")
   639  	signedDeny(c, mysql.TypeDuration, "2012-08-x", "00:00:00")
   640  
   641  	// string from string
   642  	signedAccept(c, mysql.TypeString, "abc", "abc")
   643  
   644  	// string from integer
   645  	signedAccept(c, mysql.TypeString, 5678, "5678")
   646  	signedAccept(c, mysql.TypeString, ZeroDuration, "00:00:00")
   647  	signedAccept(c, mysql.TypeString, ZeroDatetime, "0000-00-00 00:00:00")
   648  	signedAccept(c, mysql.TypeString, []byte("123"), "123")
   649  
   650  	//TODO add more tests
   651  	signedAccept(c, mysql.TypeNewDecimal, 123, "123")
   652  	signedAccept(c, mysql.TypeNewDecimal, int64(123), "123")
   653  	signedAccept(c, mysql.TypeNewDecimal, uint64(123), "123")
   654  	signedAccept(c, mysql.TypeNewDecimal, float32(123), "123")
   655  	signedAccept(c, mysql.TypeNewDecimal, 123.456, "123.456")
   656  	signedAccept(c, mysql.TypeNewDecimal, "-123.456", "-123.456")
   657  	signedAccept(c, mysql.TypeNewDecimal, NewDecFromInt(12300000), "12300000")
   658  	dec := NewDecFromInt(-123)
   659  	dec.Shift(-5)
   660  	dec.Round(dec, 5, ModeHalfEven)
   661  	signedAccept(c, mysql.TypeNewDecimal, dec, "-0.00123")
   662  }
   663  
   664  func (s *testTypeConvertSuite) TestGetValidFloat(c *C) {
   665  	tests := []struct {
   666  		origin string
   667  		valid  string
   668  	}{
   669  		{"-100", "-100"},
   670  		{"1abc", "1"},
   671  		{"-1-1", "-1"},
   672  		{"+1+1", "+1"},
   673  		{"123..34", "123."},
   674  		{"123.23E-10", "123.23E-10"},
   675  		{"1.1e1.3", "1.1e1"},
   676  		{"11e1.3", "11e1"},
   677  		{"1.1e-13a", "1.1e-13"},
   678  		{"1.", "1."},
   679  		{".1", ".1"},
   680  		{"", "0"},
   681  		{"123e+", "123"},
   682  		{"123.e", "123."},
   683  	}
   684  	sc := new(stmtctx.StatementContext)
   685  	for _, tt := range tests {
   686  		prefix, _ := getValidFloatPrefix(sc, tt.origin)
   687  		c.Assert(prefix, Equals, tt.valid)
   688  		_, err := strconv.ParseFloat(prefix, 64)
   689  		c.Assert(err, IsNil)
   690  	}
   691  	floatStr, err := floatStrToIntStr(sc, "1e9223372036854775807", "1e9223372036854775807")
   692  	c.Assert(err, IsNil)
   693  	c.Assert(floatStr, Equals, "1")
   694  	floatStr, err = floatStrToIntStr(sc, "125e342", "125e342.83")
   695  	c.Assert(err, IsNil)
   696  	c.Assert(floatStr, Equals, "125")
   697  	floatStr, err = floatStrToIntStr(sc, "1e21", "1e21")
   698  	c.Assert(err, IsNil)
   699  	c.Assert(floatStr, Equals, "1")
   700  }
   701  
   702  // TestConvertTime tests time related conversion.
   703  // time conversion is complicated including Date/Datetime/Time/Timestamp etc,
   704  // Timestamp may involving timezone.
   705  func (s *testTypeConvertSuite) TestConvertTime(c *C) {
   706  	timezones := []*time.Location{
   707  		time.UTC,
   708  		time.FixedZone("", 3*3600),
   709  		time.Local,
   710  	}
   711  
   712  	for _, timezone := range timezones {
   713  		sc := &stmtctx.StatementContext{
   714  			TimeZone: timezone,
   715  		}
   716  		testConvertTimeTimeZone(c, sc)
   717  	}
   718  }
   719  
   720  func testConvertTimeTimeZone(c *C, sc *stmtctx.StatementContext) {
   721  	raw := FromDate(2002, 3, 4, 4, 6, 7, 8)
   722  	tests := []struct {
   723  		input  Time
   724  		target *FieldType
   725  		expect Time
   726  	}{
   727  		{
   728  			input:  Time{Type: mysql.TypeDatetime, Time: raw},
   729  			target: NewFieldType(mysql.TypeTimestamp),
   730  			expect: Time{Type: mysql.TypeTimestamp, Time: raw},
   731  		},
   732  		{
   733  			input:  Time{Type: mysql.TypeDatetime, Time: raw},
   734  			target: NewFieldType(mysql.TypeTimestamp),
   735  			expect: Time{Type: mysql.TypeTimestamp, Time: raw},
   736  		},
   737  		{
   738  			input:  Time{Type: mysql.TypeDatetime, Time: raw},
   739  			target: NewFieldType(mysql.TypeTimestamp),
   740  			expect: Time{Type: mysql.TypeTimestamp, Time: raw},
   741  		},
   742  		{
   743  			input:  Time{Type: mysql.TypeTimestamp, Time: raw},
   744  			target: NewFieldType(mysql.TypeDatetime),
   745  			expect: Time{Type: mysql.TypeDatetime, Time: raw},
   746  		},
   747  	}
   748  
   749  	for _, test := range tests {
   750  		var d Datum
   751  		d.SetMysqlTime(test.input)
   752  		nd, err := d.ConvertTo(sc, test.target)
   753  		c.Assert(err, IsNil)
   754  		t := nd.GetMysqlTime()
   755  		c.Assert(t.Type, Equals, test.expect.Type)
   756  		c.Assert(t.Time, Equals, test.expect.Time)
   757  	}
   758  }
   759  
   760  func (s *testTypeConvertSuite) TestConvertJSONToInt(c *C) {
   761  	var tests = []struct {
   762  		In  string
   763  		Out int64
   764  	}{
   765  		{`{}`, 0},
   766  		{`[]`, 0},
   767  		{`3`, 3},
   768  		{`-3`, -3},
   769  		{`4.5`, 5},
   770  		{`true`, 1},
   771  		{`false`, 0},
   772  		{`null`, 0},
   773  		{`"hello"`, 0},
   774  		{`"123hello"`, 123},
   775  		{`"1234"`, 1234},
   776  	}
   777  	for _, tt := range tests {
   778  		j, err := json.ParseBinaryFromString(tt.In)
   779  		c.Assert(err, IsNil)
   780  
   781  		casted, _ := ConvertJSONToInt(new(stmtctx.StatementContext), j, false)
   782  		c.Assert(casted, Equals, tt.Out)
   783  	}
   784  }
   785  
   786  func (s *testTypeConvertSuite) TestConvertJSONToFloat(c *C) {
   787  	var tests = []struct {
   788  		In  string
   789  		Out float64
   790  	}{
   791  		{`{}`, 0},
   792  		{`[]`, 0},
   793  		{`3`, 3},
   794  		{`-3`, -3},
   795  		{`4.5`, 4.5},
   796  		{`true`, 1},
   797  		{`false`, 0},
   798  		{`null`, 0},
   799  		{`"hello"`, 0},
   800  		{`"123.456hello"`, 123.456},
   801  		{`"1234"`, 1234},
   802  	}
   803  	for _, tt := range tests {
   804  		j, err := json.ParseBinaryFromString(tt.In)
   805  		c.Assert(err, IsNil)
   806  		casted, _ := ConvertJSONToFloat(new(stmtctx.StatementContext), j)
   807  		c.Assert(casted, Equals, tt.Out)
   808  	}
   809  }
   810  
   811  func (s *testTypeConvertSuite) TestConvertJSONToDecimal(c *C) {
   812  	var tests = []struct {
   813  		In  string
   814  		Out *MyDecimal
   815  	}{
   816  		{`{}`, NewDecFromStringForTest("0")},
   817  		{`[]`, NewDecFromStringForTest("0")},
   818  		{`3`, NewDecFromStringForTest("3")},
   819  		{`-3`, NewDecFromStringForTest("-3")},
   820  		{`4.5`, NewDecFromStringForTest("4.5")},
   821  		{`"1234"`, NewDecFromStringForTest("1234")},
   822  		{`"1234567890123456789012345678901234567890123456789012345"`, NewDecFromStringForTest("1234567890123456789012345678901234567890123456789012345")},
   823  	}
   824  	for _, tt := range tests {
   825  		j, err := json.ParseBinaryFromString(tt.In)
   826  		c.Assert(err, IsNil)
   827  		casted, _ := ConvertJSONToDecimal(new(stmtctx.StatementContext), j)
   828  		c.Assert(casted.Compare(tt.Out), Equals, 0)
   829  	}
   830  }
   831  
   832  func (s *testTypeConvertSuite) TestNumberToDuration(c *C) {
   833  	var testCases = []struct {
   834  		number int64
   835  		fsp    int
   836  		hasErr bool
   837  		year   int
   838  		month  int
   839  		day    int
   840  		hour   int
   841  		minute int
   842  		second int
   843  	}{
   844  		{20171222, 0, true, 0, 0, 0, 0, 0, 0},
   845  		{171222, 0, false, 0, 0, 0, 17, 12, 22},
   846  		{20171222020005, 0, false, 2017, 12, 22, 02, 00, 05},
   847  		{10000000000, 0, true, 0, 0, 0, 0, 0, 0},
   848  		{171222, 1, false, 0, 0, 0, 17, 12, 22},
   849  		{176022, 1, true, 0, 0, 0, 0, 0, 0},
   850  		{8391222, 1, true, 0, 0, 0, 0, 0, 0},
   851  		{8381222, 0, false, 0, 0, 0, 838, 12, 22},
   852  		{1001222, 0, false, 0, 0, 0, 100, 12, 22},
   853  		{171260, 1, true, 0, 0, 0, 0, 0, 0},
   854  	}
   855  
   856  	for _, tc := range testCases {
   857  		dur, err := NumberToDuration(tc.number, tc.fsp)
   858  		if tc.hasErr {
   859  			c.Assert(err, NotNil)
   860  			continue
   861  		}
   862  		c.Assert(err, IsNil)
   863  		c.Assert(dur.Hour(), Equals, tc.hour)
   864  		c.Assert(dur.Minute(), Equals, tc.minute)
   865  		c.Assert(dur.Second(), Equals, tc.second)
   866  	}
   867  
   868  	var testCases1 = []struct {
   869  		number int64
   870  		dur    time.Duration
   871  	}{
   872  		{171222, 17*time.Hour + 12*time.Minute + 22*time.Second},
   873  		{-171222, -(17*time.Hour + 12*time.Minute + 22*time.Second)},
   874  	}
   875  
   876  	for _, tc := range testCases1 {
   877  		dur, err := NumberToDuration(tc.number, 0)
   878  		c.Assert(err, IsNil)
   879  		c.Assert(dur.Duration, Equals, tc.dur)
   880  	}
   881  }