github.com/vedadiyan/sqlparser@v1.0.0/pkg/sqltypes/type.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  	"fmt"
    21  
    22  	querypb "github.com/vedadiyan/sqlparser/pkg/query"
    23  )
    24  
    25  type Type = querypb.Type
    26  
    27  // This file provides wrappers and support
    28  // functions for querypb.Type.
    29  
    30  // These bit flags can be used to query on the
    31  // common properties of types.
    32  const (
    33  	flagIsIntegral = int(querypb.Flag_ISINTEGRAL)
    34  	flagIsUnsigned = int(querypb.Flag_ISUNSIGNED)
    35  	flagIsFloat    = int(querypb.Flag_ISFLOAT)
    36  	flagIsQuoted   = int(querypb.Flag_ISQUOTED)
    37  	flagIsText     = int(querypb.Flag_ISTEXT)
    38  	flagIsBinary   = int(querypb.Flag_ISBINARY)
    39  )
    40  
    41  const (
    42  	TimestampFormat           = "2006-01-02 15:04:05"
    43  	TimestampFormatPrecision3 = "2006-01-02 15:04:05.000"
    44  	TimestampFormatPrecision6 = "2006-01-02 15:04:05.000000"
    45  )
    46  
    47  // IsIntegral returns true if querypb.Type is an integral
    48  // (signed/unsigned) that can be represented using
    49  // up to 64 binary bits.
    50  // If you have a Value object, use its member function.
    51  func IsIntegral(t querypb.Type) bool {
    52  	return int(t)&flagIsIntegral == flagIsIntegral
    53  }
    54  
    55  // IsSigned returns true if querypb.Type is a signed integral.
    56  // If you have a Value object, use its member function.
    57  func IsSigned(t querypb.Type) bool {
    58  	return int(t)&(flagIsIntegral|flagIsUnsigned) == flagIsIntegral
    59  }
    60  
    61  // IsUnsigned returns true if querypb.Type is an unsigned integral.
    62  // Caution: this is not the same as !IsSigned.
    63  // If you have a Value object, use its member function.
    64  func IsUnsigned(t querypb.Type) bool {
    65  	return int(t)&(flagIsIntegral|flagIsUnsigned) == flagIsIntegral|flagIsUnsigned
    66  }
    67  
    68  // IsFloat returns true is querypb.Type is a floating point.
    69  // If you have a Value object, use its member function.
    70  func IsFloat(t querypb.Type) bool {
    71  	return int(t)&flagIsFloat == flagIsFloat
    72  }
    73  
    74  // IsQuoted returns true if querypb.Type is a quoted text or binary.
    75  // If you have a Value object, use its member function.
    76  func IsQuoted(t querypb.Type) bool {
    77  	return (int(t)&flagIsQuoted == flagIsQuoted) && t != Bit
    78  }
    79  
    80  // IsText returns true if querypb.Type is a text.
    81  // If you have a Value object, use its member function.
    82  func IsText(t querypb.Type) bool {
    83  	return int(t)&flagIsText == flagIsText
    84  }
    85  
    86  // IsBinary returns true if querypb.Type is a binary.
    87  // If you have a Value object, use its member function.
    88  func IsBinary(t querypb.Type) bool {
    89  	return int(t)&flagIsBinary == flagIsBinary
    90  }
    91  
    92  // IsNumber returns true if the type is any type of number.
    93  func IsNumber(t querypb.Type) bool {
    94  	return IsIntegral(t) || IsFloat(t) || t == Decimal
    95  }
    96  
    97  // IsDate returns true if the type represents a date and/or time.
    98  func IsDate(t querypb.Type) bool {
    99  	return t == Datetime || t == Date || t == Timestamp || t == Time
   100  }
   101  
   102  // IsNull returns true if the type is NULL type
   103  func IsNull(t querypb.Type) bool {
   104  	return t == Null
   105  }
   106  
   107  // Vitess data types. These are idiomatically named synonyms for the querypb.Type values.
   108  // Although these constants are interchangeable, they should be treated as different from querypb.Type.
   109  // Use the synonyms only to refer to the type in Value. For proto variables, use the querypb.Type constants instead.
   110  // The following is a complete listing of types that match each classification function in this API:
   111  //
   112  //	IsSigned(): INT8, INT16, INT24, INT32, INT64
   113  //	IsFloat(): FLOAT32, FLOAT64
   114  //	IsUnsigned(): UINT8, UINT16, UINT24, UINT32, UINT64, YEAR
   115  //	IsIntegral(): INT8, UINT8, INT16, UINT16, INT24, UINT24, INT32, UINT32, INT64, UINT64, YEAR
   116  //	IsText(): TEXT, VARCHAR, CHAR, HEXNUM, HEXVAL, BITNUM
   117  //	IsNumber(): INT8, UINT8, INT16, UINT16, INT24, UINT24, INT32, UINT32, INT64, UINT64, FLOAT32, FLOAT64, YEAR, DECIMAL
   118  //	IsQuoted(): TIMESTAMP, DATE, TIME, DATETIME, TEXT, BLOB, VARCHAR, VARBINARY, CHAR, BINARY, ENUM, SET, GEOMETRY, JSON
   119  //	IsBinary(): BLOB, VARBINARY, BINARY
   120  //	IsDate(): TIMESTAMP, DATE, TIME, DATETIME
   121  //	IsNull(): NULL_TYPE
   122  //
   123  // TODO(sougou): provide a categorization function
   124  // that returns enums, which will allow for cleaner
   125  // switch statements for those who want to cover types
   126  // by their category.
   127  const (
   128  	Null       = querypb.Type_NULL_TYPE
   129  	Int8       = querypb.Type_INT8
   130  	Uint8      = querypb.Type_UINT8
   131  	Int16      = querypb.Type_INT16
   132  	Uint16     = querypb.Type_UINT16
   133  	Int24      = querypb.Type_INT24
   134  	Uint24     = querypb.Type_UINT24
   135  	Int32      = querypb.Type_INT32
   136  	Uint32     = querypb.Type_UINT32
   137  	Int64      = querypb.Type_INT64
   138  	Uint64     = querypb.Type_UINT64
   139  	Float32    = querypb.Type_FLOAT32
   140  	Float64    = querypb.Type_FLOAT64
   141  	Timestamp  = querypb.Type_TIMESTAMP
   142  	Date       = querypb.Type_DATE
   143  	Time       = querypb.Type_TIME
   144  	Datetime   = querypb.Type_DATETIME
   145  	Year       = querypb.Type_YEAR
   146  	Decimal    = querypb.Type_DECIMAL
   147  	Text       = querypb.Type_TEXT
   148  	Blob       = querypb.Type_BLOB
   149  	VarChar    = querypb.Type_VARCHAR
   150  	VarBinary  = querypb.Type_VARBINARY
   151  	Char       = querypb.Type_CHAR
   152  	Binary     = querypb.Type_BINARY
   153  	Bit        = querypb.Type_BIT
   154  	Enum       = querypb.Type_ENUM
   155  	Set        = querypb.Type_SET
   156  	Geometry   = querypb.Type_GEOMETRY
   157  	TypeJSON   = querypb.Type_JSON
   158  	Expression = querypb.Type_EXPRESSION
   159  	HexNum     = querypb.Type_HEXNUM
   160  	HexVal     = querypb.Type_HEXVAL
   161  	Tuple      = querypb.Type_TUPLE
   162  	BitNum     = querypb.Type_BITNUM
   163  )
   164  
   165  // bit-shift the mysql flags by two byte so we
   166  // can merge them with the mysql or vitess types.
   167  const (
   168  	mysqlUnsigned = 32
   169  	mysqlBinary   = 128
   170  	mysqlEnum     = 256
   171  	mysqlSet      = 2048
   172  )
   173  
   174  // If you add to this map, make sure you add a test case
   175  // in tabletserver/endtoend.
   176  var mysqlToType = map[int64]querypb.Type{
   177  	0:   Decimal,
   178  	1:   Int8,
   179  	2:   Int16,
   180  	3:   Int32,
   181  	4:   Float32,
   182  	5:   Float64,
   183  	6:   Null,
   184  	7:   Timestamp,
   185  	8:   Int64,
   186  	9:   Int24,
   187  	10:  Date,
   188  	11:  Time,
   189  	12:  Datetime,
   190  	13:  Year,
   191  	15:  VarChar,
   192  	16:  Bit,
   193  	17:  Timestamp,
   194  	18:  Datetime,
   195  	19:  Time,
   196  	245: TypeJSON,
   197  	246: Decimal,
   198  	247: Enum,
   199  	248: Set,
   200  	249: Text,
   201  	250: Text,
   202  	251: Text,
   203  	252: Text,
   204  	253: VarChar,
   205  	254: Char,
   206  	255: Geometry,
   207  }
   208  
   209  // modifyType modifies the vitess type based on the
   210  // mysql flag. The function checks specific flags based
   211  // on the type. This allows us to ignore stray flags
   212  // that MySQL occasionally sets.
   213  func modifyType(typ querypb.Type, flags int64) querypb.Type {
   214  	switch typ {
   215  	case Int8:
   216  		if flags&mysqlUnsigned != 0 {
   217  			return Uint8
   218  		}
   219  	case Int16:
   220  		if flags&mysqlUnsigned != 0 {
   221  			return Uint16
   222  		}
   223  	case Int32:
   224  		if flags&mysqlUnsigned != 0 {
   225  			return Uint32
   226  		}
   227  	case Int64:
   228  		if flags&mysqlUnsigned != 0 {
   229  			return Uint64
   230  		}
   231  	case Int24:
   232  		if flags&mysqlUnsigned != 0 {
   233  			return Uint24
   234  		}
   235  	case Text:
   236  		if flags&mysqlBinary != 0 {
   237  			return Blob
   238  		}
   239  	case VarChar:
   240  		if flags&mysqlBinary != 0 {
   241  			return VarBinary
   242  		}
   243  	case Char:
   244  		if flags&mysqlBinary != 0 {
   245  			return Binary
   246  		}
   247  		if flags&mysqlEnum != 0 {
   248  			return Enum
   249  		}
   250  		if flags&mysqlSet != 0 {
   251  			return Set
   252  		}
   253  	case Year:
   254  		if flags&mysqlBinary != 0 {
   255  			return VarBinary
   256  		}
   257  	}
   258  	return typ
   259  }
   260  
   261  // MySQLToType computes the vitess type from mysql type and flags.
   262  func MySQLToType(mysqlType, flags int64) (typ querypb.Type, err error) {
   263  	result, ok := mysqlToType[mysqlType]
   264  	if !ok {
   265  		return 0, fmt.Errorf("unsupported type: %d", mysqlType)
   266  	}
   267  	return modifyType(result, flags), nil
   268  }
   269  
   270  // AreTypesEquivalent returns whether two types are equivalent.
   271  func AreTypesEquivalent(mysqlTypeFromBinlog, mysqlTypeFromSchema querypb.Type) bool {
   272  	return (mysqlTypeFromBinlog == mysqlTypeFromSchema) ||
   273  		(mysqlTypeFromBinlog == VarChar && mysqlTypeFromSchema == VarBinary) ||
   274  		// Binlog only has base type. But doesn't have per-column-flags to differentiate
   275  		// various logical types. For Binary, Enum, Set types, binlog only returns Char
   276  		// as data type.
   277  		(mysqlTypeFromBinlog == Char && mysqlTypeFromSchema == Binary) ||
   278  		(mysqlTypeFromBinlog == Char && mysqlTypeFromSchema == Enum) ||
   279  		(mysqlTypeFromBinlog == Char && mysqlTypeFromSchema == Set) ||
   280  		(mysqlTypeFromBinlog == Text && mysqlTypeFromSchema == Blob) ||
   281  		(mysqlTypeFromBinlog == Int8 && mysqlTypeFromSchema == Uint8) ||
   282  		(mysqlTypeFromBinlog == Int16 && mysqlTypeFromSchema == Uint16) ||
   283  		(mysqlTypeFromBinlog == Int24 && mysqlTypeFromSchema == Uint24) ||
   284  		(mysqlTypeFromBinlog == Int32 && mysqlTypeFromSchema == Uint32) ||
   285  		(mysqlTypeFromBinlog == Int64 && mysqlTypeFromSchema == Uint64)
   286  }
   287  
   288  // typeToMySQL is the reverse of mysqlToType.
   289  var typeToMySQL = map[querypb.Type]struct {
   290  	typ   int64
   291  	flags int64
   292  }{
   293  	Int8:      {typ: 1},
   294  	Uint8:     {typ: 1, flags: mysqlUnsigned},
   295  	Int16:     {typ: 2},
   296  	Uint16:    {typ: 2, flags: mysqlUnsigned},
   297  	Int32:     {typ: 3},
   298  	Uint32:    {typ: 3, flags: mysqlUnsigned},
   299  	Float32:   {typ: 4},
   300  	Float64:   {typ: 5},
   301  	Null:      {typ: 6, flags: mysqlBinary},
   302  	Timestamp: {typ: 7},
   303  	Int64:     {typ: 8},
   304  	Uint64:    {typ: 8, flags: mysqlUnsigned},
   305  	Int24:     {typ: 9},
   306  	Uint24:    {typ: 9, flags: mysqlUnsigned},
   307  	Date:      {typ: 10, flags: mysqlBinary},
   308  	Time:      {typ: 11, flags: mysqlBinary},
   309  	Datetime:  {typ: 12, flags: mysqlBinary},
   310  	Year:      {typ: 13, flags: mysqlUnsigned},
   311  	Bit:       {typ: 16, flags: mysqlUnsigned},
   312  	TypeJSON:  {typ: 245},
   313  	Decimal:   {typ: 246},
   314  	Text:      {typ: 252},
   315  	Blob:      {typ: 252, flags: mysqlBinary},
   316  	BitNum:    {typ: 253, flags: mysqlBinary},
   317  	HexNum:    {typ: 253, flags: mysqlBinary},
   318  	HexVal:    {typ: 253, flags: mysqlBinary},
   319  	VarChar:   {typ: 253},
   320  	VarBinary: {typ: 253, flags: mysqlBinary},
   321  	Char:      {typ: 254},
   322  	Binary:    {typ: 254, flags: mysqlBinary},
   323  	Enum:      {typ: 254, flags: mysqlEnum},
   324  	Set:       {typ: 254, flags: mysqlSet},
   325  	Geometry:  {typ: 255},
   326  }
   327  
   328  // TypeToMySQL returns the equivalent mysql type and flag for a vitess type.
   329  func TypeToMySQL(typ querypb.Type) (mysqlType, flags int64) {
   330  	val := typeToMySQL[typ]
   331  	return val.typ, val.flags
   332  }