github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/column/column.go (about) 1 // Copyright 2013 The ql Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSES/QL-LICENSE file. 4 5 // Copyright 2015 PingCAP, Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package column 19 20 import ( 21 "strings" 22 23 "github.com/insionng/yougam/libraries/juju/errors" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/context" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 29 ) 30 31 // Col provides meta data describing a table column. 32 type Col struct { 33 model.ColumnInfo 34 } 35 36 // PrimaryKeyName defines primary key name. 37 const PrimaryKeyName = "PRIMARY" 38 39 // IndexedCol defines an index with info. 40 type IndexedCol struct { 41 model.IndexInfo 42 X kv.Index 43 } 44 45 // String implements fmt.Stringer interface. 46 func (c *Col) String() string { 47 ans := []string{c.Name.O, types.TypeToStr(c.Tp, c.Charset)} 48 if mysql.HasAutoIncrementFlag(c.Flag) { 49 ans = append(ans, "AUTO_INCREMENT") 50 } 51 if mysql.HasNotNullFlag(c.Flag) { 52 ans = append(ans, "NOT NULL") 53 } 54 return strings.Join(ans, " ") 55 } 56 57 // FindCol finds column in cols by name. 58 func FindCol(cols []*Col, name string) *Col { 59 for _, col := range cols { 60 if strings.EqualFold(col.Name.O, name) { 61 return col 62 } 63 } 64 return nil 65 } 66 67 // FindCols finds columns in cols by names. 68 func FindCols(cols []*Col, names []string) ([]*Col, error) { 69 var rcols []*Col 70 for _, name := range names { 71 col := FindCol(cols, name) 72 if col != nil { 73 rcols = append(rcols, col) 74 } else { 75 return nil, errors.Errorf("unknown column %s", name) 76 } 77 } 78 79 return rcols, nil 80 } 81 82 // FindOnUpdateCols finds columns which have OnUpdateNow flag. 83 func FindOnUpdateCols(cols []*Col) []*Col { 84 var rcols []*Col 85 for _, col := range cols { 86 if mysql.HasOnUpdateNowFlag(col.Flag) { 87 rcols = append(rcols, col) 88 } 89 } 90 91 return rcols 92 } 93 94 // CastValues casts values based on columns type. 95 func CastValues(ctx context.Context, rec []types.Datum, cols []*Col) (err error) { 96 for _, c := range cols { 97 var converted types.Datum 98 converted, err = rec[c.Offset].ConvertTo(&c.FieldType) 99 if err != nil { 100 return errors.Trace(err) 101 } 102 rec[c.Offset] = converted 103 } 104 return nil 105 } 106 107 // ColDesc describes column information like MySQL desc and show columns do. 108 type ColDesc struct { 109 Field string 110 Type string 111 Collation string 112 Null string 113 Key string 114 DefaultValue interface{} 115 Extra string 116 Privileges string 117 Comment string 118 } 119 120 const defaultPrivileges string = "select,insert,update,references" 121 122 // GetTypeDesc gets the description for column type. 123 func (c *Col) GetTypeDesc() string { 124 desc := c.FieldType.CompactStr() 125 if mysql.HasUnsignedFlag(c.Flag) { 126 desc += " UNSIGNED" 127 } 128 return desc 129 } 130 131 // NewColDesc returns a new ColDesc for a column. 132 func NewColDesc(col *Col) *ColDesc { 133 // TODO: if we have no primary key and a unique index which's columns are all not null 134 // we will set these columns' flag as PriKeyFlag 135 // see https://dev.mysql.com/doc/refman/5.7/en/show-columns.html 136 // create table 137 name := col.Name 138 nullFlag := "YES" 139 if mysql.HasNotNullFlag(col.Flag) { 140 nullFlag = "NO" 141 } 142 keyFlag := "" 143 if mysql.HasPriKeyFlag(col.Flag) { 144 keyFlag = "PRI" 145 } else if mysql.HasUniKeyFlag(col.Flag) { 146 keyFlag = "UNI" 147 } else if mysql.HasMultipleKeyFlag(col.Flag) { 148 keyFlag = "MUL" 149 } 150 var defaultValue interface{} 151 if !mysql.HasNoDefaultValueFlag(col.Flag) { 152 defaultValue = col.DefaultValue 153 } 154 155 extra := "" 156 if mysql.HasAutoIncrementFlag(col.Flag) { 157 extra = "auto_increment" 158 } else if mysql.HasOnUpdateNowFlag(col.Flag) { 159 extra = "on update CURRENT_TIMESTAMP" 160 } 161 162 return &ColDesc{ 163 Field: name.O, 164 Type: col.GetTypeDesc(), 165 Collation: col.Collate, 166 Null: nullFlag, 167 Key: keyFlag, 168 DefaultValue: defaultValue, 169 Extra: extra, 170 Privileges: defaultPrivileges, 171 Comment: "", 172 } 173 } 174 175 // ColDescFieldNames returns the fields name in result set for desc and show columns. 176 func ColDescFieldNames(full bool) []string { 177 if full { 178 return []string{"Field", "Type", "Collation", "Null", "Key", "Default", "Extra", "Privileges", "Comment"} 179 } 180 return []string{"Field", "Type", "Null", "Key", "Default", "Extra"} 181 } 182 183 // CheckOnce checks if there are duplicated column names in cols. 184 func CheckOnce(cols []*Col) error { 185 m := map[string]struct{}{} 186 for _, col := range cols { 187 name := col.Name 188 _, ok := m[name.L] 189 if ok { 190 return errors.Errorf("column specified twice - %s", name) 191 } 192 193 m[name.L] = struct{}{} 194 } 195 196 return nil 197 } 198 199 // CheckNotNull checks if nil value set to a column with NotNull flag is set. 200 func (c *Col) CheckNotNull(data types.Datum) error { 201 if mysql.HasNotNullFlag(c.Flag) && data.Kind() == types.KindNull { 202 return errors.Errorf("Column %s can't be null.", c.Name) 203 } 204 return nil 205 } 206 207 // IsPKHandleColumn checks if the column is primary key handle column. 208 func (c *Col) IsPKHandleColumn(tbInfo *model.TableInfo) bool { 209 return mysql.HasPriKeyFlag(c.Flag) && tbInfo.PKIsHandle 210 } 211 212 // CheckNotNull checks if row has nil value set to a column with NotNull flag set. 213 func CheckNotNull(cols []*Col, row []types.Datum) error { 214 for _, c := range cols { 215 if err := c.CheckNotNull(row[c.Offset]); err != nil { 216 return errors.Trace(err) 217 } 218 } 219 return nil 220 } 221 222 // FetchValues fetches indexed values from a row. 223 func (idx *IndexedCol) FetchValues(r []types.Datum) ([]types.Datum, error) { 224 vals := make([]types.Datum, len(idx.Columns)) 225 for i, ic := range idx.Columns { 226 if ic.Offset < 0 || ic.Offset > len(r) { 227 return nil, errors.New("Index column offset out of bound") 228 } 229 vals[i] = r[ic.Offset] 230 } 231 return vals, nil 232 }