github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/field_type_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  	. "github.com/pingcap/check"
    18  
    19  	"github.com/XiaoMi/Gaea/mysql"
    20  	"github.com/XiaoMi/Gaea/util/testleak"
    21  )
    22  
    23  var _ = Suite(&testFieldTypeSuite{})
    24  
    25  type testFieldTypeSuite struct {
    26  }
    27  
    28  func (s *testFieldTypeSuite) TestFieldType(c *C) {
    29  	defer testleak.AfterTest(c)()
    30  	ft := NewFieldType(mysql.TypeDuration)
    31  	c.Assert(ft.Flen, Equals, UnspecifiedLength)
    32  	c.Assert(ft.Decimal, Equals, UnspecifiedLength)
    33  	ft.Decimal = 5
    34  	c.Assert(ft.String(), Equals, "time(5)")
    35  
    36  	ft = NewFieldType(mysql.TypeLong)
    37  	ft.Flen = 5
    38  	ft.Flag = mysql.UnsignedFlag | mysql.ZerofillFlag
    39  	c.Assert(ft.String(), Equals, "int(5) UNSIGNED ZEROFILL")
    40  	c.Assert(ft.InfoSchemaStr(), Equals, "int(5) unsigned")
    41  
    42  	ft = NewFieldType(mysql.TypeFloat)
    43  	ft.Flen = 12   // Default
    44  	ft.Decimal = 3 // Not Default
    45  	c.Assert(ft.String(), Equals, "float(12,3)")
    46  	ft = NewFieldType(mysql.TypeFloat)
    47  	ft.Flen = 12    // Default
    48  	ft.Decimal = -1 // Default
    49  	c.Assert(ft.String(), Equals, "float")
    50  	ft = NewFieldType(mysql.TypeFloat)
    51  	ft.Flen = 5     // Not Default
    52  	ft.Decimal = -1 // Default
    53  	c.Assert(ft.String(), Equals, "float")
    54  	ft = NewFieldType(mysql.TypeFloat)
    55  	ft.Flen = 7    // Not Default
    56  	ft.Decimal = 3 // Not Default
    57  	c.Assert(ft.String(), Equals, "float(7,3)")
    58  
    59  	ft = NewFieldType(mysql.TypeDouble)
    60  	ft.Flen = 22   // Default
    61  	ft.Decimal = 3 // Not Default
    62  	c.Assert(ft.String(), Equals, "double(22,3)")
    63  	ft = NewFieldType(mysql.TypeDouble)
    64  	ft.Flen = 22    // Default
    65  	ft.Decimal = -1 // Default
    66  	c.Assert(ft.String(), Equals, "double")
    67  	ft = NewFieldType(mysql.TypeDouble)
    68  	ft.Flen = 5     // Not Default
    69  	ft.Decimal = -1 // Default
    70  	c.Assert(ft.String(), Equals, "double")
    71  	ft = NewFieldType(mysql.TypeDouble)
    72  	ft.Flen = 7    // Not Default
    73  	ft.Decimal = 3 // Not Default
    74  	c.Assert(ft.String(), Equals, "double(7,3)")
    75  
    76  	ft = NewFieldType(mysql.TypeBlob)
    77  	ft.Flen = 10
    78  	ft.Charset = "UTF8"
    79  	ft.Collate = "UTF8_UNICODE_GI"
    80  	c.Assert(ft.String(), Equals, "text CHARACTER SET UTF8 COLLATE UTF8_UNICODE_GI")
    81  
    82  	ft = NewFieldType(mysql.TypeVarchar)
    83  	ft.Flen = 10
    84  	ft.Flag |= mysql.BinaryFlag
    85  	c.Assert(ft.String(), Equals, "varchar(10) BINARY")
    86  
    87  	ft = NewFieldType(mysql.TypeString)
    88  	ft.Charset = mysql.CollationBin
    89  	ft.Flag |= mysql.BinaryFlag
    90  	c.Assert(ft.String(), Equals, "binary(1)")
    91  
    92  	ft = NewFieldType(mysql.TypeEnum)
    93  	ft.Elems = []string{"a", "b"}
    94  	c.Assert(ft.String(), Equals, "enum('a','b')")
    95  
    96  	ft = NewFieldType(mysql.TypeEnum)
    97  	ft.Elems = []string{"'a'", "'b'"}
    98  	c.Assert(ft.String(), Equals, "enum('''a''','''b''')")
    99  
   100  	ft = NewFieldType(mysql.TypeEnum)
   101  	ft.Elems = []string{"a\nb", "a\tb", "a\rb"}
   102  	c.Assert(ft.String(), Equals, "enum('a\\nb','a\tb','a\\rb')")
   103  
   104  	ft = NewFieldType(mysql.TypeEnum)
   105  	ft.Elems = []string{"a\nb", "a'\t\r\nb", "a\rb"}
   106  	c.Assert(ft.String(), Equals, "enum('a\\nb','a''	\\r\\nb','a\\rb')")
   107  
   108  	ft = NewFieldType(mysql.TypeSet)
   109  	ft.Elems = []string{"a", "b"}
   110  	c.Assert(ft.String(), Equals, "set('a','b')")
   111  
   112  	ft = NewFieldType(mysql.TypeSet)
   113  	ft.Elems = []string{"'a'", "'b'"}
   114  	c.Assert(ft.String(), Equals, "set('''a''','''b''')")
   115  
   116  	ft = NewFieldType(mysql.TypeSet)
   117  	ft.Elems = []string{"a\nb", "a'\t\r\nb", "a\rb"}
   118  	c.Assert(ft.String(), Equals, "set('a\\nb','a''	\\r\\nb','a\\rb')")
   119  
   120  	ft = NewFieldType(mysql.TypeSet)
   121  	ft.Elems = []string{"a'\nb", "a'b\tc"}
   122  	c.Assert(ft.String(), Equals, "set('a''\\nb','a''b	c')")
   123  
   124  	ft = NewFieldType(mysql.TypeTimestamp)
   125  	ft.Flen = 8
   126  	ft.Decimal = 2
   127  	c.Assert(ft.String(), Equals, "timestamp(2)")
   128  	ft = NewFieldType(mysql.TypeTimestamp)
   129  	ft.Flen = 8
   130  	ft.Decimal = 0
   131  	c.Assert(ft.String(), Equals, "timestamp")
   132  
   133  	ft = NewFieldType(mysql.TypeDatetime)
   134  	ft.Flen = 8
   135  	ft.Decimal = 2
   136  	c.Assert(ft.String(), Equals, "datetime(2)")
   137  	ft = NewFieldType(mysql.TypeDatetime)
   138  	ft.Flen = 8
   139  	ft.Decimal = 0
   140  	c.Assert(ft.String(), Equals, "datetime")
   141  
   142  	ft = NewFieldType(mysql.TypeDate)
   143  	ft.Flen = 8
   144  	ft.Decimal = 2
   145  	c.Assert(ft.String(), Equals, "date")
   146  	ft = NewFieldType(mysql.TypeDate)
   147  	ft.Flen = 8
   148  	ft.Decimal = 0
   149  	c.Assert(ft.String(), Equals, "date")
   150  
   151  	ft = NewFieldType(mysql.TypeYear)
   152  	ft.Flen = 4
   153  	ft.Decimal = 0
   154  	c.Assert(ft.String(), Equals, "year")
   155  	ft = NewFieldType(mysql.TypeYear)
   156  	ft.Flen = 2
   157  	ft.Decimal = 2
   158  	c.Assert(ft.String(), Equals, "year") // Note: Invalid year.
   159  }
   160  
   161  func (s *testFieldTypeSuite) TestDefaultTypeForValue(c *C) {
   162  	defer testleak.AfterTest(c)()
   163  	tests := []struct {
   164  		value     interface{}
   165  		tp        byte
   166  		flen      int
   167  		decimal   int
   168  		charset   string
   169  		collation string
   170  		flag      uint
   171  	}{
   172  		{nil, mysql.TypeNull, 0, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   173  		{1, mysql.TypeLonglong, 1, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   174  		{uint64(1), mysql.TypeLonglong, 1, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag},
   175  		{"abc", mysql.TypeVarString, 3, UnspecifiedLength, mysql.CharsetUTF8MB4, mysql.CollationUTF8MB4, 0},
   176  		{1.1, mysql.TypeDouble, 3, -1, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   177  		{[]byte("abc"), mysql.TypeBlob, 3, UnspecifiedLength, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   178  		{HexLiteral{}, mysql.TypeVarString, 0, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag},
   179  		{BitLiteral{}, mysql.TypeVarString, 0, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   180  		{Time{Type: mysql.TypeDatetime}, mysql.TypeDatetime, 19, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   181  		{Time{
   182  			Time: FromDate(2017, 12, 12, 12, 59, 59, 0),
   183  			Type: mysql.TypeDatetime,
   184  			Fsp:  3}, mysql.TypeDatetime, 23, 3, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   185  		{Duration{}, mysql.TypeDuration, 8, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   186  		{&MyDecimal{}, mysql.TypeNewDecimal, 1, 0, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   187  		{Enum{Name: "a", Value: 1}, mysql.TypeEnum, 1, UnspecifiedLength, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   188  		{Set{Name: "a", Value: 1}, mysql.TypeSet, 1, UnspecifiedLength, mysql.CharsetBin, mysql.CharsetBin, mysql.BinaryFlag},
   189  	}
   190  	for _, tt := range tests {
   191  		var ft FieldType
   192  		DefaultTypeForValue(tt.value, &ft)
   193  		c.Assert(ft.Tp, Equals, tt.tp, Commentf("%v %v", ft.Tp, tt.tp))
   194  		c.Assert(ft.Flen, Equals, tt.flen, Commentf("%v %v", ft.Flen, tt.flen))
   195  		c.Assert(ft.Charset, Equals, tt.charset, Commentf("%v %v", ft.Charset, tt.charset))
   196  		c.Assert(ft.Decimal, Equals, tt.decimal, Commentf("%v %v", ft.Decimal, tt.decimal))
   197  		c.Assert(ft.Collate, Equals, tt.collation, Commentf("%v %v", ft.Collate, tt.collation))
   198  		c.Assert(ft.Flag, Equals, tt.flag, Commentf("%v %v", ft.Flag, tt.flag))
   199  	}
   200  }
   201  
   202  func (s *testFieldTypeSuite) TestAggFieldType(c *C) {
   203  	defer testleak.AfterTest(c)()
   204  	fts := []*FieldType{
   205  		NewFieldType(mysql.TypeDecimal),
   206  		NewFieldType(mysql.TypeTiny),
   207  		NewFieldType(mysql.TypeShort),
   208  		NewFieldType(mysql.TypeLong),
   209  		NewFieldType(mysql.TypeFloat),
   210  		NewFieldType(mysql.TypeDouble),
   211  		NewFieldType(mysql.TypeNull),
   212  		NewFieldType(mysql.TypeTimestamp),
   213  		NewFieldType(mysql.TypeLonglong),
   214  		NewFieldType(mysql.TypeInt24),
   215  		NewFieldType(mysql.TypeDate),
   216  		NewFieldType(mysql.TypeDuration),
   217  		NewFieldType(mysql.TypeDatetime),
   218  		NewFieldType(mysql.TypeYear),
   219  		NewFieldType(mysql.TypeNewDate),
   220  		NewFieldType(mysql.TypeVarchar),
   221  		NewFieldType(mysql.TypeBit),
   222  		NewFieldType(mysql.TypeJSON),
   223  		NewFieldType(mysql.TypeNewDecimal),
   224  		NewFieldType(mysql.TypeEnum),
   225  		NewFieldType(mysql.TypeSet),
   226  		NewFieldType(mysql.TypeTinyBlob),
   227  		NewFieldType(mysql.TypeMediumBlob),
   228  		NewFieldType(mysql.TypeLongBlob),
   229  		NewFieldType(mysql.TypeBlob),
   230  		NewFieldType(mysql.TypeVarString),
   231  		NewFieldType(mysql.TypeString),
   232  		NewFieldType(mysql.TypeGeometry),
   233  	}
   234  
   235  	for i := range fts {
   236  		aggTp := AggFieldType(fts[i : i+1])
   237  		c.Assert(aggTp.Tp, Equals, fts[i].Tp)
   238  
   239  		aggTp = AggFieldType([]*FieldType{fts[i], fts[i]})
   240  		switch fts[i].Tp {
   241  		case mysql.TypeDate:
   242  			c.Assert(aggTp.Tp, Equals, mysql.TypeDate)
   243  		case mysql.TypeJSON:
   244  			c.Assert(aggTp.Tp, Equals, mysql.TypeJSON)
   245  		case mysql.TypeEnum, mysql.TypeSet, mysql.TypeVarString:
   246  			c.Assert(aggTp.Tp, Equals, mysql.TypeVarchar)
   247  		case mysql.TypeDecimal:
   248  			c.Assert(aggTp.Tp, Equals, mysql.TypeNewDecimal)
   249  		default:
   250  			c.Assert(aggTp.Tp, Equals, fts[i].Tp)
   251  		}
   252  
   253  		aggTp = AggFieldType([]*FieldType{fts[i], NewFieldType(mysql.TypeLong)})
   254  		switch fts[i].Tp {
   255  		case mysql.TypeTiny, mysql.TypeShort, mysql.TypeLong,
   256  			mysql.TypeYear, mysql.TypeInt24, mysql.TypeNull:
   257  			c.Assert(aggTp.Tp, Equals, mysql.TypeLong)
   258  		case mysql.TypeLonglong:
   259  			c.Assert(aggTp.Tp, Equals, mysql.TypeLonglong)
   260  		case mysql.TypeFloat, mysql.TypeDouble:
   261  			c.Assert(aggTp.Tp, Equals, mysql.TypeDouble)
   262  		case mysql.TypeTimestamp, mysql.TypeDate, mysql.TypeDuration,
   263  			mysql.TypeDatetime, mysql.TypeNewDate, mysql.TypeVarchar,
   264  			mysql.TypeBit, mysql.TypeJSON, mysql.TypeEnum, mysql.TypeSet,
   265  			mysql.TypeVarString, mysql.TypeGeometry:
   266  			c.Assert(aggTp.Tp, Equals, mysql.TypeVarchar)
   267  		case mysql.TypeString:
   268  			c.Assert(aggTp.Tp, Equals, mysql.TypeString)
   269  		case mysql.TypeDecimal, mysql.TypeNewDecimal:
   270  			c.Assert(aggTp.Tp, Equals, mysql.TypeNewDecimal)
   271  		case mysql.TypeTinyBlob:
   272  			c.Assert(aggTp.Tp, Equals, mysql.TypeTinyBlob)
   273  		case mysql.TypeBlob:
   274  			c.Assert(aggTp.Tp, Equals, mysql.TypeBlob)
   275  		case mysql.TypeMediumBlob:
   276  			c.Assert(aggTp.Tp, Equals, mysql.TypeMediumBlob)
   277  		case mysql.TypeLongBlob:
   278  			c.Assert(aggTp.Tp, Equals, mysql.TypeLongBlob)
   279  		}
   280  
   281  		aggTp = AggFieldType([]*FieldType{fts[i], NewFieldType(mysql.TypeJSON)})
   282  		switch fts[i].Tp {
   283  		case mysql.TypeJSON, mysql.TypeNull:
   284  			c.Assert(aggTp.Tp, Equals, mysql.TypeJSON)
   285  		case mysql.TypeLongBlob, mysql.TypeMediumBlob, mysql.TypeTinyBlob, mysql.TypeBlob:
   286  			c.Assert(aggTp.Tp, Equals, mysql.TypeLongBlob)
   287  		case mysql.TypeString:
   288  			c.Assert(aggTp.Tp, Equals, mysql.TypeString)
   289  		default:
   290  			c.Assert(aggTp.Tp, Equals, mysql.TypeVarchar)
   291  		}
   292  	}
   293  }
   294  
   295  func (s *testFieldTypeSuite) TestAggregateEvalType(c *C) {
   296  	defer testleak.AfterTest(c)()
   297  	fts := []*FieldType{
   298  		NewFieldType(mysql.TypeDecimal),
   299  		NewFieldType(mysql.TypeTiny),
   300  		NewFieldType(mysql.TypeShort),
   301  		NewFieldType(mysql.TypeLong),
   302  		NewFieldType(mysql.TypeFloat),
   303  		NewFieldType(mysql.TypeDouble),
   304  		NewFieldType(mysql.TypeNull),
   305  		NewFieldType(mysql.TypeTimestamp),
   306  		NewFieldType(mysql.TypeLonglong),
   307  		NewFieldType(mysql.TypeInt24),
   308  		NewFieldType(mysql.TypeDate),
   309  		NewFieldType(mysql.TypeDuration),
   310  		NewFieldType(mysql.TypeDatetime),
   311  		NewFieldType(mysql.TypeYear),
   312  		NewFieldType(mysql.TypeNewDate),
   313  		NewFieldType(mysql.TypeVarchar),
   314  		NewFieldType(mysql.TypeBit),
   315  		NewFieldType(mysql.TypeJSON),
   316  		NewFieldType(mysql.TypeNewDecimal),
   317  		NewFieldType(mysql.TypeEnum),
   318  		NewFieldType(mysql.TypeSet),
   319  		NewFieldType(mysql.TypeTinyBlob),
   320  		NewFieldType(mysql.TypeMediumBlob),
   321  		NewFieldType(mysql.TypeLongBlob),
   322  		NewFieldType(mysql.TypeBlob),
   323  		NewFieldType(mysql.TypeVarString),
   324  		NewFieldType(mysql.TypeString),
   325  		NewFieldType(mysql.TypeGeometry),
   326  	}
   327  
   328  	for i := range fts {
   329  		var flag uint
   330  		aggregatedEvalType := AggregateEvalType(fts[i:i+1], &flag)
   331  		switch fts[i].Tp {
   332  		case mysql.TypeDecimal, mysql.TypeNull, mysql.TypeTimestamp, mysql.TypeDate,
   333  			mysql.TypeDuration, mysql.TypeDatetime, mysql.TypeNewDate, mysql.TypeVarchar,
   334  			mysql.TypeJSON, mysql.TypeEnum, mysql.TypeSet, mysql.TypeTinyBlob,
   335  			mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob,
   336  			mysql.TypeVarString, mysql.TypeString, mysql.TypeGeometry:
   337  			c.Assert(aggregatedEvalType.IsStringKind(), IsTrue)
   338  			c.Assert(flag, Equals, uint(0))
   339  		case mysql.TypeTiny, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeBit,
   340  			mysql.TypeInt24, mysql.TypeYear:
   341  			c.Assert(aggregatedEvalType, Equals, ETInt)
   342  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   343  		case mysql.TypeFloat, mysql.TypeDouble:
   344  			c.Assert(aggregatedEvalType, Equals, ETReal)
   345  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   346  		case mysql.TypeNewDecimal:
   347  			c.Assert(aggregatedEvalType, Equals, ETDecimal)
   348  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   349  		}
   350  
   351  		flag = 0
   352  		aggregatedEvalType = AggregateEvalType([]*FieldType{fts[i], fts[i]}, &flag)
   353  		switch fts[i].Tp {
   354  		case mysql.TypeDecimal, mysql.TypeNull, mysql.TypeTimestamp, mysql.TypeDate,
   355  			mysql.TypeDuration, mysql.TypeDatetime, mysql.TypeNewDate, mysql.TypeVarchar,
   356  			mysql.TypeJSON, mysql.TypeEnum, mysql.TypeSet, mysql.TypeTinyBlob,
   357  			mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob,
   358  			mysql.TypeVarString, mysql.TypeString, mysql.TypeGeometry:
   359  			c.Assert(aggregatedEvalType.IsStringKind(), IsTrue)
   360  			c.Assert(flag, Equals, uint(0))
   361  		case mysql.TypeTiny, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeBit,
   362  			mysql.TypeInt24, mysql.TypeYear:
   363  			c.Assert(aggregatedEvalType, Equals, ETInt)
   364  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   365  		case mysql.TypeFloat, mysql.TypeDouble:
   366  			c.Assert(aggregatedEvalType, Equals, ETReal)
   367  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   368  		case mysql.TypeNewDecimal:
   369  			c.Assert(aggregatedEvalType, Equals, ETDecimal)
   370  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   371  		}
   372  		flag = 0
   373  		aggregatedEvalType = AggregateEvalType([]*FieldType{fts[i], NewFieldType(mysql.TypeLong)}, &flag)
   374  		switch fts[i].Tp {
   375  		case mysql.TypeTimestamp, mysql.TypeDate, mysql.TypeDuration,
   376  			mysql.TypeDatetime, mysql.TypeNewDate, mysql.TypeVarchar, mysql.TypeJSON,
   377  			mysql.TypeEnum, mysql.TypeSet, mysql.TypeTinyBlob, mysql.TypeMediumBlob,
   378  			mysql.TypeLongBlob, mysql.TypeBlob, mysql.TypeVarString,
   379  			mysql.TypeString, mysql.TypeGeometry:
   380  			c.Assert(aggregatedEvalType.IsStringKind(), IsTrue)
   381  			c.Assert(flag, Equals, uint(0))
   382  		case mysql.TypeDecimal, mysql.TypeTiny, mysql.TypeShort, mysql.TypeLong, mysql.TypeNull, mysql.TypeBit,
   383  			mysql.TypeLonglong, mysql.TypeYear, mysql.TypeInt24:
   384  			c.Assert(aggregatedEvalType, Equals, ETInt)
   385  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   386  		case mysql.TypeFloat, mysql.TypeDouble:
   387  			c.Assert(aggregatedEvalType, Equals, ETReal)
   388  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   389  		case mysql.TypeNewDecimal:
   390  			c.Assert(aggregatedEvalType, Equals, ETDecimal)
   391  			c.Assert(flag, Equals, uint(mysql.BinaryFlag))
   392  		}
   393  	}
   394  }