// Modifiable checks if the 'origin' type can be modified to 'to' type with out the need to // change or check existing data in the table. // It returns true if the two types has the same Charset and Collation, the same sign, both are // integer types or string types, and new Flen and Decimal must be greater than or equal to origin. func (d *ddl) modifiable(origin *types.FieldType, to *types.FieldType) bool { if to.Flen > 0 && to.Flen < origin.Flen { return false } if to.Decimal > 0 && to.Decimal < origin.Decimal { return false } if origin.Charset != to.Charset || origin.Collate != to.Collate { return false } if mysql.HasUnsignedFlag(uint(origin.Flag)) != mysql.HasUnsignedFlag(uint(to.Flag)) { return false } switch origin.Tp { case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: switch to.Tp { case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: return true default: return false } case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: switch to.Tp { case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: return true default: return false } default: return false } }
func getZeroValue(col *model.ColumnInfo) types.Datum { var d types.Datum switch col.Tp { case mysql.TypeTiny, mysql.TypeInt24, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear: if mysql.HasUnsignedFlag(col.Flag) { d.SetUint64(0) } else { d.SetInt64(0) } case mysql.TypeFloat: d.SetFloat32(0) case mysql.TypeDouble: d.SetFloat64(0) case mysql.TypeNewDecimal: d.SetMysqlDecimal(mysql.NewDecimalFromInt(0, 0)) case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar: d.SetString("") case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: d.SetBytes([]byte{}) case mysql.TypeDuration: d.SetMysqlDuration(mysql.ZeroDuration) case mysql.TypeDate, mysql.TypeNewDate: d.SetMysqlTime(mysql.ZeroDate) case mysql.TypeTimestamp: d.SetMysqlTime(mysql.ZeroTimestamp) case mysql.TypeDatetime: d.SetMysqlTime(mysql.ZeroDatetime) case mysql.TypeBit: d.SetMysqlBit(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}) case mysql.TypeSet: d.SetMysqlSet(mysql.Set{}) } return d }
// handleRowData deals with raw row data: // 1. Decodes row from raw byte slice. // 2. Checks if it fit where condition. // 3. Update aggregate functions. // returns true if got a row. func (rs *localRegion) handleRowData(ctx *selectContext, handle int64, value []byte) (bool, error) { columns := ctx.sel.TableInfo.Columns values, err := rs.getRowData(value, ctx.colTps) if err != nil { return false, errors.Trace(err) } // Fill handle and null columns. for _, col := range columns { if col.GetPkHandle() { var handleDatum types.Datum if mysql.HasUnsignedFlag(uint(col.Flag)) { // PK column is Unsigned handleDatum = types.NewUintDatum(uint64(handle)) } else { handleDatum = types.NewIntDatum(handle) } handleData, err1 := codec.EncodeValue(nil, handleDatum) if err1 != nil { return false, errors.Trace(err1) } values[col.GetColumnId()] = handleData } else { _, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return false, errors.New("Miss column") } values[col.GetColumnId()] = []byte{codec.NilFlag} } } } return rs.valuesToRow(ctx, handle, values) }
// GetTypeDesc gets the description for column type. func (c *Column) GetTypeDesc() string { desc := c.FieldType.CompactStr() if mysql.HasUnsignedFlag(c.Flag) { desc += " UNSIGNED" } return desc }
// RowWithCols implements table.Table RowWithCols interface. func (t *Table) RowWithCols(ctx context.Context, h int64, cols []*table.Column) ([]types.Datum, error) { txn, err := ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } // Get raw row data from kv. key := t.RecordKey(h) value, err := txn.Get(key) if err != nil { return nil, errors.Trace(err) } // Decode raw row data. v := make([]types.Datum, len(cols)) colTps := make(map[int64]*types.FieldType, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } colTps[col.ID] = &col.FieldType } row, err := tablecodec.DecodeRow(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { // TODO: check this return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { continue } ri, ok := row[col.ID] if !ok && mysql.HasNotNullFlag(col.Flag) { return nil, errors.New("Miss column") } v[i] = ri } return v, nil }
func (h *rpcHandler) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) { tid := ctx.sel.TableInfo.GetTableId() columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } for _, col := range columns { if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(col.GetFlag())) { row.Data, err = codec.EncodeValue(row.Data, types.NewUintDatum(uint64(handle))) if err != nil { return nil, errors.Trace(err) } } else { row.Data = append(row.Data, row.Handle...) } } else { colID := col.GetColumnId() if ctx.whereColumns[colID] != nil { // The column is saved in evaluator, use it directly. datum := ctx.eval.Row[colID] row.Data, err = codec.EncodeValue(row.Data, datum) if err != nil { return nil, errors.Trace(err) } } else { key := tablecodec.EncodeColumnKey(tid, handle, colID) data, err1 := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err1 != nil { return nil, errors.Trace(err1) } if data == nil { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.Trace(kv.ErrNotExist) } row.Data = append(row.Data, codec.NilFlag) } else { row.Data = append(row.Data, data...) } } } } return row, nil }
func rowWithCols(txn kv.Retriever, t table.Table, h int64, cols []*table.Column) ([]types.Datum, error) { key := t.RecordKey(h) value, err := txn.Get(key) if err != nil { return nil, errors.Trace(err) } v := make([]types.Datum, len(cols)) colTps := make(map[int64]*types.FieldType, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.Meta()) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } colTps[col.ID] = &col.FieldType } row, err := tablecodec.DecodeRow(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { // TODO: check this return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.Meta()) { continue } ri, ok := row[col.ID] if !ok && mysql.HasNotNullFlag(col.Flag) { return nil, errors.New("Miss") } v[i] = ri } return v, nil }
func (h *rpcHandler) evalWhereForRow(ctx *selectContext, handle int64) (bool, error) { if ctx.sel.Where == nil { return true, nil } tid := ctx.sel.TableInfo.GetTableId() for colID, col := range ctx.whereColumns { if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(col.GetFlag())) { ctx.eval.Row[colID] = types.NewUintDatum(uint64(handle)) } else { ctx.eval.Row[colID] = types.NewIntDatum(handle) } } else { key := tablecodec.EncodeColumnKey(tid, handle, colID) data, err := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err != nil { return false, errors.Trace(err) } if data == nil { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return false, errors.Trace(kv.ErrNotExist) } ctx.eval.Row[colID] = types.Datum{} } else { var d types.Datum d, err = tablecodec.DecodeColumnValue(data, col) if err != nil { return false, errors.Trace(err) } ctx.eval.Row[colID] = d } } } result, err := ctx.eval.Eval(ctx.sel.Where) if err != nil { return false, errors.Trace(err) } if result.IsNull() { return false, nil } boolResult, err := result.ToBool() if err != nil { return false, errors.Trace(err) } return boolResult == 1, nil }
// String implements the Expression String interface. func (f *FunctionCast) String() string { tpStr := "" if f.Tp.Tp == mysql.TypeLonglong { if mysql.HasUnsignedFlag(f.Tp.Flag) { tpStr = "UNSIGNED" } else { tpStr = "SIGNED" } } else { tpStr = f.Tp.String() } if f.FunctionType == ConvertFunction { return fmt.Sprintf("CONVERT(%s, %s)", f.Expr.String(), tpStr) } else if f.FunctionType == BinaryOperator { return fmt.Sprintf("BINARY %s", f.Expr.String()) } return fmt.Sprintf("CAST(%s AS %s)", f.Expr.String(), tpStr) }
func (e *XSelectIndexExec) indexRowToTableRow(handle int64, indexRow []types.Datum) []types.Datum { tableRow := make([]types.Datum, len(e.indexPlan.Columns)) for i, tblCol := range e.indexPlan.Columns { if table.ToColumn(tblCol).IsPKHandleColumn(e.indexPlan.Table) { if mysql.HasUnsignedFlag(tblCol.FieldType.Flag) { tableRow[i] = types.NewUintDatum(uint64(handle)) } else { tableRow[i] = types.NewIntDatum(handle) } continue } for j, idxCol := range e.indexPlan.Index.Columns { if tblCol.Name.L == idxCol.Name.L { tableRow[i] = indexRow[j] break } } } return tableRow }
// Put column values into ctx, the values will be used for expr evaluation. func (rs *localRegion) setColumnValueToCtx(ctx *selectContext, h int64, row map[int64][]byte, cols map[int64]*tipb.ColumnInfo) error { for colID, col := range cols { if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(col.GetFlag())) { ctx.eval.Row[colID] = types.NewUintDatum(uint64(h)) } else { ctx.eval.Row[colID] = types.NewIntDatum(h) } } else { data := row[colID] ft := distsql.FieldTypeFromPBColumn(col) datum, err := tablecodec.DecodeColumnValue(data, ft) if err != nil { return errors.Trace(err) } ctx.eval.Row[colID] = datum } } return nil }
// String joins the information of FieldType and // returns a string. func (ft *FieldType) String() string { strs := []string{ft.CompactStr()} if mysql.HasUnsignedFlag(ft.Flag) { strs = append(strs, "UNSIGNED") } if mysql.HasZerofillFlag(ft.Flag) { strs = append(strs, "ZEROFILL") } if mysql.HasBinaryFlag(ft.Flag) { strs = append(strs, "BINARY") } if IsTypeChar(ft.Tp) || IsTypeBlob(ft.Tp) { if ft.Charset != "" && ft.Charset != charset.CharsetBin { strs = append(strs, fmt.Sprintf("CHARACTER SET %s", ft.Charset)) } if ft.Collate != "" && ft.Collate != charset.CharsetBin { strs = append(strs, fmt.Sprintf("COLLATE %s", ft.Collate)) } } return strings.Join(strs, " ") }
// RowWithCols implements table.Table RowWithCols interface. func (t *Table) RowWithCols(ctx context.Context, h int64, cols []*table.Column) ([]types.Datum, error) { txn, err := ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } v := make([]types.Datum, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } k := t.RecordKey(h, col) data, err := txn.Get(k) if terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(col.Flag) { continue } else if err != nil { return nil, errors.Trace(err) } v[i], err = DecodeValue(data, &col.FieldType) if err != nil { return nil, errors.Trace(err) } } return v, nil }
// ConvertTo converts a datum to the target field type. func (d *Datum) ConvertTo(target *FieldType) (Datum, error) { if d.k == KindNull { return Datum{}, nil } switch target.Tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported. case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: unsigned := mysql.HasUnsignedFlag(target.Flag) if unsigned { return d.convertToUint(target) } return d.convertToInt(target) case mysql.TypeFloat, mysql.TypeDouble: return d.convertToFloat(target) case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString: return d.convertToString(target) case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate: return d.convertToMysqlTime(target) case mysql.TypeDuration: return d.convertToMysqlDuration(target) case mysql.TypeBit: return d.convertToMysqlBit(target) case mysql.TypeDecimal, mysql.TypeNewDecimal: return d.convertToMysqlDecimal(target) case mysql.TypeYear: return d.convertToMysqlYear(target) case mysql.TypeEnum: return d.convertToMysqlEnum(target) case mysql.TypeSet: return d.convertToMysqlSet(target) case mysql.TypeNull: return Datum{}, nil default: panic("should never happen") } }
// Cast casts val to certain types and does not return error. func Cast(val interface{}, target *FieldType) (v interface{}) { tp := target.Tp switch tp { case mysql.TypeString: x, _ := ToString(val) // TODO: consider target.Charset/Collate x = truncateStr(x, target.Flen) if target.Charset == charset.CharsetBin { return []byte(x) } return x case mysql.TypeDuration: var dur mysql.Duration fsp := mysql.DefaultFsp if target.Decimal != UnspecifiedLength { fsp = target.Decimal } switch x := val.(type) { case mysql.Duration: dur, _ = x.RoundFrac(fsp) case mysql.Time: dur, _ = x.ConvertToDuration() dur, _ = dur.RoundFrac(fsp) case string: dur, _ = mysql.ParseDuration(x, fsp) case *DataItem: return Cast(x.Data, target) } return dur case mysql.TypeDatetime, mysql.TypeDate: fsp := mysql.DefaultFsp if target.Decimal != UnspecifiedLength { fsp = target.Decimal } var t mysql.Time t.Type = tp switch x := val.(type) { case mysql.Time: t, _ = x.Convert(tp) t, _ = t.RoundFrac(fsp) case mysql.Duration: t, _ = x.ConvertToTime(tp) t, _ = t.RoundFrac(fsp) case string: t, _ = mysql.ParseTime(x, tp, fsp) case int64: t, _ = mysql.ParseTimeFromNum(x, tp, fsp) case *DataItem: return Cast(x.Data, target) } return t case mysql.TypeLonglong: if mysql.HasUnsignedFlag(target.Flag) { v, _ = ToUint64(val) } else { v, _ = ToInt64(val) } return case mysql.TypeNewDecimal: x, _ := ToDecimal(val) if target.Decimal != UnspecifiedLength { x = x.Round(int32(target.Decimal)) } // TODO: check Flen return x default: panic("should never happen") } }
// handleRowData deals with raw row data: // 1. Decodes row from raw byte slice. // 2. Checks if it fit where condition. // 3. Update aggregate functions. func (rs *localRegion) handleRowData(ctx *selectContext, handle int64, value []byte) (*tipb.Row, error) { columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } rowData := make([][]byte, len(columns)) values, err := rs.getRowData(value, ctx.colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range columns { if *col.PkHandle { var colVal []byte if mysql.HasUnsignedFlag(uint(*col.Flag)) { // PK column is Unsigned var ud types.Datum ud.SetUint64(uint64(handle)) var err1 error colVal, err1 = codec.EncodeValue(nil, ud) if err1 != nil { return nil, errors.Trace(err1) } } else { colVal = row.Handle } rowData[i] = colVal continue } v, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.New("Miss column") } v = []byte{codec.NilFlag} values[col.GetColumnId()] = v } rowData[i] = v } // Evalue where match, err := rs.evalWhereForRow(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } if !match { return nil, nil } if ctx.aggregate { // Update aggregate functions. err = rs.aggregate(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } } else { // If without aggregate functions, just return raw row data. for _, d := range rowData { row.Data = append(row.Data, d...) } } return row, nil }
func (h *rpcHandler) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) { tid := ctx.sel.TableInfo.GetTableId() columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } rowData := make([][]byte, len(columns)) colTps := make(map[int64]*types.FieldType, len(columns)) for i, col := range columns { var colVal []byte if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(*col.Flag)) { // PK column is Unsigned var ud types.Datum ud.SetUint64(uint64(handle)) var err1 error colVal, err1 = codec.EncodeValue(nil, ud) if err1 != nil { return nil, errors.Trace(err1) } } else { colVal = row.Handle } rowData[i] = colVal } else { colTps[col.GetColumnId()] = xapi.FieldTypeFromPBColumn(col) } } key := tablecodec.EncodeRowKeyWithHandle(tid, handle) value, err := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err != nil { return nil, errors.Trace(err) } values, err := h.getRowData(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range columns { if col.GetPkHandle() { continue } v, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.New("Miss column") } v = []byte{codec.NilFlag} values[col.GetColumnId()] = v } rowData[i] = v } // Evalue where match, err := h.evalWhereForRow(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } if !match { return nil, nil } for _, d := range rowData { row.Data = append(row.Data, d...) } return row, nil }
// Convert converts the val with type tp. func Convert(val interface{}, target *FieldType) (v interface{}, err error) { tp := target.Tp if val == nil { return nil, nil } vdi, ok := val.(*DataItem) if ok { return Convert(vdi.Data, target) } switch tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported. case mysql.TypeFloat: x, err := ToFloat64(val) if err != nil { return invConv(val, tp) } // For float and following double type, we will only truncate it for float(M, D) format. // If no D is set, we will handle it like origin float whether M is set or not. if target.Flen != UnspecifiedLength && target.Decimal != UnspecifiedLength { x, err = TruncateFloat(x, target.Flen, target.Decimal) if err != nil { return nil, errors.Trace(err) } } return float32(x), nil case mysql.TypeDouble: x, err := ToFloat64(val) if err != nil { return invConv(val, tp) } if target.Flen != UnspecifiedLength && target.Decimal != UnspecifiedLength { x, err = TruncateFloat(x, target.Flen, target.Decimal) if err != nil { return nil, errors.Trace(err) } } return float64(x), nil case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString: x, err := ToString(val) if err != nil { return invConv(val, tp) } // TODO: consider target.Charset/Collate x = truncateStr(x, target.Flen) if target.Charset == charset.CharsetBin { return []byte(x), nil } return x, nil case mysql.TypeDuration: fsp := mysql.DefaultFsp if target.Decimal != UnspecifiedLength { fsp = target.Decimal } switch x := val.(type) { case mysql.Duration: return x.RoundFrac(fsp) case mysql.Time: t, err := x.ConvertToDuration() if err != nil { return nil, errors.Trace(err) } return t.RoundFrac(fsp) case string: return mysql.ParseDuration(x, fsp) default: return invConv(val, tp) } case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate: fsp := mysql.DefaultFsp if target.Decimal != UnspecifiedLength { fsp = target.Decimal } switch x := val.(type) { case mysql.Time: t, err := x.Convert(tp) if err != nil { return nil, errors.Trace(err) } return t.RoundFrac(fsp) case mysql.Duration: t, err := x.ConvertToTime(tp) if err != nil { return nil, errors.Trace(err) } return t.RoundFrac(fsp) case string: return mysql.ParseTime(x, tp, fsp) case int64: return mysql.ParseTimeFromNum(x, tp, fsp) default: return invConv(val, tp) } case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: unsigned := mysql.HasUnsignedFlag(target.Flag) if unsigned { return convertToUint(val, target) } return convertToInt(val, target) case mysql.TypeBit: x, err := convertToUint(val, target) if err != nil { return x, errors.Trace(err) } // check bit boundary, if bit has n width, the boundary is // in [0, (1 << n) - 1] width := target.Flen if width == 0 || width == mysql.UnspecifiedBitWidth { width = mysql.MinBitWidth } maxValue := uint64(1)<<uint64(width) - 1 if x > maxValue { return maxValue, overflow(val, tp) } return mysql.Bit{Value: x, Width: width}, nil case mysql.TypeDecimal, mysql.TypeNewDecimal: x, err := ToDecimal(val) if err != nil { return invConv(val, tp) } if target.Decimal != UnspecifiedLength { x = x.Round(int32(target.Decimal)) } // TODO: check Flen return x, nil case mysql.TypeYear: var ( intVal int64 err error ) switch x := val.(type) { case string: intVal, err = StrToInt(x) case mysql.Time: return int64(x.Year()), nil case mysql.Duration: return int64(time.Now().Year()), nil default: intVal, err = ToInt64(x) } if err != nil { return invConv(val, tp) } y, err := mysql.AdjustYear(int(intVal)) if err != nil { return invConv(val, tp) } return int64(y), nil case mysql.TypeEnum: var ( e mysql.Enum err error ) switch x := val.(type) { case string: e, err = mysql.ParseEnumName(target.Elems, x) case []byte: e, err = mysql.ParseEnumName(target.Elems, string(x)) default: var number uint64 number, err = ToUint64(x) if err != nil { return nil, errors.Trace(err) } e, err = mysql.ParseEnumValue(target.Elems, number) } if err != nil { return invConv(val, tp) } return e, nil case mysql.TypeSet: var ( s mysql.Set err error ) switch x := val.(type) { case string: s, err = mysql.ParseSetName(target.Elems, x) case []byte: s, err = mysql.ParseSetName(target.Elems, string(x)) default: var number uint64 number, err = ToUint64(x) if err != nil { return nil, errors.Trace(err) } s, err = mysql.ParseSetValue(target.Elems, number) } if err != nil { return invConv(val, tp) } return s, nil case mysql.TypeNull: return nil, nil default: panic("should never happen") } }
func (rs *localRegion) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) { tid := ctx.sel.TableInfo.GetTableId() columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } rowData := make([][]byte, 0, len(columns)) for _, col := range columns { var colVal []byte if *col.PkHandle { if mysql.HasUnsignedFlag(uint(*col.Flag)) { // PK column is Unsigned var ud types.Datum ud.SetUint64(uint64(handle)) var err1 error colVal, err1 = codec.EncodeValue(nil, ud) if err1 != nil { return nil, errors.Trace(err1) } } else { colVal = row.Handle } } else { colID := col.GetColumnId() if ctx.whereColumns[colID] != nil { // The column is saved in evaluator, use it directly. datum := ctx.eval.Row[colID] var err1 error colVal, err1 = codec.EncodeValue(nil, datum) if err1 != nil { return nil, errors.Trace(err1) } } else { key := tablecodec.EncodeColumnKey(tid, handle, colID) var err1 error colVal, err1 = ctx.txn.Get(key) if err1 != nil { if !isDefaultNull(err1, col) { return nil, errors.Trace(err1) } colVal = []byte{codec.NilFlag} } } } rowData = append(rowData, colVal) } if ctx.aggregate { // Update aggregate functions. err = rs.aggregate(ctx, rowData) if err != nil { return nil, errors.Trace(err) } } else { // If without aggregate functions, just return raw row data. for _, d := range rowData { row.Data = append(row.Data, d...) } } return row, nil }