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 }