func flatten(data types.Datum) (types.Datum, error) { switch data.Kind() { case types.KindMysqlTime: // for mysql datetime, timestamp and date type v, err := data.GetMysqlTime().ToPackedUint() return types.NewUintDatum(v), errors.Trace(err) case types.KindMysqlDuration: // for mysql time type data.SetInt64(int64(data.GetMysqlDuration().Duration)) return data, nil case types.KindMysqlEnum: data.SetUint64(data.GetMysqlEnum().Value) return data, nil case types.KindMysqlSet: data.SetUint64(data.GetMysqlSet().Value) return data, nil case types.KindMysqlBit: data.SetUint64(data.GetMysqlBit().Value) return data, nil case types.KindMysqlHex: data.SetInt64(data.GetMysqlHex().Value) return data, nil default: return data, nil } }
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 }
func flatten(data types.Datum) (types.Datum, error) { switch data.Kind() { case types.KindMysqlTime: // for mysql datetime, timestamp and date type b, err := data.GetMysqlTime().Marshal() if err != nil { return types.NewDatum(nil), errors.Trace(err) } return types.NewDatum(b), nil case types.KindMysqlDuration: // for mysql time type data.SetInt64(int64(data.GetMysqlDuration().Duration)) return data, nil case types.KindMysqlDecimal: data.SetString(data.GetMysqlDecimal().String()) return data, nil case types.KindMysqlEnum: data.SetUint64(data.GetMysqlEnum().Value) return data, nil case types.KindMysqlSet: data.SetUint64(data.GetMysqlSet().Value) return data, nil case types.KindMysqlBit: data.SetUint64(data.GetMysqlBit().Value) return data, nil case types.KindMysqlHex: data.SetInt64(data.GetMysqlHex().Value) return data, nil default: return data, nil } }
func (e *Evaluator) evalInt(val []byte) (types.Datum, error) { var d types.Datum _, i, err := codec.DecodeInt(val) if err != nil { return d, ErrInvalid.Gen("invalid int % x", val) } d.SetInt64(i) return d, nil }
func (s *testEvaluatorSuite) TestFromUnixTime(c *C) { defer testleak.AfterTest(c)() tbl := []struct { isDecimal bool integralPart int64 fractionalPart int64 decimal float64 format string ansLen int }{ {false, 1451606400, 0, 0, "", 19}, {true, 1451606400, 123456000, 1451606400.123456, "", 26}, {true, 1451606400, 999999000, 1451606400.999999, "", 26}, {true, 1451606400, 999999900, 1451606400.9999999, "", 19}, {false, 1451606400, 0, 0, "%Y %D %M %h:%i:%s %x", 19}, {true, 1451606400, 123456000, 1451606400.123456, "%Y %D %M %h:%i:%s %x", 26}, {true, 1451606400, 999999000, 1451606400.999999, "%Y %D %M %h:%i:%s %x", 26}, {true, 1451606400, 999999900, 1451606400.9999999, "%Y %D %M %h:%i:%s %x", 19}, } for _, t := range tbl { var timestamp types.Datum if !t.isDecimal { timestamp.SetInt64(t.integralPart) } else { timestamp.SetFloat64(t.decimal) } // result of from_unixtime() is dependent on specific time zone. unixTime := time.Unix(t.integralPart, t.fractionalPart).Round(time.Microsecond).String()[:t.ansLen] if len(t.format) == 0 { v, err := builtinFromUnixTime([]types.Datum{timestamp}, s.ctx) c.Assert(err, IsNil) ans := v.GetMysqlTime() c.Assert(ans.String(), Equals, unixTime) } else { format := types.NewStringDatum(t.format) v, err := builtinFromUnixTime([]types.Datum{timestamp, format}, s.ctx) c.Assert(err, IsNil) result, err := builtinDateFormat([]types.Datum{types.NewStringDatum(unixTime), format}, s.ctx) c.Assert(err, IsNil) c.Assert(v.GetString(), Equals, result.GetString()) } } v, err := builtinFromUnixTime([]types.Datum{types.NewIntDatum(-12345)}, s.ctx) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindNull) _, err = builtinFromUnixTime([]types.Datum{types.NewIntDatum(math.MaxInt32 + 1)}, s.ctx) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindNull) }
// evalXor computes result of (X XOR Y). func (e *Evaluator) evalXor(leftBool, rightBool int64) (types.Datum, error) { var d types.Datum if leftBool == compareResultNull || rightBool == compareResultNull { d.SetNull() return d, nil } if leftBool == rightBool { d.SetInt64(0) return d, nil } d.SetInt64(1) return d, 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 (e *Evaluator) evalOr(expr *tipb.Expr) (types.Datum, error) { leftBool, rightBool, err := e.evalTwoBoolChildren(expr) if err != nil { return types.Datum{}, errors.Trace(err) } var d types.Datum if leftBool == 1 || rightBool == 1 { d.SetInt64(1) return d, nil } if leftBool == compareResultNull || rightBool == compareResultNull { d.SetNull() return d, nil } d.SetInt64(0) return d, nil }
func getIndexRowFromRange(idxInfo *tipb.IndexInfo, txn kv.Transaction, ran kv.KeyRange, desc bool, limit int64) ([]*tipb.Row, error) { var rows []*tipb.Row var seekKey kv.Key if desc { seekKey = ran.EndKey } else { seekKey = ran.StartKey } for { if limit == 0 { break } var it kv.Iterator var err error if desc { it, err = txn.SeekReverse(seekKey) if err != nil { return nil, errors.Trace(err) } seekKey = it.Key() } else { it, err = txn.Seek(seekKey) if err != nil { return nil, errors.Trace(err) } seekKey = it.Key().PrefixNext() } if !it.Valid() { break } if desc { if it.Key().Cmp(ran.StartKey) < 0 { break } } else { if it.Key().Cmp(ran.EndKey) >= 0 { break } } datums, err := tablecodec.DecodeIndexKey(it.Key()) if err != nil { return nil, errors.Trace(err) } var handle types.Datum if len(datums) > len(idxInfo.Columns) { handle = datums[len(idxInfo.Columns)] datums = datums[:len(idxInfo.Columns)] } else { var intHandle int64 intHandle, err = decodeHandle(it.Value()) if err != nil { return nil, errors.Trace(err) } handle.SetInt64(intHandle) } data, err := codec.EncodeValue(nil, datums...) if err != nil { return nil, errors.Trace(err) } handleData, err := codec.EncodeValue(nil, handle) if err != nil { return nil, errors.Trace(err) } row := &tipb.Row{Handle: handleData, Data: data} rows = append(rows, row) limit-- } return rows, nil }
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 }
// 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 }
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekofyear func builtinWeekOfYear(args []types.Datum, ctx context.Context) (types.Datum, error) { // WeekOfYear is equivalent to to Week(date, 3) d := types.Datum{} d.SetInt64(3) return builtinWeek([]types.Datum{args[0], d}, ctx) }
func convertDateFormat(ctx context.Context, arg types.Datum, b byte) (types.Datum, error) { var d types.Datum var err error switch b { case 'b': d, err = builtinMonthName([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(d.GetString()[:3]) } case 'M': d, err = builtinMonthName([]types.Datum{arg}, ctx) case 'm': d, err = builtinMonth([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'c': d, err = builtinMonth([]types.Datum{arg}, ctx) case 'D': d, err = abbrDayOfMonth(arg, ctx) case 'd': d, err = builtinDayOfMonth([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'e': d, err = builtinDayOfMonth([]types.Datum{arg}, ctx) case 'j': d, err = builtinDayOfYear([]types.Datum{arg}, ctx) if err == nil { d.SetString(fmt.Sprintf("%03d", d.GetInt64())) } case 'H', 'k': d, err = builtinHour([]types.Datum{arg}, ctx) if err == nil && b == 'H' && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'h', 'I', 'l': d, err = builtinHour([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { if d.GetInt64() > 12 { d.SetInt64(d.GetInt64() - 12) } else if d.GetInt64() == 0 { d.SetInt64(12) } d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'i': d, err = builtinMinute([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'p': d, err = builtinHour([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { if d.GetInt64() < 12 { d.SetString("AM") break } d.SetString("PM") } case 'r': d, err = to12Hour(arg, ctx) case 'T': d, err = builtinTime([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { duration := types.Duration{ Duration: d.GetMysqlDuration().Duration, Fsp: 0} d.SetMysqlDuration(duration) } case 'S', 's': d, err = builtinSecond([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'f': d, err = builtinMicroSecond([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%06d", d.GetInt64())) } case 'U': d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(0)}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'u': d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(1)}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'V': d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(2)}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'v': d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(3)}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%02d", d.GetInt64())) } case 'a': d, err = builtinDayName([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(d.GetString()[:3]) } case 'W': d, err = builtinDayName([]types.Datum{arg}, ctx) case 'w': d, err = builtinDayOfWeek([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetInt64(d.GetInt64() - 1) } case 'X': d, err = builtinYearWeek([]types.Datum{arg, types.NewIntDatum(2)}, ctx) if err == nil && !d.IsNull() { if d.GetInt64() == math.MaxUint32 { break } str := fmt.Sprintf("%04d", d.GetInt64()) d.SetString(fmt.Sprintf("%04s", str[:4])) } case 'x': d, err = builtinYearWeek([]types.Datum{arg, types.NewIntDatum(3)}, ctx) if err == nil && !d.IsNull() { if d.GetInt64() == math.MaxUint32 { break } str := fmt.Sprintf("%04d", d.GetInt64()) d.SetString(fmt.Sprintf("%04s", str[:4])) } case 'Y': d, err = builtinYear([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%04d", d.GetInt64())) } case 'y': d, err = builtinYear([]types.Datum{arg}, ctx) if err == nil && !d.IsNull() { str := fmt.Sprintf("%04d", d.GetInt64()) d.SetString(fmt.Sprintf("%02s", str[2:])) } default: d.SetString(string(b)) } if err == nil && !d.IsNull() { d.SetString(fmt.Sprintf("%v", d.GetValue())) } return d, errors.Trace(err) }
func (h *rpcHandler) getIndexRowFromRange(sel *tipb.SelectRequest, ran kv.KeyRange, desc bool, limit int64) ([]*tipb.Row, error) { startKey := maxStartKey(ran.StartKey, h.startKey) endKey := minEndKey(ran.EndKey, h.endKey) if limit == 0 || bytes.Compare(startKey, endKey) >= 0 { return nil, nil } var rows []*tipb.Row var seekKey kv.Key if desc { seekKey = endKey } else { seekKey = startKey } for { if limit == 0 { break } var ( pairs []Pair pair Pair err error ) if desc { pairs = h.mvccStore.ReverseScan(startKey, seekKey, 1, sel.GetStartTs()) } else { pairs = h.mvccStore.Scan(seekKey, endKey, 1, sel.GetStartTs()) } if len(pairs) > 0 { pair = pairs[0] } if pair.Err != nil { // TODO: handle lock error. return nil, errors.Trace(pair.Err) } if pair.Key == nil { break } if desc { if bytes.Compare(pair.Key, startKey) < 0 { break } seekKey = pair.Key } else { if bytes.Compare(pair.Key, endKey) >= 0 { break } seekKey = []byte(kv.Key(pair.Key).PrefixNext()) } datums, err := tablecodec.DecodeIndexKey(pair.Key) if err != nil { return nil, errors.Trace(err) } var handle types.Datum columns := sel.IndexInfo.Columns if len(datums) > len(columns) { handle = datums[len(columns)] datums = datums[:len(columns)] } else { var intHandle int64 intHandle, err = decodeHandle(pair.Value) if err != nil { return nil, errors.Trace(err) } handle.SetInt64(intHandle) } data, err := codec.EncodeValue(nil, datums...) if err != nil { return nil, errors.Trace(err) } handleData, err := codec.EncodeValue(nil, handle) if err != nil { return nil, errors.Trace(err) } row := &tipb.Row{Handle: handleData, Data: data} rows = append(rows, row) limit-- } return rows, 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 }