From 3f468ecf4021826122331ce1b4d0925e2bb795f1 Mon Sep 17 00:00:00 2001 From: JmPotato Date: Fri, 10 Dec 2021 17:18:59 +0800 Subject: [PATCH 1/2] Show PK name when decoding the clustered index row key (close #30615) Signed-off-by: JmPotato --- ddl/ddl_api.go | 6 ++-- executor/infoschema_reader.go | 2 +- executor/show.go | 2 +- expression/builtin_info.go | 2 +- expression/integration_test.go | 43 ++++++++++++++++++++++++----- parser/model/model.go | 5 ++++ planner/core/expression_rewriter.go | 7 ++++- planner/core/planbuilder.go | 4 +-- 8 files changed, 55 insertions(+), 16 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 965213864f687..632aa4874556a 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1577,7 +1577,7 @@ func buildTableInfo( tbInfo.CommonHandleVersion = 1 } } - if tbInfo.PKIsHandle || tbInfo.IsCommonHandle { + if tbInfo.HasClusteredIndex() { // Primary key cannot be invisible. if constr.Option != nil && constr.Option.Visibility == ast.IndexVisibilityInvisible { return nil, ErrPKIndexCantBeInvisible @@ -2438,7 +2438,7 @@ func handleTableOptions(options []*ast.TableOption, tbInfo *model.TableInfo) err case ast.TableOptionCompression: tbInfo.Compression = op.StrValue case ast.TableOptionShardRowID: - if op.UintValue > 0 && (tbInfo.PKIsHandle || tbInfo.IsCommonHandle) { + if op.UintValue > 0 && tbInfo.HasClusteredIndex() { return errUnsupportedShardRowIDBits } tbInfo.ShardRowIDBits = op.UintValue @@ -2946,7 +2946,7 @@ func (d *ddl) ShardRowID(ctx sessionctx.Context, tableIdent ast.Ident, uVal uint // Nothing need to do. return nil } - if uVal > 0 && (t.Meta().PKIsHandle || t.Meta().IsCommonHandle) { + if uVal > 0 && t.Meta().HasClusteredIndex() { return errUnsupportedShardRowIDBits } err = verifyNoOverflowShardBits(d.sessPool, t, uVal) diff --git a/executor/infoschema_reader.go b/executor/infoschema_reader.go index 483e970d479fc..1e4fcae3829ba 100644 --- a/executor/infoschema_reader.go +++ b/executor/infoschema_reader.go @@ -579,7 +579,7 @@ func (e *memtableRetriever) setDataFromTables(ctx context.Context, sctx sessionc rowCount = 1 } } - if table.PKIsHandle || table.IsCommonHandle { + if table.HasClusteredIndex() { pkType = "CLUSTERED" } shardingInfo := infoschema.GetShardingInfo(schema, table) diff --git a/executor/show.go b/executor/show.go index 935b2c6bae64a..2a4eac148f74e 100644 --- a/executor/show.go +++ b/executor/show.go @@ -975,7 +975,7 @@ func ConstructResultOfShowCreateTable(ctx sessionctx.Context, tableInfo *model.T fmt.Fprintf(buf, ` COMMENT '%s'`, format.OutputFormat(idxInfo.Comment)) } if idxInfo.Primary { - if tableInfo.PKIsHandle || tableInfo.IsCommonHandle { + if tableInfo.HasClusteredIndex() { buf.WriteString(" /*T![clustered_index] CLUSTERED */") } else { buf.WriteString(" /*T![clustered_index] NONCLUSTERED */") diff --git a/expression/builtin_info.go b/expression/builtin_info.go index 013ee74d66bac..22018213ef9e7 100644 --- a/expression/builtin_info.go +++ b/expression/builtin_info.go @@ -746,7 +746,7 @@ func (b *builtinTiDBDecodeKeySig) Clone() builtinFunc { return newSig } -// evalInt evals a builtinTiDBIsDDLOwnerSig. +// evalInt evals a builtinTiDBDecodeKeySig. func (b *builtinTiDBDecodeKeySig) evalString(row chunk.Row) (string, bool, error) { s, isNull, err := b.args[0].EvalString(b.ctx, row) if isNull || err != nil { diff --git a/expression/integration_test.go b/expression/integration_test.go index 616b8d793b7da..b5c89730373a3 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2826,7 +2826,7 @@ func TestTiDBDecodePlanFunc(t *testing.T) { tk.MustQuery("select tidb_decode_plan('xxx')").Check(testkit.Rows("xxx")) } -func TestTiDBInternalFunc(t *testing.T) { +func TestTiDBDecodeKeyFunc(t *testing.T) { t.Parallel() store, clean := testkit.CreateMockStore(t) @@ -2876,16 +2876,14 @@ func TestTiDBInternalFunc(t *testing.T) { h, err := kv.NewCommonHandle(k) require.NoError(t, err) k = tablecodec.EncodeRowKeyWithHandle(tableID, h) - hexKey := hex.EncodeToString(codec.EncodeBytes(nil, k)) - return hexKey + return hex.EncodeToString(codec.EncodeBytes(nil, k)) } // split table t by ('bbbb', 10, '2020-01-01'); data := []types.Datum{types.NewStringDatum("bbbb"), types.NewIntDatum(10), types.NewTimeDatum(getTime(2020, 1, 1, mysql.TypeDatetime))} hexKey := buildCommonKeyFromData(tbl.Meta().ID, data) sql := fmt.Sprintf("select tidb_decode_key( '%s' )", hexKey) - result = tk.MustQuery(sql) rs := fmt.Sprintf(`{"handle":{"a":"bbbb","b":"10","c":"2020-01-01 00:00:00"},"table_id":%d}`, tbl.Meta().ID) - result.Check(testkit.Rows(rs)) + tk.MustQuery(sql).Check(testkit.Rows(rs)) // split table t by ('bbbb', 10, null); data = []types.Datum{types.NewStringDatum("bbbb"), types.NewIntDatum(10), types.NewDatum(nil)} @@ -2903,8 +2901,7 @@ func TestTiDBInternalFunc(t *testing.T) { k, err := codec.EncodeKey(tk.Session().GetSessionVars().StmtCtx, nil, data...) require.NoError(t, err) k = tablecodec.EncodeIndexSeekKey(tableID, indexID, k) - hexKey := hex.EncodeToString(codec.EncodeBytes(nil, k)) - return hexKey + return hex.EncodeToString(codec.EncodeBytes(nil, k)) } // split table t index idx by ('aaaaa', 100, '2000-01-01'); data = []types.Datum{types.NewStringDatum("aaaaa"), types.NewIntDatum(100), types.NewTimeDatum(getTime(2000, 1, 1, mysql.TypeDatetime))} @@ -2925,6 +2922,38 @@ func TestTiDBInternalFunc(t *testing.T) { hexKey = "7480000000000000375F69800000000000000103800000000001D4C1023B6458" sql = fmt.Sprintf("select tidb_decode_key( '%s' )", hexKey) tk.MustQuery(sql).Check(testkit.Rows(hexKey)) + + // Test the table with the nonclustered index. + const rowID = 10 + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (a int primary key nonclustered, b int, key bk (b));") + dom = domain.GetDomain(tk.Session()) + is = dom.InfoSchema() + tbl, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + require.NoError(t, err) + buildTableRowKey := func(tableID, rowID int64) string { + return hex.EncodeToString( + codec.EncodeBytes( + nil, + tablecodec.EncodeRowKeyWithHandle(tableID, kv.IntHandle(rowID)), + )) + } + hexKey = buildTableRowKey(tbl.Meta().ID, rowID) + sql = fmt.Sprintf("select tidb_decode_key( '%s' )", hexKey) + rs = fmt.Sprintf(`{"_tidb_rowid":%d,"table_id":"%d"}`, rowID, tbl.Meta().ID) + tk.MustQuery(sql).Check(testkit.Rows(rs)) + + // Test the table with the clustered index. + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (a int primary key clustered, b int, key bk (b));") + dom = domain.GetDomain(tk.Session()) + is = dom.InfoSchema() + tbl, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + require.NoError(t, err) + hexKey = buildTableRowKey(tbl.Meta().ID, rowID) + sql = fmt.Sprintf("select tidb_decode_key( '%s' )", hexKey) + rs = fmt.Sprintf(`{"a":%d,"table_id":"%d"}`, rowID, tbl.Meta().ID) + tk.MustQuery(sql).Check(testkit.Rows(rs)) } func TestTwoDecimalTruncate(t *testing.T) { diff --git a/parser/model/model.go b/parser/model/model.go index 20e770c607149..c08ea8b8b309c 100644 --- a/parser/model/model.go +++ b/parser/model/model.go @@ -656,6 +656,11 @@ func (t *TableInfo) ColumnIsInIndex(c *ColumnInfo) bool { return false } +// HasClusteredIndex checks whether the table has a clustered index. +func (t *TableInfo) HasClusteredIndex() bool { + return t.PKIsHandle || t.IsCommonHandle +} + // IsView checks if TableInfo is a view. func (t *TableInfo) IsView() bool { return t.View != nil diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index a370fdaa36697..8f950b3d3ece5 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -2030,7 +2030,12 @@ func decodeRecordKey(key []byte, tableID int64, tbl table.Table, loc *time.Locat if handle.IsInt() { ret := make(map[string]interface{}) ret["table_id"] = strconv.FormatInt(tableID, 10) - ret["_tidb_rowid"] = handle.IntValue() + // When the clustered index is enabled, we should show the PK name. + if tbl.Meta().HasClusteredIndex() { + ret[tbl.Meta().GetPkName().String()] = handle.IntValue() + } else { + ret["_tidb_rowid"] = handle.IntValue() + } retStr, err := json.Marshal(ret) if err != nil { return "", errors.Trace(err) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 3dd919749c25b..b830d26da025d 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -960,7 +960,7 @@ func getPathByIndexName(paths []*util.AccessPath, idxName model.CIStr, tblInfo * return path } } - if isPrimaryIndex(idxName) && (tblInfo.PKIsHandle || tblInfo.IsCommonHandle) { + if isPrimaryIndex(idxName) && tblInfo.HasClusteredIndex() { return tablePath } return nil @@ -1707,7 +1707,7 @@ func getColsInfo(tn *ast.TableName) (indicesInfo []*model.IndexInfo, colsInfo [] if col.IsGenerated() && !col.GeneratedStored { continue } - if mysql.HasPriKeyFlag(col.Flag) && (tbl.PKIsHandle || tbl.IsCommonHandle) { + if mysql.HasPriKeyFlag(col.Flag) && tbl.HasClusteredIndex() { continue } colsInfo = append(colsInfo, col) From e1b65d49c4599362a49516dab3159ad889c504a6 Mon Sep 17 00:00:00 2001 From: JmPotato Date: Fri, 10 Dec 2021 17:47:25 +0800 Subject: [PATCH 2/2] Refine the test Signed-off-by: JmPotato --- expression/integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index b5c89730373a3..677b33d68a500 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2952,7 +2952,7 @@ func TestTiDBDecodeKeyFunc(t *testing.T) { require.NoError(t, err) hexKey = buildTableRowKey(tbl.Meta().ID, rowID) sql = fmt.Sprintf("select tidb_decode_key( '%s' )", hexKey) - rs = fmt.Sprintf(`{"a":%d,"table_id":"%d"}`, rowID, tbl.Meta().ID) + rs = fmt.Sprintf(`{"%s":%d,"table_id":"%d"}`, tbl.Meta().GetPkName().String(), rowID, tbl.Meta().ID) tk.MustQuery(sql).Check(testkit.Rows(rs)) }