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  }