github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/set.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 "strconv" 18 "strings" 19 20 "github.com/pingcap/errors" 21 ) 22 23 var zeroSet = Set{Name: "", Value: 0} 24 25 // Set is for MySQL Set type. 26 type Set struct { 27 Name string 28 Value uint64 29 } 30 31 // String implements fmt.Stringer interface. 32 func (e Set) String() string { 33 return e.Name 34 } 35 36 // ToNumber changes Set to float64 for numeric operation. 37 func (e Set) ToNumber() float64 { 38 return float64(e.Value) 39 } 40 41 // ParseSetName creates a Set with name. 42 func ParseSetName(elems []string, name string) (Set, error) { 43 if len(name) == 0 { 44 return zeroSet, nil 45 } 46 47 seps := strings.Split(name, ",") 48 marked := make(map[string]struct{}, len(seps)) 49 for _, s := range seps { 50 marked[strings.ToLower(s)] = struct{}{} 51 } 52 items := make([]string, 0, len(seps)) 53 54 value := uint64(0) 55 for i, n := range elems { 56 key := strings.ToLower(n) 57 if _, ok := marked[key]; ok { 58 value |= 1 << uint64(i) 59 delete(marked, key) 60 items = append(items, n) 61 } 62 } 63 64 if len(marked) == 0 { 65 return Set{Name: strings.Join(items, ","), Value: value}, nil 66 } 67 68 // name doesn't exist, maybe an integer? 69 if num, err := strconv.ParseUint(name, 0, 64); err == nil { 70 return ParseSetValue(elems, num) 71 } 72 73 return Set{}, errors.Errorf("item %s is not in Set %v", name, elems) 74 } 75 76 var ( 77 setIndexValue []uint64 78 setIndexInvertValue []uint64 79 ) 80 81 func init() { 82 setIndexValue = make([]uint64, 64) 83 setIndexInvertValue = make([]uint64, 64) 84 85 for i := 0; i < 64; i++ { 86 setIndexValue[i] = 1 << uint64(i) 87 setIndexInvertValue[i] = ^setIndexValue[i] 88 } 89 } 90 91 // ParseSetValue creates a Set with special number. 92 func ParseSetValue(elems []string, number uint64) (Set, error) { 93 if number == 0 { 94 return zeroSet, nil 95 } 96 97 value := number 98 var items []string 99 for i := 0; i < len(elems); i++ { 100 if number&setIndexValue[i] > 0 { 101 items = append(items, elems[i]) 102 number &= setIndexInvertValue[i] 103 } 104 } 105 106 if number != 0 { 107 return Set{}, errors.Errorf("invalid number %d for Set %v", number, elems) 108 } 109 110 return Set{Name: strings.Join(items, ","), Value: value}, nil 111 }