Skip to content

Commit 0bbbbbe

Browse files
planner: suppress column number in plan_tree explain (#65148)
ref #63118
1 parent 3f5e128 commit 0bbbbbe

File tree

99 files changed

+3253
-3173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+3253
-3173
lines changed

pkg/executor/select.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,18 +1073,21 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
10731073
sc.OriginalSQL = s.Text()
10741074
if explainStmt, ok := s.(*ast.ExplainStmt); ok {
10751075
sc.InExplainStmt = true
1076-
sc.ExplainFormat = explainStmt.Format
1076+
// Normalize to lowercase to avoid repeated conversions in shouldRemoveColumnNumbers and other places
1077+
sc.ExplainFormat = strings.ToLower(explainStmt.Format)
10771078
sc.InExplainAnalyzeStmt = explainStmt.Analyze
1078-
sc.IgnoreExplainIDSuffix = strings.ToLower(explainStmt.Format) == types.ExplainFormatBrief || strings.ToLower(explainStmt.Format) == types.ExplainFormatPlanTree
1079-
sc.InVerboseExplain = strings.ToLower(explainStmt.Format) == types.ExplainFormatVerbose
1079+
sc.IgnoreExplainIDSuffix = sc.ExplainFormat == types.ExplainFormatBrief || sc.ExplainFormat == types.ExplainFormatPlanTree
1080+
sc.InVerboseExplain = sc.ExplainFormat == types.ExplainFormatVerbose
10801081
s = explainStmt.Stmt
10811082
} else {
10821083
sc.ExplainFormat = ""
10831084
}
10841085
if explainForStmt, ok := s.(*ast.ExplainForStmt); ok {
10851086
sc.InExplainStmt = true
10861087
sc.InExplainAnalyzeStmt = true
1087-
sc.InVerboseExplain = strings.ToLower(explainForStmt.Format) == types.ExplainFormatVerbose
1088+
// Normalize to lowercase to avoid repeated conversions in shouldRemoveColumnNumbers and other places
1089+
sc.ExplainFormat = strings.ToLower(explainForStmt.Format)
1090+
sc.InVerboseExplain = sc.ExplainFormat == types.ExplainFormatVerbose
10881091
}
10891092

10901093
// TODO: Many same bool variables here.
@@ -1246,7 +1249,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
12461249
}
12471250

12481251
sc.SetForcePlanCache(fixcontrol.GetBoolWithDefault(vars.OptimizerFixControl, fixcontrol.Fix49736, false))
1249-
sc.SetAlwaysWarnSkipCache(sc.InExplainStmt && sc.ExplainFormat == "plan_cache")
1252+
sc.SetAlwaysWarnSkipCache(sc.InExplainStmt && sc.ExplainFormat == types.ExplainFormatPlanCache)
12501253
errCount, warnCount := vars.StmtCtx.NumErrorWarnings()
12511254
vars.SysErrorCount = errCount
12521255
vars.SysWarningCount = warnCount

pkg/expression/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ go_library(
8383
"//pkg/errno",
8484
"//pkg/expression/exprctx",
8585
"//pkg/expression/expropt",
86+
"//pkg/expression/sessionexpr",
8687
"//pkg/extension",
8788
"//pkg/infoschema/context",
8889
"//pkg/kv",

pkg/expression/column.go

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/pingcap/errors"
2525
"github.com/pingcap/tidb/pkg/expression/exprctx"
26+
"github.com/pingcap/tidb/pkg/expression/sessionexpr"
2627
"github.com/pingcap/tidb/pkg/meta/model"
2728
"github.com/pingcap/tidb/pkg/parser/ast"
2829
"github.com/pingcap/tidb/pkg/parser/charset"
@@ -448,17 +449,45 @@ func (col *Column) VecEvalVectorFloat32(ctx EvalContext, input *chunk.Chunk, res
448449

449450
const columnPrefix = "Column#"
450451

452+
// shouldRemoveColumnNumbers checks if column numbers should be removed based on the explain format.
453+
// This is used for plan_tree format to show "Column" instead of "Column#<number>".
454+
// Note: ExplainFormat is normalized to lowercase when set, but we use strings.ToLower as a defensive measure
455+
// in case the format wasn't normalized in some code path.
456+
func shouldRemoveColumnNumbers(ctx ParamValues) bool {
457+
if evalCtx, ok := ctx.(EvalContext); ok {
458+
if sessionCtx, ok := evalCtx.(*sessionexpr.EvalContext); ok {
459+
stmtCtx := sessionCtx.Sctx().GetSessionVars().StmtCtx
460+
// Only check format if we're actually in an explain statement
461+
if !stmtCtx.InExplainStmt {
462+
return false
463+
}
464+
format := stmtCtx.ExplainFormat
465+
// Use ToLower defensively in case format wasn't normalized in some code path
466+
formatLower := strings.ToLower(strings.TrimSpace(format))
467+
if formatLower == types.ExplainFormatPlanTree {
468+
return true
469+
}
470+
}
471+
}
472+
return false
473+
}
474+
451475
// StringWithCtx implements Expression interface.
452-
func (col *Column) StringWithCtx(_ ParamValues, redact string) string {
453-
return col.string(redact)
476+
func (col *Column) StringWithCtx(ctx ParamValues, redact string) string {
477+
return col.string(redact, shouldRemoveColumnNumbers(ctx))
478+
}
479+
480+
// StringWithCtxForExplain implements Expression interface with option to remove column numbers for plan_tree format.
481+
func (col *Column) StringWithCtxForExplain(_ ParamValues, redact string, removeColumnNumbers bool) string {
482+
return col.string(redact, removeColumnNumbers)
454483
}
455484

456485
// String implements Stringer interface.
457486
func (col *Column) String() string {
458-
return col.string(errors.RedactLogDisable)
487+
return col.string(errors.RedactLogDisable, false)
459488
}
460489

461-
func (col *Column) string(redact string) string {
490+
func (col *Column) string(redact string, removeColumnNumbers bool) string {
462491
if col.IsHidden && col.VirtualExpr != nil {
463492
// A hidden column without virtual expression indicates it's a stored type.
464493
// a virtual column should be able to be stringified without context.
@@ -468,7 +497,12 @@ func (col *Column) string(redact string) string {
468497
return col.OrigName
469498
}
470499
var builder strings.Builder
471-
fmt.Fprintf(&builder, "%s%d", columnPrefix, col.UniqueID)
500+
if removeColumnNumbers {
501+
// For plan_tree format, return "Column" instead of "Column#<number>"
502+
builder.WriteString("Column")
503+
} else {
504+
fmt.Fprintf(&builder, "%s%d", columnPrefix, col.UniqueID)
505+
}
472506
return builder.String()
473507
}
474508

pkg/expression/explain.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (col *Column) ColumnExplainInfo(ctx ParamValues, normalized bool) string {
111111
if normalized {
112112
return col.ColumnExplainInfoNormalized()
113113
}
114-
return col.StringWithCtx(ctx, errors.RedactLogDisable)
114+
return col.StringWithCtxForExplain(ctx, errors.RedactLogDisable, shouldRemoveColumnNumbers(ctx))
115115
}
116116

117117
// ColumnExplainInfoNormalized returns the normalized explained info for column.
@@ -187,24 +187,37 @@ func (expr *Constant) format(dt types.Datum) string {
187187
// ExplainExpressionList generates explain information for a list of expressions.
188188
func ExplainExpressionList(ctx EvalContext, exprs []Expression, schema *Schema, redactMode string) string {
189189
builder := &strings.Builder{}
190+
// Check explain format once at the start - it doesn't change during a single explain output
191+
removeColNums := shouldRemoveColumnNumbers(ctx)
190192
for i, expr := range exprs {
191193
switch expr := expr.(type) {
192194
case *Column, *CorrelatedColumn:
193-
builder.WriteString(expr.StringWithCtx(ctx, redactMode))
194-
if expr.StringWithCtx(ctx, redactMode) != schema.Columns[i].StringWithCtx(ctx, redactMode) {
195+
// Both Column and CorrelatedColumn use the same StringWithCtxForExplain method
196+
// (CorrelatedColumn embeds Column), so they can share the same logic
197+
var col *Column
198+
switch c := expr.(type) {
199+
case *Column:
200+
col = c
201+
case *CorrelatedColumn:
202+
col = &c.Column
203+
}
204+
exprStr := col.StringWithCtxForExplain(ctx, redactMode, removeColNums)
205+
schemaColStr := schema.Columns[i].StringWithCtxForExplain(ctx, redactMode, removeColNums)
206+
builder.WriteString(exprStr)
207+
if exprStr != schemaColStr {
195208
// simple col projected again with another uniqueID without origin name.
196209
builder.WriteString("->")
197-
builder.WriteString(schema.Columns[i].StringWithCtx(ctx, redactMode))
210+
builder.WriteString(schemaColStr)
198211
}
199212
case *Constant:
200213
v := expr.StringWithCtx(ctx, errors.RedactLogDisable)
201214
redact.WriteRedact(builder, v, redactMode)
202215
builder.WriteString("->")
203-
builder.WriteString(schema.Columns[i].StringWithCtx(ctx, redactMode))
216+
builder.WriteString(schema.Columns[i].StringWithCtxForExplain(ctx, redactMode, removeColNums))
204217
default:
205218
builder.WriteString(expr.StringWithCtx(ctx, redactMode))
206219
builder.WriteString("->")
207-
builder.WriteString(schema.Columns[i].StringWithCtx(ctx, redactMode))
220+
builder.WriteString(schema.Columns[i].StringWithCtxForExplain(ctx, redactMode, removeColNums))
208221
}
209222
if i+1 < len(exprs) {
210223
builder.WriteString(", ")

pkg/expression/test/constantpropagation/constant_propagation_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ func TestConstantPropagation(t *testing.T) {
4949
col_36 binary(117) NOT NULL DEFAULT 'k#Vf)%G$9T6)'
5050
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci`)
5151
tk.MustQuery(`explain format='plan_tree' select /*+ NO_HASH_JOIN( t373b8b5b , tafab9ab4 */ tafab9ab4.col_32 as r0 , substring_index( tafab9ab4.col_36 , ',' , 2 ) as r1 , tafab9ab4.col_32 as r2 from t373b8b5b join tafab9ab4 on t373b8b5b.col_53 = tafab9ab4.col_35 where tafab9ab4.col_35 in ( 78 ,177 ) and t373b8b5b.col_53 between 0 and 1 order by r0,r1,r2`).Check(testkit.Rows(
52-
`Sort root test.tafab9ab4.col_32, Column#7`,
53-
`└─Projection root test.tafab9ab4.col_32, substring_index(test.tafab9ab4.col_36, ,, 2)->Column#7, test.tafab9ab4.col_32`,
52+
`Sort root test.tafab9ab4.col_32, Column`,
53+
`└─Projection root test.tafab9ab4.col_32, substring_index(test.tafab9ab4.col_36, ,, 2)->Column, test.tafab9ab4.col_32`,
5454
` └─HashJoin root inner join, equal:[eq(test.t373b8b5b.col_53, test.tafab9ab4.col_35)]`,
5555
` ├─TableReader(Build) root data:Selection`,
5656
` │ └─Selection cop[tikv] ge(test.t373b8b5b.col_53, 0), in(test.t373b8b5b.col_53, 78, 177), le(test.t373b8b5b.col_53, 1)`,

0 commit comments

Comments
 (0)