Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddl, util: Handle default values for generating column expressions when adding an index #9371

Merged
merged 8 commits into from
Feb 27, 2019
16 changes: 16 additions & 0 deletions ddl/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2361,4 +2361,20 @@ func (s *testDBSuite) TestAddIndexForGeneratedColumn(c *C) {
s.mustExec(c, "delete from t where y = 2155")
s.mustExec(c, "alter table t add index idx_y(y1)")
s.mustExec(c, "alter table t drop index idx_y")

// Fix issue 9311.
s.tk.MustExec("create table gcai_table (id int primary key);")
s.tk.MustExec("insert into gcai_table values(1);")
s.tk.MustExec("ALTER TABLE gcai_table ADD COLUMN d date DEFAULT '9999-12-31';")
s.tk.MustExec("ALTER TABLE gcai_table ADD COLUMN d1 date as (DATE_SUB(d, INTERVAL 31 DAY));")
s.tk.MustExec("ALTER TABLE gcai_table ADD INDEX idx(d1);")
s.tk.MustQuery("select * from gcai_table").Check(testkit.Rows("1 9999-12-31 9999-11-30"))
s.tk.MustQuery("select d1 from gcai_table use index(idx)").Check(testkit.Rows("9999-11-30"))
s.tk.MustExec("admin check table gcai_table")
// The column is PKIsHandle in generated column expression.
s.tk.MustExec("ALTER TABLE gcai_table ADD COLUMN id1 int as (id+5);")
s.tk.MustExec("ALTER TABLE gcai_table ADD INDEX idx1(id1);")
s.tk.MustQuery("select * from gcai_table").Check(testkit.Rows("1 9999-12-31 9999-11-30 6"))
s.tk.MustQuery("select id1 from gcai_table use index(idx1)").Check(testkit.Rows("6"))
s.tk.MustExec("admin check table gcai_table")
}
8 changes: 4 additions & 4 deletions ddl/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ func mergeAddIndexCtxToResult(taskCtx *addIndexTaskContext, result *addIndexResu

func newAddIndexWorker(sessCtx sessionctx.Context, worker *worker, id int, t table.PhysicalTable, indexInfo *model.IndexInfo, decodeColMap map[int64]decoder.Column) *addIndexWorker {
index := tables.NewIndex(t.GetPhysicalID(), t.Meta(), indexInfo)
rowDecoder := decoder.NewRowDecoder(t.Cols(), decodeColMap)
rowDecoder := decoder.NewRowDecoder(t, decodeColMap)
return &addIndexWorker{
id: id,
ddlWorker: worker,
Expand Down Expand Up @@ -547,7 +547,7 @@ func (w *addIndexWorker) getIndexRecord(handle int64, recordKey []byte, rawRecor
cols := t.Cols()
idxInfo := w.index.Meta()
sysZone := timeutil.SystemLocation()
_, err := w.rowDecoder.DecodeAndEvalRowWithMap(w.sessCtx, rawRecord, time.UTC, sysZone, w.rowMap)
_, err := w.rowDecoder.DecodeAndEvalRowWithMap(w.sessCtx, handle, rawRecord, time.UTC, sysZone, w.rowMap)
if err != nil {
return nil, errors.Trace(errCantDecodeIndex.GenWithStackByArgs(err))
}
Expand Down Expand Up @@ -899,13 +899,13 @@ func makeupDecodeColMap(sessCtx sessionctx.Context, t table.Table, indexInfo *mo
for _, v := range indexInfo.Columns {
col := cols[v.Offset]
tpExpr := decoder.Column{
Info: col.ToInfo(),
Col: col,
}
if col.IsGenerated() && !col.GeneratedStored {
for _, c := range cols {
if _, ok := col.Dependences[c.Name.L]; ok {
decodeColMap[c.ID] = decoder.Column{
Info: c.ToInfo(),
Col: c,
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions util/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,21 +591,21 @@ func makeRowDecoder(t table.Table, decodeCol []*table.Column, genExpr map[model.
for _, v := range decodeCol {
col := cols[v.Offset]
tpExpr := decoder.Column{
Info: col.ToInfo(),
Col: col,
}
if col.IsGenerated() && !col.GeneratedStored {
for _, c := range cols {
if _, ok := col.Dependences[c.Name.L]; ok {
decodeColsMap[c.ID] = decoder.Column{
Info: c.ToInfo(),
Col: c,
}
}
}
tpExpr.GenExpr = genExpr[model.TableColumnID{TableID: tblInfo.ID, ColumnID: col.ID}]
}
decodeColsMap[col.ID] = tpExpr
}
return decoder.NewRowDecoder(cols, decodeColsMap)
return decoder.NewRowDecoder(t, decodeColsMap)
}

// genExprs use to calculate generated column value.
Expand Down Expand Up @@ -633,7 +633,7 @@ func rowWithCols(sessCtx sessionctx.Context, txn kv.Retriever, t table.Table, h
}
}

rowMap, err := rowDecoder.DecodeAndEvalRowWithMap(sessCtx, value, sessCtx.GetSessionVars().Location(), time.UTC, nil)
rowMap, err := rowDecoder.DecodeAndEvalRowWithMap(sessCtx, h, value, sessCtx.GetSessionVars().Location(), time.UTC, nil)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down Expand Up @@ -694,7 +694,7 @@ func iterRecords(sessCtx sessionctx.Context, retriever kv.Retriever, t table.Tab
return errors.Trace(err)
}

rowMap, err := rowDecoder.DecodeAndEvalRowWithMap(sessCtx, it.Value(), sessCtx.GetSessionVars().Location(), time.UTC, nil)
rowMap, err := rowDecoder.DecodeAndEvalRowWithMap(sessCtx, handle, it.Value(), sessCtx.GetSessionVars().Location(), time.UTC, nil)
if err != nil {
return errors.Trace(err)
}
Expand Down
41 changes: 33 additions & 8 deletions util/rowDecoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,38 @@ import (
"time"

"github.com/pingcap/errors"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/tablecodec"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/chunk"
)

// Column contains the info and generated expr of column.
type Column struct {
Info *model.ColumnInfo
Col *table.Column
GenExpr expression.Expression
}

// RowDecoder decodes a byte slice into datums and eval the generated column value.
type RowDecoder struct {
tbl table.Table
mutRow chunk.MutRow
columns map[int64]Column
colTypes map[int64]*types.FieldType
haveGenColumn bool
defaultVals []types.Datum
}

// NewRowDecoder returns a new RowDecoder.
func NewRowDecoder(cols []*table.Column, decodeColMap map[int64]Column) *RowDecoder {
func NewRowDecoder(tbl table.Table, decodeColMap map[int64]Column) *RowDecoder {
colFieldMap := make(map[int64]*types.FieldType, len(decodeColMap))
haveGenCol := false
for id, col := range decodeColMap {
colFieldMap[id] = &col.Info.FieldType
colFieldMap[id] = &col.Col.ColumnInfo.FieldType
if col.GenExpr != nil {
haveGenCol = true
}
Expand All @@ -57,20 +59,23 @@ func NewRowDecoder(cols []*table.Column, decodeColMap map[int64]Column) *RowDeco
}
}

cols := tbl.Cols()
tps := make([]*types.FieldType, len(cols))
for _, col := range cols {
tps[col.Offset] = &col.FieldType
}
return &RowDecoder{
tbl: tbl,
mutRow: chunk.MutRowFromTypes(tps),
columns: decodeColMap,
colTypes: colFieldMap,
haveGenColumn: haveGenCol,
defaultVals: make([]types.Datum, len(cols)),
}
}

// DecodeAndEvalRowWithMap decodes a byte slice into datums and evaluates the generated column value.
func (rd *RowDecoder) DecodeAndEvalRowWithMap(ctx sessionctx.Context, b []byte, decodeLoc, sysLoc *time.Location, row map[int64]types.Datum) (map[int64]types.Datum, error) {
func (rd *RowDecoder) DecodeAndEvalRowWithMap(ctx sessionctx.Context, handle int64, b []byte, decodeLoc, sysLoc *time.Location, row map[int64]types.Datum) (map[int64]types.Datum, error) {
row, err := tablecodec.DecodeRowWithMap(b, rd.colTypes, decodeLoc, row)
if err != nil {
return nil, errors.Trace(err)
Expand All @@ -79,8 +84,28 @@ func (rd *RowDecoder) DecodeAndEvalRowWithMap(ctx sessionctx.Context, b []byte,
return row, nil
}

for id, v := range row {
rd.mutRow.SetValue(rd.columns[id].Info.Offset, v.GetValue())
for _, dCol := range rd.columns {
colInfo := dCol.Col.ColumnInfo
val, ok := row[colInfo.ID]
if ok || dCol.GenExpr != nil {
rd.mutRow.SetValue(colInfo.Offset, val.GetValue())
continue
}

// Get the default value of the column in the generated column expression.
if dCol.Col.IsPKHandleColumn(rd.tbl.Meta()) {
if mysql.HasUnsignedFlag(colInfo.Flag) {
val.SetUint64(uint64(handle))
} else {
val.SetInt64(handle)
}
} else {
val, err = tables.GetColDefaultValue(ctx, dCol.Col, rd.defaultVals)
if err != nil {
return nil, errors.Trace(err)
}
}
rd.mutRow.SetValue(colInfo.Offset, val.GetValue())
}
for id, col := range rd.columns {
if col.GenExpr == nil {
Expand All @@ -91,7 +116,7 @@ func (rd *RowDecoder) DecodeAndEvalRowWithMap(ctx sessionctx.Context, b []byte,
if err != nil {
return nil, errors.Trace(err)
}
val, err = table.CastValue(ctx, val, col.Info)
val, err = table.CastValue(ctx, val, col.Col.ColumnInfo)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down