github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/types/field_type.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 "encoding/json" 18 "fmt" 19 "io" 20 "strings" 21 "unsafe" 22 23 "github.com/cznic/mathutil" 24 "github.com/pingcap/tidb/parser/charset" 25 "github.com/pingcap/tidb/parser/format" 26 "github.com/pingcap/tidb/parser/mysql" 27 ) 28 29 // UnspecifiedLength is unspecified length. 30 const ( 31 UnspecifiedLength = -1 32 ) 33 34 // TiDBStrictIntegerDisplayWidth represent whether return warnings when integerType with (length) was parsed. 35 // The default is `false`, it will be parsed as warning, and the result in show-create-table will ignore the 36 // display length when it set to `true`. This is for compatibility with MySQL 8.0 in which integer max display 37 // length is deprecated, referring this issue #6688 for more details. 38 var ( 39 TiDBStrictIntegerDisplayWidth bool 40 ) 41 42 // FieldType records field type information. 43 type FieldType struct { 44 // tp is type of the field 45 tp byte 46 // flag represent NotNull, Unsigned, PriKey flags etc. 47 flag uint 48 // flen represent size of bytes of the field 49 flen int 50 // decimal represent decimal length of the field 51 decimal int 52 // charset represent character set 53 charset string 54 // collate represent collate rules of the charset 55 collate string 56 // elems is the element list for enum and set type. 57 elems []string 58 elemsIsBinaryLit []bool 59 array bool 60 // Please keep in mind that jsonFieldType should be updated if you add a new field here. 61 } 62 63 // NewFieldType returns a FieldType, 64 // with a type and other information about field type. 65 func NewFieldType(tp byte) *FieldType { 66 return &FieldType{ 67 tp: tp, 68 flen: UnspecifiedLength, 69 decimal: UnspecifiedLength, 70 } 71 } 72 73 // IsDecimalValid checks whether the decimal is valid. 74 func (ft *FieldType) IsDecimalValid() bool { 75 if ft.GetType() == mysql.TypeNewDecimal && (ft.decimal < 0 || ft.decimal > mysql.MaxDecimalScale || ft.flen <= 0 || ft.flen > mysql.MaxDecimalWidth || ft.flen < ft.decimal) { 76 return false 77 } 78 return true 79 } 80 81 // IsVarLengthType Determine whether the column type is a variable-length type 82 func (ft *FieldType) IsVarLengthType() bool { 83 switch ft.GetType() { 84 case mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeJSON, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: 85 return true 86 default: 87 return false 88 } 89 } 90 91 // GetType returns the type of the FieldType. 92 func (ft *FieldType) GetType() byte { 93 if ft.array { 94 return mysql.TypeJSON 95 } 96 return ft.tp 97 } 98 99 // GetFlag returns the flag of the FieldType. 100 func (ft *FieldType) GetFlag() uint { 101 return ft.flag 102 } 103 104 // GetFlen returns the length of the field. 105 func (ft *FieldType) GetFlen() int { 106 return ft.flen 107 } 108 109 // GetDecimal returns the decimal of the FieldType. 110 func (ft *FieldType) GetDecimal() int { 111 return ft.decimal 112 } 113 114 // GetCharset returns the field's charset 115 func (ft *FieldType) GetCharset() string { 116 return ft.charset 117 } 118 119 // GetCollate returns the collation of the field. 120 func (ft *FieldType) GetCollate() string { 121 return ft.collate 122 } 123 124 // GetElems returns the elements of the FieldType. 125 func (ft *FieldType) GetElems() []string { 126 return ft.elems 127 } 128 129 // SetType sets the type of the FieldType. 130 func (ft *FieldType) SetType(tp byte) { 131 ft.tp = tp 132 ft.array = false 133 } 134 135 // SetFlag sets the flag of the FieldType. 136 func (ft *FieldType) SetFlag(flag uint) { 137 ft.flag = flag 138 } 139 140 // AddFlag adds a flag to the FieldType. 141 func (ft *FieldType) AddFlag(flag uint) { 142 ft.flag |= flag 143 } 144 145 // AndFlag and the flag of the FieldType. 146 func (ft *FieldType) AndFlag(flag uint) { 147 ft.flag &= flag 148 } 149 150 // ToggleFlag toggle the flag of the FieldType. 151 func (ft *FieldType) ToggleFlag(flag uint) { 152 ft.flag ^= flag 153 } 154 155 // DelFlag delete the flag of the FieldType. 156 func (ft *FieldType) DelFlag(flag uint) { 157 ft.flag &= ^flag 158 } 159 160 // SetFlen sets the length of the field. 161 func (ft *FieldType) SetFlen(flen int) { 162 ft.flen = flen 163 } 164 165 // SetFlenUnderLimit sets the length of the field to the value of the argument 166 func (ft *FieldType) SetFlenUnderLimit(flen int) { 167 if ft.GetType() == mysql.TypeNewDecimal { 168 ft.flen = mathutil.Min(flen, mysql.MaxDecimalWidth) 169 } else { 170 ft.flen = flen 171 } 172 } 173 174 // SetDecimal sets the decimal of the FieldType. 175 func (ft *FieldType) SetDecimal(decimal int) { 176 ft.decimal = decimal 177 } 178 179 // SetDecimalUnderLimit sets the decimal of the field to the value of the argument 180 func (ft *FieldType) SetDecimalUnderLimit(decimal int) { 181 if ft.GetType() == mysql.TypeNewDecimal { 182 ft.decimal = mathutil.Min(decimal, mysql.MaxDecimalScale) 183 } else { 184 ft.decimal = decimal 185 } 186 } 187 188 // UpdateFlenAndDecimalUnderLimit updates the length and decimal to the value of the argument 189 func (ft *FieldType) UpdateFlenAndDecimalUnderLimit(old *FieldType, deltaDecimal int, deltaFlen int) { 190 if ft.GetType() != mysql.TypeNewDecimal { 191 return 192 } 193 if old.decimal < 0 { 194 deltaFlen += mysql.MaxDecimalScale 195 ft.decimal = mysql.MaxDecimalScale 196 } else { 197 ft.SetDecimal(old.decimal + deltaDecimal) 198 } 199 if old.flen < 0 { 200 ft.flen = mysql.MaxDecimalWidth 201 } else { 202 ft.SetFlenUnderLimit(old.flen + deltaFlen) 203 } 204 } 205 206 // SetCharset sets the charset of the FieldType. 207 func (ft *FieldType) SetCharset(charset string) { 208 ft.charset = charset 209 } 210 211 // SetCollate sets the collation of the FieldType. 212 func (ft *FieldType) SetCollate(collate string) { 213 ft.collate = collate 214 } 215 216 // SetElems sets the elements of the FieldType. 217 func (ft *FieldType) SetElems(elems []string) { 218 ft.elems = elems 219 } 220 221 // SetElem sets the element of the FieldType. 222 func (ft *FieldType) SetElem(idx int, element string) { 223 ft.elems[idx] = element 224 } 225 226 // SetArray sets the array field of the FieldType. 227 func (ft *FieldType) SetArray(array bool) { 228 ft.array = array 229 } 230 231 // IsArray return true if the filed type is array. 232 func (ft *FieldType) IsArray() bool { 233 return ft.array 234 } 235 236 // ArrayType return the type of the array. 237 func (ft *FieldType) ArrayType() *FieldType { 238 if !ft.array { 239 return ft 240 } 241 clone := ft.Clone() 242 clone.SetArray(false) 243 return clone 244 } 245 246 // SetElemWithIsBinaryLit sets the element of the FieldType. 247 func (ft *FieldType) SetElemWithIsBinaryLit(idx int, element string, isBinaryLit bool) { 248 ft.elems[idx] = element 249 if isBinaryLit { 250 // Create the binary literal flags lazily. 251 if ft.elemsIsBinaryLit == nil { 252 ft.elemsIsBinaryLit = make([]bool, len(ft.elems)) 253 } 254 ft.elemsIsBinaryLit[idx] = true 255 } 256 } 257 258 // GetElem returns the element of the FieldType. 259 func (ft *FieldType) GetElem(idx int) string { 260 return ft.elems[idx] 261 } 262 263 // GetElemIsBinaryLit returns the binary literal flag of the element at index idx. 264 func (ft *FieldType) GetElemIsBinaryLit(idx int) bool { 265 if len(ft.elemsIsBinaryLit) == 0 { 266 return false 267 } 268 return ft.elemsIsBinaryLit[idx] 269 } 270 271 // CleanElemIsBinaryLit cleans the binary literal flag of the element at index idx. 272 func (ft *FieldType) CleanElemIsBinaryLit() { 273 if ft != nil && ft.elemsIsBinaryLit != nil { 274 ft.elemsIsBinaryLit = nil 275 } 276 } 277 278 // Clone returns a copy of itself. 279 func (ft *FieldType) Clone() *FieldType { 280 ret := *ft 281 return &ret 282 } 283 284 // Equal checks whether two FieldType objects are equal. 285 func (ft *FieldType) Equal(other *FieldType) bool { 286 // We do not need to compare whole `ft.flag == other.flag` when wrapping cast upon an Expression. 287 // but need compare unsigned_flag of ft.flag. 288 // When tp is float or double with decimal unspecified, do not check whether flen is equal, 289 // because flen for them is useless. 290 // The decimal field can be ignored if the type is int or string. 291 tpEqual := (ft.GetType() == other.GetType()) || (ft.GetType() == mysql.TypeVarchar && other.GetType() == mysql.TypeVarString) || (ft.GetType() == mysql.TypeVarString && other.GetType() == mysql.TypeVarchar) 292 flenEqual := ft.flen == other.flen || (ft.EvalType() == ETReal && ft.decimal == UnspecifiedLength) 293 ignoreDecimal := ft.EvalType() == ETInt || ft.EvalType() == ETString 294 partialEqual := tpEqual && 295 (ignoreDecimal || ft.decimal == other.decimal) && 296 ft.charset == other.charset && 297 ft.collate == other.collate && 298 flenEqual && 299 mysql.HasUnsignedFlag(ft.flag) == mysql.HasUnsignedFlag(other.flag) 300 if !partialEqual || len(ft.elems) != len(other.elems) { 301 return false 302 } 303 for i := range ft.elems { 304 if ft.elems[i] != other.elems[i] { 305 return false 306 } 307 } 308 return true 309 } 310 311 // PartialEqual checks whether two FieldType objects are equal. 312 // If unsafe is true and the objects is string type, PartialEqual will ignore flen. 313 // See https://github.com/pingcap/tidb/issues/35490#issuecomment-1211658886 for more detail. 314 func (ft *FieldType) PartialEqual(other *FieldType, unsafe bool) bool { 315 if !unsafe || ft.EvalType() != ETString || other.EvalType() != ETString { 316 return ft.Equal(other) 317 } 318 319 partialEqual := ft.charset == other.charset && ft.collate == other.collate && mysql.HasUnsignedFlag(ft.flag) == mysql.HasUnsignedFlag(other.flag) 320 if !partialEqual || len(ft.elems) != len(other.elems) { 321 return false 322 } 323 for i := range ft.elems { 324 if ft.elems[i] != other.elems[i] { 325 return false 326 } 327 } 328 return true 329 } 330 331 // EvalType gets the type in evaluation. 332 func (ft *FieldType) EvalType() EvalType { 333 switch ft.GetType() { 334 case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, 335 mysql.TypeBit, mysql.TypeYear: 336 return ETInt 337 case mysql.TypeFloat, mysql.TypeDouble: 338 return ETReal 339 case mysql.TypeNewDecimal: 340 return ETDecimal 341 case mysql.TypeDate, mysql.TypeDatetime: 342 return ETDatetime 343 case mysql.TypeTimestamp: 344 return ETTimestamp 345 case mysql.TypeDuration: 346 return ETDuration 347 case mysql.TypeJSON: 348 return ETJson 349 case mysql.TypeEnum, mysql.TypeSet: 350 if ft.flag&mysql.EnumSetAsIntFlag > 0 { 351 return ETInt 352 } 353 } 354 return ETString 355 } 356 357 // Hybrid checks whether a type is a hybrid type, which can represent different types of value in specific context. 358 func (ft *FieldType) Hybrid() bool { 359 return ft.GetType() == mysql.TypeEnum || ft.GetType() == mysql.TypeBit || ft.GetType() == mysql.TypeSet 360 } 361 362 // Init initializes the FieldType data. 363 func (ft *FieldType) Init(tp byte) { 364 ft.tp = tp 365 ft.flen = UnspecifiedLength 366 ft.decimal = UnspecifiedLength 367 } 368 369 // CompactStr only considers tp/CharsetBin/flen/Deimal. 370 // This is used for showing column type in infoschema. 371 func (ft *FieldType) CompactStr() string { 372 ts := TypeToStr(ft.GetType(), ft.charset) 373 suffix := "" 374 375 defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(ft.GetType()) 376 isDecimalNotDefault := ft.decimal != defaultDecimal && ft.decimal != 0 && ft.decimal != UnspecifiedLength 377 378 // displayFlen and displayDecimal are flen and decimal values with `-1` substituted with default value. 379 displayFlen, displayDecimal := ft.flen, ft.decimal 380 if displayFlen == UnspecifiedLength { 381 displayFlen = defaultFlen 382 } 383 if displayDecimal == UnspecifiedLength { 384 displayDecimal = defaultDecimal 385 } 386 387 switch ft.GetType() { 388 case mysql.TypeEnum, mysql.TypeSet: 389 // Format is ENUM ('e1', 'e2') or SET ('e1', 'e2') 390 es := make([]string, 0, len(ft.elems)) 391 for _, e := range ft.elems { 392 e = format.OutputFormat(e) 393 es = append(es, e) 394 } 395 suffix = fmt.Sprintf("('%s')", strings.Join(es, "','")) 396 case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDuration: 397 if isDecimalNotDefault { 398 suffix = fmt.Sprintf("(%d)", displayDecimal) 399 } 400 case mysql.TypeDouble, mysql.TypeFloat: 401 // 1. flen Not Default, decimal Not Default -> Valid 402 // 2. flen Not Default, decimal Default (-1) -> Invalid 403 // 3. flen Default, decimal Not Default -> Valid 404 // 4. flen Default, decimal Default -> Valid (hide) 405 if isDecimalNotDefault { 406 suffix = fmt.Sprintf("(%d,%d)", displayFlen, displayDecimal) 407 } 408 case mysql.TypeNewDecimal: 409 suffix = fmt.Sprintf("(%d,%d)", displayFlen, displayDecimal) 410 case mysql.TypeBit, mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString: 411 suffix = fmt.Sprintf("(%d)", displayFlen) 412 case mysql.TypeTiny: 413 // With display length deprecation active tinyint(1) still has 414 // a display length to indicate this might have been a BOOL. 415 // Connectors expect this. 416 // 417 // See also: 418 // https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html 419 if !TiDBStrictIntegerDisplayWidth || (mysql.HasZerofillFlag(ft.flag) || displayFlen == 1) { 420 suffix = fmt.Sprintf("(%d)", displayFlen) 421 } 422 case mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: 423 // Referring this issue #6688, the integer max display length is deprecated in MySQL 8.0. 424 // Since the length doesn't take any effect in TiDB storage or showing result, we remove it here. 425 if !TiDBStrictIntegerDisplayWidth || mysql.HasZerofillFlag(ft.flag) { 426 suffix = fmt.Sprintf("(%d)", displayFlen) 427 } 428 case mysql.TypeYear: 429 suffix = fmt.Sprintf("(%d)", ft.flen) 430 case mysql.TypeNull: 431 suffix = "(0)" 432 } 433 return ts + suffix 434 } 435 436 // InfoSchemaStr joins the CompactStr with unsigned flag and 437 // returns a string. 438 func (ft *FieldType) InfoSchemaStr() string { 439 suffix := "" 440 if mysql.HasUnsignedFlag(ft.flag) && 441 ft.GetType() != mysql.TypeBit && 442 ft.GetType() != mysql.TypeYear { 443 suffix = " unsigned" 444 } 445 return ft.CompactStr() + suffix 446 } 447 448 // String joins the information of FieldType and returns a string. 449 // Note: when flen or decimal is unspecified, this function will use the default value instead of -1. 450 func (ft *FieldType) String() string { 451 strs := []string{ft.CompactStr()} 452 if mysql.HasUnsignedFlag(ft.flag) { 453 strs = append(strs, "UNSIGNED") 454 } 455 if mysql.HasZerofillFlag(ft.flag) { 456 strs = append(strs, "ZEROFILL") 457 } 458 if mysql.HasBinaryFlag(ft.flag) && ft.GetType() != mysql.TypeString { 459 strs = append(strs, "BINARY") 460 } 461 462 if IsTypeChar(ft.GetType()) || IsTypeBlob(ft.GetType()) { 463 if ft.charset != "" && ft.charset != charset.CharsetBin { 464 strs = append(strs, fmt.Sprintf("CHARACTER SET %s", ft.charset)) 465 } 466 if ft.collate != "" && ft.collate != charset.CharsetBin { 467 strs = append(strs, fmt.Sprintf("COLLATE %s", ft.collate)) 468 } 469 } 470 471 return strings.Join(strs, " ") 472 } 473 474 // Restore implements Node interface. 475 func (ft *FieldType) Restore(ctx *format.RestoreCtx) error { 476 ctx.WriteKeyWord(TypeToStr(ft.GetType(), ft.charset)) 477 478 precision := UnspecifiedLength 479 scale := UnspecifiedLength 480 481 switch ft.GetType() { 482 case mysql.TypeEnum, mysql.TypeSet: 483 ctx.WritePlain("(") 484 for i, e := range ft.elems { 485 if i != 0 { 486 ctx.WritePlain(",") 487 } 488 ctx.WriteString(e) 489 } 490 ctx.WritePlain(")") 491 case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDuration: 492 precision = ft.decimal 493 case mysql.TypeUnspecified, mysql.TypeFloat, mysql.TypeDouble, mysql.TypeNewDecimal: 494 precision = ft.flen 495 scale = ft.decimal 496 default: 497 precision = ft.flen 498 } 499 500 if precision != UnspecifiedLength { 501 ctx.WritePlainf("(%d", precision) 502 if scale != UnspecifiedLength { 503 ctx.WritePlainf(",%d", scale) 504 } 505 ctx.WritePlain(")") 506 } 507 508 if mysql.HasUnsignedFlag(ft.flag) { 509 ctx.WriteKeyWord(" UNSIGNED") 510 } 511 if mysql.HasZerofillFlag(ft.flag) { 512 ctx.WriteKeyWord(" ZEROFILL") 513 } 514 if mysql.HasBinaryFlag(ft.flag) && ft.charset != charset.CharsetBin { 515 ctx.WriteKeyWord(" BINARY") 516 } 517 518 if IsTypeChar(ft.GetType()) || IsTypeBlob(ft.GetType()) { 519 if ft.charset != "" && ft.charset != charset.CharsetBin { 520 ctx.WriteKeyWord(" CHARACTER SET " + ft.charset) 521 } 522 if ft.collate != "" && ft.collate != charset.CharsetBin { 523 ctx.WriteKeyWord(" COLLATE ") 524 ctx.WritePlain(ft.collate) 525 } 526 } 527 528 return nil 529 } 530 531 // RestoreAsCastType is used for write AST back to string. 532 func (ft *FieldType) RestoreAsCastType(ctx *format.RestoreCtx, explicitCharset bool) { 533 switch ft.tp { 534 case mysql.TypeVarString, mysql.TypeString: 535 skipWriteBinary := false 536 if ft.charset == charset.CharsetBin && ft.collate == charset.CollationBin { 537 ctx.WriteKeyWord("BINARY") 538 skipWriteBinary = true 539 } else { 540 ctx.WriteKeyWord("CHAR") 541 } 542 if ft.flen != UnspecifiedLength { 543 ctx.WritePlainf("(%d)", ft.flen) 544 } 545 if !explicitCharset { 546 break 547 } 548 if !skipWriteBinary && ft.flag&mysql.BinaryFlag != 0 { 549 ctx.WriteKeyWord(" BINARY") 550 } 551 if ft.charset != charset.CharsetBin && ft.charset != mysql.DefaultCharset { 552 ctx.WriteKeyWord(" CHARSET ") 553 ctx.WriteKeyWord(ft.charset) 554 } 555 case mysql.TypeDate: 556 ctx.WriteKeyWord("DATE") 557 case mysql.TypeDatetime: 558 ctx.WriteKeyWord("DATETIME") 559 if ft.decimal > 0 { 560 ctx.WritePlainf("(%d)", ft.decimal) 561 } 562 case mysql.TypeNewDecimal: 563 ctx.WriteKeyWord("DECIMAL") 564 if ft.flen > 0 && ft.decimal > 0 { 565 ctx.WritePlainf("(%d, %d)", ft.flen, ft.decimal) 566 } else if ft.flen > 0 { 567 ctx.WritePlainf("(%d)", ft.flen) 568 } 569 case mysql.TypeDuration: 570 ctx.WriteKeyWord("TIME") 571 if ft.decimal > 0 { 572 ctx.WritePlainf("(%d)", ft.decimal) 573 } 574 case mysql.TypeLonglong: 575 if ft.flag&mysql.UnsignedFlag != 0 { 576 ctx.WriteKeyWord("UNSIGNED") 577 } else { 578 ctx.WriteKeyWord("SIGNED") 579 } 580 case mysql.TypeJSON: 581 ctx.WriteKeyWord("JSON") 582 case mysql.TypeDouble: 583 ctx.WriteKeyWord("DOUBLE") 584 case mysql.TypeFloat: 585 ctx.WriteKeyWord("FLOAT") 586 case mysql.TypeYear: 587 ctx.WriteKeyWord("YEAR") 588 } 589 if ft.array { 590 ctx.WritePlain(" ") 591 ctx.WriteKeyWord("ARRAY") 592 } 593 } 594 595 // FormatAsCastType is used for write AST back to string. 596 func (ft *FieldType) FormatAsCastType(w io.Writer, explicitCharset bool) { 597 var sb strings.Builder 598 restoreCtx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb) 599 ft.RestoreAsCastType(restoreCtx, explicitCharset) 600 fmt.Fprint(w, sb.String()) 601 } 602 603 // VarStorageLen indicates this column is a variable length column. 604 const VarStorageLen = -1 605 606 // StorageLength is the length of stored value for the type. 607 func (ft *FieldType) StorageLength() int { 608 switch ft.GetType() { 609 case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, 610 mysql.TypeLonglong, mysql.TypeDouble, mysql.TypeFloat, mysql.TypeYear, mysql.TypeDuration, 611 mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeEnum, mysql.TypeSet, 612 mysql.TypeBit: 613 // This may not be the accurate length, because we may encode them as varint. 614 return 8 615 case mysql.TypeNewDecimal: 616 precision, frac := ft.flen-ft.decimal, ft.decimal 617 return precision/digitsPerWord*wordSize + dig2bytes[precision%digitsPerWord] + frac/digitsPerWord*wordSize + dig2bytes[frac%digitsPerWord] 618 default: 619 return VarStorageLen 620 } 621 } 622 623 // HasCharset indicates if a COLUMN has an associated charset. Returning false here prevents some information 624 // statements(like `SHOW CREATE TABLE`) from attaching a CHARACTER SET clause to the column. 625 func HasCharset(ft *FieldType) bool { 626 switch ft.GetType() { 627 case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString, mysql.TypeBlob, 628 mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: 629 return !mysql.HasBinaryFlag(ft.flag) 630 case mysql.TypeEnum, mysql.TypeSet: 631 return true 632 } 633 return false 634 } 635 636 // for json 637 type jsonFieldType struct { 638 Tp byte 639 Flag uint 640 Flen int 641 Decimal int 642 Charset string 643 Collate string 644 Elems []string 645 ElemsIsBinaryLit []bool 646 Array bool 647 } 648 649 // UnmarshalJSON implements the json.Unmarshaler interface. 650 func (ft *FieldType) UnmarshalJSON(data []byte) error { 651 var r jsonFieldType 652 err := json.Unmarshal(data, &r) 653 if err == nil { 654 ft.tp = r.Tp 655 ft.flag = r.Flag 656 ft.flen = r.Flen 657 ft.decimal = r.Decimal 658 ft.charset = r.Charset 659 ft.collate = r.Collate 660 ft.elems = r.Elems 661 ft.elemsIsBinaryLit = r.ElemsIsBinaryLit 662 ft.array = r.Array 663 } 664 return err 665 } 666 667 // MarshalJSON marshals the FieldType to JSON. 668 func (ft *FieldType) MarshalJSON() ([]byte, error) { 669 var r jsonFieldType 670 r.Tp = ft.tp 671 r.Flag = ft.flag 672 r.Flen = ft.flen 673 r.Decimal = ft.decimal 674 r.Charset = ft.charset 675 r.Collate = ft.collate 676 r.Elems = ft.elems 677 r.ElemsIsBinaryLit = ft.elemsIsBinaryLit 678 r.Array = ft.array 679 return json.Marshal(r) 680 } 681 682 const emptyFieldTypeSize = int64(unsafe.Sizeof(FieldType{})) 683 684 // MemoryUsage return the memory usage of FieldType 685 func (ft *FieldType) MemoryUsage() (sum int64) { 686 if ft == nil { 687 return 688 } 689 sum = emptyFieldTypeSize + int64(len(ft.charset)+len(ft.collate)) + int64(cap(ft.elems))*int64(unsafe.Sizeof(*new(string))) + 690 int64(cap(ft.elemsIsBinaryLit))*int64(unsafe.Sizeof(*new(bool))) 691 692 for _, s := range ft.elems { 693 sum += int64(len(s)) 694 } 695 return 696 }