vitess.io/vitess@v0.16.2/go/sqltypes/type_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sqltypes
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	querypb "vitess.io/vitess/go/vt/proto/query"
    24  )
    25  
    26  func TestTypeValues(t *testing.T) {
    27  	testcases := []struct {
    28  		defined  querypb.Type
    29  		expected int
    30  	}{{
    31  		defined:  Null,
    32  		expected: 0,
    33  	}, {
    34  		defined:  Int8,
    35  		expected: 1 | flagIsIntegral,
    36  	}, {
    37  		defined:  Uint8,
    38  		expected: 2 | flagIsIntegral | flagIsUnsigned,
    39  	}, {
    40  		defined:  Int16,
    41  		expected: 3 | flagIsIntegral,
    42  	}, {
    43  		defined:  Uint16,
    44  		expected: 4 | flagIsIntegral | flagIsUnsigned,
    45  	}, {
    46  		defined:  Int24,
    47  		expected: 5 | flagIsIntegral,
    48  	}, {
    49  		defined:  Uint24,
    50  		expected: 6 | flagIsIntegral | flagIsUnsigned,
    51  	}, {
    52  		defined:  Int32,
    53  		expected: 7 | flagIsIntegral,
    54  	}, {
    55  		defined:  Uint32,
    56  		expected: 8 | flagIsIntegral | flagIsUnsigned,
    57  	}, {
    58  		defined:  Int64,
    59  		expected: 9 | flagIsIntegral,
    60  	}, {
    61  		defined:  Uint64,
    62  		expected: 10 | flagIsIntegral | flagIsUnsigned,
    63  	}, {
    64  		defined:  Float32,
    65  		expected: 11 | flagIsFloat,
    66  	}, {
    67  		defined:  Float64,
    68  		expected: 12 | flagIsFloat,
    69  	}, {
    70  		defined:  Timestamp,
    71  		expected: 13 | flagIsQuoted,
    72  	}, {
    73  		defined:  Date,
    74  		expected: 14 | flagIsQuoted,
    75  	}, {
    76  		defined:  Time,
    77  		expected: 15 | flagIsQuoted,
    78  	}, {
    79  		defined:  Datetime,
    80  		expected: 16 | flagIsQuoted,
    81  	}, {
    82  		defined:  Year,
    83  		expected: 17 | flagIsIntegral | flagIsUnsigned,
    84  	}, {
    85  		defined:  Decimal,
    86  		expected: 18,
    87  	}, {
    88  		defined:  Text,
    89  		expected: 19 | flagIsQuoted | flagIsText,
    90  	}, {
    91  		defined:  Blob,
    92  		expected: 20 | flagIsQuoted | flagIsBinary,
    93  	}, {
    94  		defined:  VarChar,
    95  		expected: 21 | flagIsQuoted | flagIsText,
    96  	}, {
    97  		defined:  VarBinary,
    98  		expected: 22 | flagIsQuoted | flagIsBinary,
    99  	}, {
   100  		defined:  Char,
   101  		expected: 23 | flagIsQuoted | flagIsText,
   102  	}, {
   103  		defined:  Binary,
   104  		expected: 24 | flagIsQuoted | flagIsBinary,
   105  	}, {
   106  		defined:  Bit,
   107  		expected: 25 | flagIsQuoted,
   108  	}, {
   109  		defined:  Enum,
   110  		expected: 26 | flagIsQuoted,
   111  	}, {
   112  		defined:  Set,
   113  		expected: 27 | flagIsQuoted,
   114  	}, {
   115  		defined:  Geometry,
   116  		expected: 29 | flagIsQuoted,
   117  	}, {
   118  		defined:  TypeJSON,
   119  		expected: 30 | flagIsQuoted,
   120  	}, {
   121  		defined:  Expression,
   122  		expected: 31,
   123  	}, {
   124  		defined:  HexNum,
   125  		expected: 32 | flagIsText,
   126  	}, {
   127  		defined:  HexVal,
   128  		expected: 33 | flagIsText,
   129  	}, {
   130  		defined:  BitNum,
   131  		expected: 34 | flagIsText,
   132  	}}
   133  	for _, tcase := range testcases {
   134  		if int(tcase.defined) != tcase.expected {
   135  			t.Errorf("Type %s: %d, want: %d", tcase.defined, int(tcase.defined), tcase.expected)
   136  		}
   137  	}
   138  }
   139  
   140  // TestCategory verifies that the type categorizations
   141  // are non-overlapping and complete.
   142  func TestCategory(t *testing.T) {
   143  	alltypes := []querypb.Type{
   144  		Null,
   145  		Int8,
   146  		Uint8,
   147  		Int16,
   148  		Uint16,
   149  		Int24,
   150  		Uint24,
   151  		Int32,
   152  		Uint32,
   153  		Int64,
   154  		Uint64,
   155  		Float32,
   156  		Float64,
   157  		Timestamp,
   158  		Date,
   159  		Time,
   160  		Datetime,
   161  		Year,
   162  		Decimal,
   163  		Text,
   164  		Blob,
   165  		VarChar,
   166  		VarBinary,
   167  		Char,
   168  		Binary,
   169  		Bit,
   170  		Enum,
   171  		Set,
   172  		Geometry,
   173  		TypeJSON,
   174  		Expression,
   175  		HexNum,
   176  		HexVal,
   177  		BitNum,
   178  	}
   179  	for _, typ := range alltypes {
   180  		matched := false
   181  		if IsSigned(typ) {
   182  			if !IsIntegral(typ) {
   183  				t.Errorf("Signed type %v is not an integral", typ)
   184  			}
   185  			matched = true
   186  		}
   187  		if IsUnsigned(typ) {
   188  			if !IsIntegral(typ) {
   189  				t.Errorf("Unsigned type %v is not an integral", typ)
   190  			}
   191  			if matched {
   192  				t.Errorf("%v matched more than one category", typ)
   193  			}
   194  			matched = true
   195  		}
   196  		if IsFloat(typ) {
   197  			if matched {
   198  				t.Errorf("%v matched more than one category", typ)
   199  			}
   200  			matched = true
   201  		}
   202  		if IsQuoted(typ) {
   203  			if matched {
   204  				t.Errorf("%v matched more than one category", typ)
   205  			}
   206  			matched = true
   207  		}
   208  		if typ == Null || typ == Decimal || typ == Expression || typ == Bit ||
   209  			typ == HexNum || typ == HexVal || typ == BitNum {
   210  			if matched {
   211  				t.Errorf("%v matched more than one category", typ)
   212  			}
   213  			matched = true
   214  		}
   215  		if !matched {
   216  			t.Errorf("%v matched no category", typ)
   217  		}
   218  	}
   219  }
   220  
   221  func TestIsFunctions(t *testing.T) {
   222  	if IsIntegral(Null) {
   223  		t.Error("Null: IsIntegral, must be false")
   224  	}
   225  	if !IsIntegral(Int64) {
   226  		t.Error("Int64: !IsIntegral, must be true")
   227  	}
   228  	if IsSigned(Uint64) {
   229  		t.Error("Uint64: IsSigned, must be false")
   230  	}
   231  	if !IsSigned(Int64) {
   232  		t.Error("Int64: !IsSigned, must be true")
   233  	}
   234  	if IsUnsigned(Int64) {
   235  		t.Error("Int64: IsUnsigned, must be false")
   236  	}
   237  	if !IsUnsigned(Uint64) {
   238  		t.Error("Uint64: !IsUnsigned, must be true")
   239  	}
   240  	if IsFloat(Int64) {
   241  		t.Error("Int64: IsFloat, must be false")
   242  	}
   243  	if !IsFloat(Float64) {
   244  		t.Error("Uint64: !IsFloat, must be true")
   245  	}
   246  	if IsQuoted(Int64) {
   247  		t.Error("Int64: IsQuoted, must be false")
   248  	}
   249  	if !IsQuoted(Binary) {
   250  		t.Error("Binary: !IsQuoted, must be true")
   251  	}
   252  	if IsText(Int64) {
   253  		t.Error("Int64: IsText, must be false")
   254  	}
   255  	if !IsText(Char) {
   256  		t.Error("Char: !IsText, must be true")
   257  	}
   258  	if IsBinary(Int64) {
   259  		t.Error("Int64: IsBinary, must be false")
   260  	}
   261  	if !IsBinary(Binary) {
   262  		t.Error("Char: !IsBinary, must be true")
   263  	}
   264  	if !IsNumber(Int64) {
   265  		t.Error("Int64: !isNumber, must be true")
   266  	}
   267  }
   268  
   269  func TestTypeToMySQL(t *testing.T) {
   270  	v, f := TypeToMySQL(Bit)
   271  	if v != 16 {
   272  		t.Errorf("Bit: %d, want 16", v)
   273  	}
   274  	if f != mysqlUnsigned {
   275  		t.Errorf("Bit flag: %x, want %x", f, mysqlUnsigned)
   276  	}
   277  	v, f = TypeToMySQL(Date)
   278  	if v != 10 {
   279  		t.Errorf("Bit: %d, want 10", v)
   280  	}
   281  	if f != mysqlBinary {
   282  		t.Errorf("Bit flag: %x, want %x", f, mysqlBinary)
   283  	}
   284  }
   285  
   286  func TestMySQLToType(t *testing.T) {
   287  	testcases := []struct {
   288  		intype  int64
   289  		inflags int64
   290  		outtype querypb.Type
   291  	}{{
   292  		intype:  1,
   293  		outtype: Int8,
   294  	}, {
   295  		intype:  1,
   296  		inflags: mysqlUnsigned,
   297  		outtype: Uint8,
   298  	}, {
   299  		intype:  2,
   300  		outtype: Int16,
   301  	}, {
   302  		intype:  2,
   303  		inflags: mysqlUnsigned,
   304  		outtype: Uint16,
   305  	}, {
   306  		intype:  3,
   307  		outtype: Int32,
   308  	}, {
   309  		intype:  3,
   310  		inflags: mysqlUnsigned,
   311  		outtype: Uint32,
   312  	}, {
   313  		intype:  4,
   314  		outtype: Float32,
   315  	}, {
   316  		intype:  5,
   317  		outtype: Float64,
   318  	}, {
   319  		intype:  6,
   320  		outtype: Null,
   321  	}, {
   322  		intype:  7,
   323  		outtype: Timestamp,
   324  	}, {
   325  		intype:  8,
   326  		outtype: Int64,
   327  	}, {
   328  		intype:  8,
   329  		inflags: mysqlUnsigned,
   330  		outtype: Uint64,
   331  	}, {
   332  		intype:  9,
   333  		outtype: Int24,
   334  	}, {
   335  		intype:  9,
   336  		inflags: mysqlUnsigned,
   337  		outtype: Uint24,
   338  	}, {
   339  		intype:  10,
   340  		outtype: Date,
   341  	}, {
   342  		intype:  11,
   343  		outtype: Time,
   344  	}, {
   345  		intype:  12,
   346  		outtype: Datetime,
   347  	}, {
   348  		intype:  13,
   349  		outtype: Year,
   350  	}, {
   351  		intype:  16,
   352  		outtype: Bit,
   353  	}, {
   354  		intype:  245,
   355  		outtype: TypeJSON,
   356  	}, {
   357  		intype:  246,
   358  		outtype: Decimal,
   359  	}, {
   360  		intype:  249,
   361  		outtype: Text,
   362  	}, {
   363  		intype:  250,
   364  		outtype: Text,
   365  	}, {
   366  		intype:  251,
   367  		outtype: Text,
   368  	}, {
   369  		intype:  252,
   370  		outtype: Text,
   371  	}, {
   372  		intype:  252,
   373  		inflags: mysqlBinary,
   374  		outtype: Blob,
   375  	}, {
   376  		intype:  253,
   377  		outtype: VarChar,
   378  	}, {
   379  		intype:  253,
   380  		inflags: mysqlBinary,
   381  		outtype: VarBinary,
   382  	}, {
   383  		intype:  254,
   384  		outtype: Char,
   385  	}, {
   386  		intype:  254,
   387  		inflags: mysqlBinary,
   388  		outtype: Binary,
   389  	}, {
   390  		intype:  254,
   391  		inflags: mysqlEnum,
   392  		outtype: Enum,
   393  	}, {
   394  		intype:  254,
   395  		inflags: mysqlSet,
   396  		outtype: Set,
   397  	}, {
   398  		intype:  255,
   399  		outtype: Geometry,
   400  	}, {
   401  		// Binary flag must be ignored.
   402  		intype:  8,
   403  		inflags: mysqlUnsigned | mysqlBinary,
   404  		outtype: Uint64,
   405  	}, {
   406  		// Unsigned flag must be ignored
   407  		intype:  252,
   408  		inflags: mysqlUnsigned | mysqlBinary,
   409  		outtype: Blob,
   410  	}}
   411  	for _, tcase := range testcases {
   412  		got, err := MySQLToType(tcase.intype, tcase.inflags)
   413  		if err != nil {
   414  			t.Error(err)
   415  		}
   416  		if got != tcase.outtype {
   417  			t.Errorf("MySQLToType(%d, %x): %v, want %v", tcase.intype, tcase.inflags, got, tcase.outtype)
   418  		}
   419  	}
   420  }
   421  
   422  func TestTypeError(t *testing.T) {
   423  	_, err := MySQLToType(50, 0)
   424  	want := "unsupported type: 50"
   425  	if err == nil || err.Error() != want {
   426  		t.Errorf("MySQLToType: %v, want %s", err, want)
   427  	}
   428  }
   429  
   430  func TestTypeEquivalenceCheck(t *testing.T) {
   431  	if !AreTypesEquivalent(Int16, Int16) {
   432  		t.Errorf("Int16 and Int16 are same types.")
   433  	}
   434  	if AreTypesEquivalent(Int16, Int24) {
   435  		t.Errorf("Int16 and Int24 are not same types.")
   436  	}
   437  	if !AreTypesEquivalent(VarChar, VarBinary) {
   438  		t.Errorf("VarChar in binlog and VarBinary in schema are equivalent types.")
   439  	}
   440  	if AreTypesEquivalent(VarBinary, VarChar) {
   441  		t.Errorf("VarBinary in binlog and VarChar in schema are not equivalent types.")
   442  	}
   443  	if !AreTypesEquivalent(Int16, Uint16) {
   444  		t.Errorf("Int16 in binlog and Uint16 in schema are equivalent types.")
   445  	}
   446  	if AreTypesEquivalent(Uint16, Int16) {
   447  		t.Errorf("Uint16 in binlog and Int16 in schema are not equivalent types.")
   448  	}
   449  }
   450  
   451  func TestPrintTypeChecks(t *testing.T) {
   452  	var funcs = []struct {
   453  		name string
   454  		f    func(p Type) bool
   455  	}{
   456  		{"IsSigned", IsSigned},
   457  		{"IsFloat", IsFloat},
   458  		{"IsUnsigned", IsUnsigned},
   459  		{"IsIntegral", IsIntegral},
   460  		{"IsText", IsText},
   461  		{"IsNumber", IsNumber},
   462  		{"IsQuoted", IsQuoted},
   463  		{"IsBinary", IsBinary},
   464  		{"IsDate", IsDate},
   465  		{"IsNull", IsNull},
   466  	}
   467  	var types = []Type{
   468  		Null,
   469  		Int8,
   470  		Uint8,
   471  		Int16,
   472  		Uint16,
   473  		Int24,
   474  		Uint24,
   475  		Int32,
   476  		Uint32,
   477  		Int64,
   478  		Uint64,
   479  		Float32,
   480  		Float64,
   481  		Timestamp,
   482  		Date,
   483  		Time,
   484  		Datetime,
   485  		Year,
   486  		Decimal,
   487  		Text,
   488  		Blob,
   489  		VarChar,
   490  		VarBinary,
   491  		Char,
   492  		Binary,
   493  		Bit,
   494  		Enum,
   495  		Set,
   496  		Geometry,
   497  		TypeJSON,
   498  		Expression,
   499  		HexNum,
   500  		HexVal,
   501  		Tuple,
   502  		BitNum,
   503  	}
   504  
   505  	for _, f := range funcs {
   506  		var match []string
   507  		for _, tt := range types {
   508  			if f.f(tt) {
   509  				match = append(match, tt.String())
   510  			}
   511  		}
   512  		t.Logf("%s(): %s", f.name, strings.Join(match, ", "))
   513  	}
   514  }