// 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) }
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 (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 (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 }
// 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 }
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 }
func (n *aggregateFuncExpr) toDatums() (ds []types.Datum, err error) { switch n.expr.GetTp() { case tipb.ExprType_Count: ds = n.getCountDatum() case tipb.ExprType_First, tipb.ExprType_Max, tipb.ExprType_Min: ds = n.getValueDatum() case tipb.ExprType_Sum: d, err := getSumValue(n.getAggItem()) if err != nil { return nil, errors.Trace(err) } ds = []types.Datum{d} case tipb.ExprType_Avg: item := n.getAggItem() sum, err := getSumValue(item) if err != nil { return nil, errors.Trace(err) } cnt := types.NewUintDatum(item.count) ds = []types.Datum{cnt, sum} } return }
// Convert count to datum list. func (n *aggregateFuncExpr) getCountDatum() []types.Datum { item := n.getAggItem() return []types.Datum{types.NewUintDatum(item.count)} }
// TODO: add more tests. func (s *testEvalSuite) TestEval(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} cases := []struct { expr *tipb.Expr result types.Datum }{ // Datums. { datumExpr(types.NewFloat32Datum(1.1)), types.NewFloat32Datum(1.1), }, { datumExpr(types.NewFloat64Datum(1.1)), types.NewFloat64Datum(1.1), }, { datumExpr(types.NewIntDatum(1)), types.NewIntDatum(1), }, { datumExpr(types.NewUintDatum(1)), types.NewUintDatum(1), }, { datumExpr(types.NewBytesDatum([]byte("abc"))), types.NewBytesDatum([]byte("abc")), }, { datumExpr(types.NewStringDatum("abc")), types.NewStringDatum("abc"), }, { datumExpr(types.Datum{}), types.Datum{}, }, { datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})), types.NewDurationDatum(mysql.Duration{Duration: time.Hour}), }, { datumExpr(types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1))), types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1)), }, { columnExpr(1), types.NewIntDatum(100), }, // Comparison operations. { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_LT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_EQ), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_EQ), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_EQ), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_NE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_NE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_NE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_GT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(0), }, { binaryExpr(types.Datum{}, types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(1), }, // Logic operation. { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_And), types.Datum{}, }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(0), tipb.ExprType_Or), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_Or), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr( binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), tipb.ExprType_And), types.NewIntDatum(1), }, { notExpr(datumExpr(types.NewIntDatum(1))), types.NewIntDatum(0), }, { notExpr(datumExpr(types.NewIntDatum(0))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.Datum{})), types.Datum{}, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (s *testColumnSuite) TestGetZeroValue(c *C) { cases := []struct { ft *types.FieldType value types.Datum }{ { types.NewFieldType(mysql.TypeLong), types.NewIntDatum(0), }, { &types.FieldType{ Tp: mysql.TypeLonglong, Flag: mysql.UnsignedFlag, }, types.NewUintDatum(0), }, { types.NewFieldType(mysql.TypeFloat), types.NewFloat32Datum(0), }, { types.NewFieldType(mysql.TypeDouble), types.NewFloat64Datum(0), }, { types.NewFieldType(mysql.TypeNewDecimal), types.NewDecimalDatum(mysql.NewDecimalFromInt(0, 0)), }, { types.NewFieldType(mysql.TypeVarchar), types.NewStringDatum(""), }, { types.NewFieldType(mysql.TypeBlob), types.NewBytesDatum([]byte{}), }, { types.NewFieldType(mysql.TypeDuration), types.NewDurationDatum(mysql.ZeroDuration), }, { types.NewFieldType(mysql.TypeDatetime), types.NewDatum(mysql.ZeroDatetime), }, { types.NewFieldType(mysql.TypeTimestamp), types.NewDatum(mysql.ZeroTimestamp), }, { types.NewFieldType(mysql.TypeDate), types.NewDatum(mysql.ZeroDate), }, { types.NewFieldType(mysql.TypeBit), types.NewDatum(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}), }, { types.NewFieldType(mysql.TypeSet), types.NewDatum(mysql.Set{}), }, } for _, ca := range cases { colInfo := &model.ColumnInfo{FieldType: *ca.ft} zv := getZeroValue(colInfo) c.Assert(zv.Kind(), Equals, ca.value.Kind()) cmp, err := zv.CompareDatum(ca.value) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
// TODO: add more tests. func (s *testEvalSuite) TestEval(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} cases := []struct { expr *tipb.Expr result types.Datum }{ // Datums. { datumExpr(types.NewFloat32Datum(1.1)), types.NewFloat32Datum(1.1), }, { datumExpr(types.NewFloat64Datum(1.1)), types.NewFloat64Datum(1.1), }, { datumExpr(types.NewIntDatum(1)), types.NewIntDatum(1), }, { datumExpr(types.NewUintDatum(1)), types.NewUintDatum(1), }, { datumExpr(types.NewBytesDatum([]byte("abc"))), types.NewBytesDatum([]byte("abc")), }, { datumExpr(types.NewStringDatum("abc")), types.NewStringDatum("abc"), }, { datumExpr(types.Datum{}), types.Datum{}, }, { datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})), types.NewDurationDatum(mysql.Duration{Duration: time.Hour}), }, { datumExpr(types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1))), types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1)), }, { columnExpr(1), types.NewIntDatum(100), }, // Comparison operations. { buildExpr(tipb.ExprType_LT, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_LT, types.NewIntDatum(1), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_LT, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(1), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(1), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_NullEQ, types.NewIntDatum(1), types.Datum{}), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_NullEQ, types.Datum{}, types.Datum{}), types.NewIntDatum(1), }, // Logic operation. { buildExpr(tipb.ExprType_And, types.NewIntDatum(0), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(1), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(0), types.Datum{}), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(1), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.NewIntDatum(0)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(1), types.Datum{}), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_And, buildExpr(tipb.ExprType_EQ, types.NewIntDatum(1), types.NewIntDatum(1)), buildExpr(tipb.ExprType_EQ, types.NewIntDatum(1), types.NewIntDatum(1))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.NewIntDatum(1))), types.NewIntDatum(0), }, { notExpr(datumExpr(types.NewIntDatum(0))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.Datum{})), types.Datum{}, }, // Arithmetic operation. { buildExpr(tipb.ExprType_Plus, types.NewIntDatum(-1), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_Plus, types.NewIntDatum(-1), types.NewFloat64Datum(1.5)), types.NewFloat64Datum(0.5), }, { buildExpr(tipb.ExprType_Minus, types.NewIntDatum(-1), types.NewIntDatum(1)), types.NewIntDatum(-2), }, { buildExpr(tipb.ExprType_Minus, types.NewIntDatum(-1), types.NewFloat64Datum(1.5)), types.NewFloat64Datum(-2.5), }, { buildExpr(tipb.ExprType_Mul, types.NewFloat64Datum(-1), types.NewFloat64Datum(1)), types.NewFloat64Datum(-1), }, { buildExpr(tipb.ExprType_Mul, types.NewFloat64Datum(-1.5), types.NewFloat64Datum(2)), types.NewFloat64Datum(-3), }, { buildExpr(tipb.ExprType_Div, types.NewFloat64Datum(-3), types.NewFloat64Datum(2)), types.NewFloat64Datum(-1.5), }, { buildExpr(tipb.ExprType_Div, types.NewFloat64Datum(-3), types.NewFloat64Datum(0)), types.NewDatum(nil), }, { buildExpr(tipb.ExprType_IntDiv, types.NewIntDatum(3), types.NewIntDatum(2)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_IntDiv, types.NewFloat64Datum(3.0), types.NewFloat64Datum(1.9)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Mod, types.NewIntDatum(3), types.NewIntDatum(2)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Mod, types.NewFloat64Datum(3.0), types.NewFloat64Datum(1.9)), types.NewFloat64Datum(1.1), }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }