Files
tidb/perfschema/common.go

144 lines
4.0 KiB
Go

// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package perfschema
import (
"strings"
"github.com/juju/errors"
"github.com/ngaut/log"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/util/codec"
"github.com/pingcap/tidb/util/types"
)
// castValues casts values based on columns type.
func castValues(rec []interface{}, cols []*model.ColumnInfo) (err error) {
for _, c := range cols {
rec[c.Offset], err = types.Convert(rec[c.Offset], &c.FieldType)
if err != nil {
return errors.Trace(err)
}
}
return nil
}
// checkNotNull checks if nil value set to a column with NotNull flag is set.
func checkNotNull(c *model.ColumnInfo, data interface{}) error {
if mysql.HasNotNullFlag(c.Flag) && data == nil {
return errors.Errorf("Column %s can't be null.", c.Name)
}
return nil
}
// checkNotNulls checks if row has nil value set to a set of columns with NotNull flag set.
func checkNotNulls(cols []*model.ColumnInfo, row []interface{}) error {
for _, c := range cols {
if err := checkNotNull(c, row[c.Offset]); err != nil {
return errors.Trace(err)
}
}
return nil
}
func decodeValue(data []byte, cols []*model.ColumnInfo) ([]interface{}, error) {
values, err := codec.Decode(data)
if err != nil {
return nil, errors.Trace(err)
}
if len(values) != len(cols) {
return nil, errors.Errorf("Column count does not match, expect %d, actual %d", len(cols), len(values))
}
var rvalues []interface{}
for i, col := range cols {
if values[i] == nil {
rvalues = append(rvalues, nil)
continue
}
// TODO: support more types if we really need.
switch col.Tp {
case mysql.TypeLong:
val := values[i].(int64)
rvalues = append(rvalues, val)
case mysql.TypeLonglong:
val := values[i].(uint64)
rvalues = append(rvalues, val)
case mysql.TypeString, mysql.TypeVarchar, mysql.TypeLongBlob:
val := string(values[i].([]byte))
rvalues = append(rvalues, val)
case mysql.TypeEnum:
val, err := mysql.ParseEnumValue(col.Elems, values[i].(uint64))
if err != nil {
return nil, errors.Trace(err)
}
rvalues = append(rvalues, val.String())
}
}
return rvalues, nil
}
// dumpValue is used for debugging purposes only.
func dumpValue(funcName string, vals []interface{}) {
for _, val := range vals {
log.Debugf("[%s] %T: %v", funcName, val, val)
}
}
// findCol finds column in cols by name.
func findCol(cols []*model.ColumnInfo, name string) *model.ColumnInfo {
for _, col := range cols {
if strings.EqualFold(col.Name.O, name) {
return col
}
}
return nil
}
// findCols finds columns in cols by names.
func findCols(cols []*model.ColumnInfo, names []string) ([]*model.ColumnInfo, error) {
var rcols []*model.ColumnInfo
for _, name := range names {
col := findCol(cols, name)
if col != nil {
rcols = append(rcols, col)
} else {
return nil, errors.Errorf("unknown column %s", name)
}
}
return rcols, nil
}
// getColDefaultValue gets default value of the column.
func getColDefaultValue(col *model.ColumnInfo) (interface{}, bool, error) {
// Check no default value flag.
if mysql.HasNoDefaultValueFlag(col.Flag) && col.Tp != mysql.TypeEnum {
return nil, false, errors.Errorf("Field '%s' doesn't have a default value", col.Name)
}
// Check and get timestamp/datetime default value.
if col.Tp == mysql.TypeEnum {
// For enum type, if no default value and not null is set,
// the default value is the first element of the enum list
if col.DefaultValue == nil && mysql.HasNotNullFlag(col.Flag) {
return col.FieldType.Elems[0], true, nil
}
}
return col.DefaultValue, true, nil
}