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

executor: prevent sending cop request for show columns #36613

Merged
merged 9 commits into from
Jul 27, 2022
19 changes: 19 additions & 0 deletions executor/infoschema_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,22 @@ SELECT
`).Check(testkit.Rows("t a b"))
}
}

// https://github.com/pingcap/tidb/issues/36426.
func TestShowColumnsWithSubQueryView(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")

tk.MustExec("CREATE TABLE added (`id` int(11), `name` text, `some_date` timestamp);")
tk.MustExec("CREATE TABLE incremental (`id` int(11), `name`text, `some_date` timestamp);")
tk.MustExec("create view temp_view as (select * from `added` where id > (select max(id) from `incremental`));")
// Show columns should not send coprocessor request to the storage.
require.NoError(t, failpoint.Enable("tikvclient/tikvStoreSendReqResult", `return("timeout")`))
tk.MustQuery("show columns from temp_view;").Check(testkit.Rows(
"id int(11) YES <nil> ",
"name text YES <nil> ",
"some_date timestamp YES <nil> "))
require.NoError(t, failpoint.Disable("tikvclient/tikvStoreSendReqResult"))
}
3 changes: 2 additions & 1 deletion executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -2062,7 +2062,8 @@ func tryFillViewColumnType(ctx context.Context, sctx sessionctx.Context, is info
// Take joining system table as an example, `fetchBuildSideRows` and `fetchProbeSideChunks` can be run concurrently.
return runWithSystemSession(ctx, sctx, func(s sessionctx.Context) error {
// Retrieve view columns info.
planBuilder, _ := plannercore.NewPlanBuilder().Init(s, is, &hint.BlockHintProcessor{})
planBuilder, _ := plannercore.NewPlanBuilder(
plannercore.PlanBuilderOptNoExecution{}).Init(s, is, &hint.BlockHintProcessor{})
if viewLogicalPlan, err := planBuilder.BuildDataSourceFromView(ctx, dbName, tbl); err == nil {
viewSchema := viewLogicalPlan.Schema()
viewOutputNames := viewLogicalPlan.OutputNames()
Expand Down
19 changes: 11 additions & 8 deletions planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -825,18 +825,20 @@ func (er *expressionRewriter) handleExistSubquery(ctx context.Context, v *ast.Ex
return v, true
}
np = er.popExistsSubPlan(np)
if len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 {

if er.b.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 {
er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not, hasRewriteHint)
if er.err != nil || !er.asScalar {
return v, true
}
er.ctxStackAppend(er.p.Schema().Columns[er.p.Schema().Len()-1], er.p.OutputNames()[er.p.Schema().Len()-1])
} else {
// We don't want nth_plan hint to affect separately executed subqueries here, so disable nth_plan temporarily.
NthPlanBackup := er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan
er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan = -1
hints := er.sctx.GetSessionVars().StmtCtx.StmtHints
NthPlanBackup := hints.ForceNthPlan
hints.ForceNthPlan = -1
physicalPlan, _, err := DoOptimize(ctx, er.sctx, er.b.optFlag, np)
er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan = NthPlanBackup
hints.ForceNthPlan = NthPlanBackup
if err != nil {
er.err = err
return v, true
Expand Down Expand Up @@ -1000,7 +1002,7 @@ func (er *expressionRewriter) handleScalarSubquery(ctx context.Context, v *ast.S
return v, true
}
np = er.b.buildMaxOneRow(np)
if len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 {
if er.b.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 {
er.p = er.b.buildApplyWithJoinType(er.p, np, LeftOuterJoin)
if np.Schema().Len() > 1 {
newCols := make([]expression.Expression, 0, np.Schema().Len())
Expand All @@ -1019,10 +1021,11 @@ func (er *expressionRewriter) handleScalarSubquery(ctx context.Context, v *ast.S
return v, true
}
// We don't want nth_plan hint to affect separately executed subqueries here, so disable nth_plan temporarily.
NthPlanBackup := er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan
er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan = -1
hints := er.sctx.GetSessionVars().StmtCtx.StmtHints
NthPlanBackup := hints.ForceNthPlan
hints.ForceNthPlan = -1
physicalPlan, _, err := DoOptimize(ctx, er.sctx, er.b.optFlag, np)
er.sctx.GetSessionVars().StmtCtx.StmtHints.ForceNthPlan = NthPlanBackup
hints.ForceNthPlan = NthPlanBackup
if err != nil {
er.err = err
return v, true
Expand Down
23 changes: 21 additions & 2 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ type PlanBuilder struct {
// hasValidSemijoinHint would tell the outer APPLY/JOIN operator that there's valid hint to be checked later
// if there's SEMI_JOIN_REWRITE hint and we find checkSemiJoinHint is true.
hasValidSemiJoinHint bool
// disableSubQueryPreprocessing indicates whether to pre-process uncorrelated sub-queries in rewriting stage.
disableSubQueryPreprocessing bool
}

type handleColHelper struct {
Expand Down Expand Up @@ -619,14 +621,31 @@ func (b *PlanBuilder) popSelectOffset() {
b.selectOffset = b.selectOffset[:len(b.selectOffset)-1]
}

// PlanBuilderOpt is used to adjust the plan builder.
type PlanBuilderOpt interface {
Apply(builder *PlanBuilder)
}

// PlanBuilderOptNoExecution means the plan builder should not run any executor during Build().
type PlanBuilderOptNoExecution struct{}

// Apply implements the interface PlanBuilderOpt.
func (p PlanBuilderOptNoExecution) Apply(builder *PlanBuilder) {
builder.disableSubQueryPreprocessing = true
}

// NewPlanBuilder creates a new PlanBuilder.
func NewPlanBuilder() *PlanBuilder {
return &PlanBuilder{
func NewPlanBuilder(opts ...PlanBuilderOpt) *PlanBuilder {
builder := &PlanBuilder{
outerCTEs: make([]*cteInfo, 0),
colMapper: make(map[*ast.ColumnNameExpr]int),
handleHelper: &handleColHelper{id2HandleMapStack: make([]map[int64][]HandleCols, 0)},
correlatedAggMapper: make(map[*ast.AggregateFuncExpr]*expression.CorrelatedColumn),
}
for _, opt := range opts {
opt.Apply(builder)
}
return builder
}

// Init initialize a PlanBuilder.
Expand Down