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