From 14066b262e80222eb558d680f29b68b357f21204 Mon Sep 17 00:00:00 2001 From: ti-srebot <66930949+ti-srebot@users.noreply.github.com> Date: Wed, 10 Aug 2022 11:32:49 +0800 Subject: [PATCH] executor: prevent sending cop request for show columns (#36613) (#36820) close pingcap/tidb#36426, ref pingcap/tidb#36496 --- executor/prepared.go | 2 +- executor/show.go | 3 +- planner/core/expression_rewriter.go | 6 +-- planner/core/indexmerge_test.go | 2 +- planner/core/logical_plan_test.go | 20 ++++---- .../core/memtable_predicate_extractor_test.go | 2 +- planner/core/optimizer.go | 2 +- planner/core/planbuilder.go | 48 ++++++++++++++----- planner/core/planbuilder_test.go | 4 +- planner/core/prepare_test.go | 2 +- planner/core/stats_test.go | 2 +- planner/optimize.go | 4 +- 12 files changed, 62 insertions(+), 35 deletions(-) diff --git a/executor/prepared.go b/executor/prepared.go index 832252a82ec93..dd623d73711f0 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -199,7 +199,7 @@ func (e *PrepareExec) Next(ctx context.Context, req *chunk.Chunk) error { var p plannercore.Plan e.ctx.GetSessionVars().PlanID = 0 e.ctx.GetSessionVars().PlanColumnID = 0 - destBuilder, _ := plannercore.NewPlanBuilder(e.ctx, e.is, &hint.BlockHintProcessor{}) + destBuilder, _ := plannercore.NewPlanBuilder().Init(e.ctx, e.is, &hint.BlockHintProcessor{}) p, err = destBuilder.Build(ctx, stmt) if err != nil { return err diff --git a/executor/show.go b/executor/show.go index 7c73eabf57f10..6d8638a717680 100644 --- a/executor/show.go +++ b/executor/show.go @@ -1693,7 +1693,8 @@ func (e *ShowExec) fetchShowBuiltins() error { func tryFillViewColumnType(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, dbName model.CIStr, tbl *model.TableInfo) error { if tbl.IsView() { // Retrieve view columns info. - planBuilder, _ := plannercore.NewPlanBuilder(sctx, is, &hint.BlockHintProcessor{}) + planBuilder, _ := plannercore.NewPlanBuilder( + plannercore.PlanBuilderOptNoExecution{}).Init(sctx, is, &hint.BlockHintProcessor{}) if viewLogicalPlan, err := planBuilder.BuildDataSourceFromView(ctx, dbName, tbl); err == nil { viewSchema := viewLogicalPlan.Schema() viewOutputNames := viewLogicalPlan.OutputNames() diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 6eaf5e21f7f8c..666484f8bef0b 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -66,7 +66,7 @@ func rewriteAstExpr(sctx sessionctx.Context, expr ast.ExprNode, schema *expressi if sctx.GetSessionVars().TxnCtx.InfoSchema != nil { is = sctx.GetSessionVars().TxnCtx.InfoSchema.(infoschema.InfoSchema) } - b, savedBlockNames := NewPlanBuilder(sctx, is, &hint.BlockHintProcessor{}) + b, savedBlockNames := NewPlanBuilder().Init(sctx, is, &hint.BlockHintProcessor{}) fakePlan := LogicalTableDual{}.Init(sctx, 0) if schema != nil { fakePlan.schema = schema @@ -780,7 +780,7 @@ 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) if er.err != nil || !er.asScalar { return v, true @@ -949,7 +949,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()) diff --git a/planner/core/indexmerge_test.go b/planner/core/indexmerge_test.go index 9fdcf2f809acb..3bba414fcdb9a 100644 --- a/planner/core/indexmerge_test.go +++ b/planner/core/indexmerge_test.go @@ -91,7 +91,7 @@ func (s *testIndexMergeSuite) TestIndexMergePathGeneration(c *C) { stmt, err := s.ParseOneStmt(tc, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) if err != nil { s.testdata.OnRecord(func() { diff --git a/planner/core/logical_plan_test.go b/planner/core/logical_plan_test.go index 03e417de66569..577376b6935ac 100644 --- a/planner/core/logical_plan_test.go +++ b/planner/core/logical_plan_test.go @@ -1163,7 +1163,7 @@ func (s *testPlanSuite) TestVisitInfo(c *C) { stmt, err := s.ParseOneStmt(tt.sql, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) builder.ctx.GetSessionVars().SetHashJoinConcurrency(1) _, err = builder.Build(context.TODO(), stmt) c.Assert(err, IsNil, comment) @@ -1243,7 +1243,7 @@ func (s *testPlanSuite) TestUnion(c *C) { stmt, err := s.ParseOneStmt(tt, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) plan, err := builder.Build(ctx, stmt) s.testData.OnRecord(func() { output[i].Err = err != nil @@ -1275,7 +1275,7 @@ func (s *testPlanSuite) TestTopNPushDown(c *C) { stmt, err := s.ParseOneStmt(tt, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) @@ -1349,7 +1349,7 @@ func (s *testPlanSuite) TestOuterJoinEliminator(c *C) { stmt, err := s.ParseOneStmt(tt, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) @@ -1385,7 +1385,7 @@ func (s *testPlanSuite) TestSelectView(c *C) { stmt, err := s.ParseOneStmt(tt.sql, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) @@ -1466,7 +1466,7 @@ func (s *testPlanSuite) optimize(ctx context.Context, sql string) (PhysicalPlan, return nil, nil, err } } - builder, _ := NewPlanBuilder(sctx, s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(sctx, s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) if err != nil { return nil, nil, err @@ -1548,7 +1548,7 @@ func (s *testPlanSuite) TestSkylinePruning(c *C) { stmt, err := s.ParseOneStmt(tt.sql, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) if err != nil { c.Assert(err.Error(), Equals, tt.result, comment) @@ -1649,7 +1649,7 @@ func (s *testPlanSuite) TestUpdateEQCond(c *C) { stmt, err := s.ParseOneStmt(tt.sql, "", "") c.Assert(err, IsNil, comment) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) @@ -1665,7 +1665,7 @@ func (s *testPlanSuite) TestConflictedJoinTypeHints(c *C) { stmt, err := s.ParseOneStmt(sql, "", "") c.Assert(err, IsNil) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) @@ -1685,7 +1685,7 @@ func (s *testPlanSuite) TestSimplyOuterJoinWithOnlyOuterExpr(c *C) { stmt, err := s.ParseOneStmt(sql, "", "") c.Assert(err, IsNil) Preprocess(s.ctx, stmt, s.is) - builder, _ := NewPlanBuilder(MockContext(), s.is, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), s.is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) p, err = logicalOptimize(ctx, builder.optFlag, p.(LogicalPlan)) diff --git a/planner/core/memtable_predicate_extractor_test.go b/planner/core/memtable_predicate_extractor_test.go index dc36934d4dc1b..3cc16efe3504d 100644 --- a/planner/core/memtable_predicate_extractor_test.go +++ b/planner/core/memtable_predicate_extractor_test.go @@ -62,7 +62,7 @@ func (s *extractorSuite) getLogicalMemTable(c *C, se session.Session, parser *pa c.Assert(err, IsNil) ctx := context.Background() - builder, _ := plannercore.NewPlanBuilder(se, s.dom.InfoSchema(), &hint.BlockHintProcessor{}) + builder, _ := plannercore.NewPlanBuilder().Init(se, s.dom.InfoSchema(), &hint.BlockHintProcessor{}) plan, err := builder.Build(ctx, stmt) c.Assert(err, IsNil) diff --git a/planner/core/optimizer.go b/planner/core/optimizer.go index 0af7828ce1bbc..26a03629feb22 100644 --- a/planner/core/optimizer.go +++ b/planner/core/optimizer.go @@ -90,7 +90,7 @@ type logicalOptRule interface { func BuildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (Plan, types.NameSlice, error) { sctx.GetSessionVars().PlanID = 0 sctx.GetSessionVars().PlanColumnID = 0 - builder, _ := NewPlanBuilder(sctx, is, &utilhint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(sctx, is, &utilhint.BlockHintProcessor{}) p, err := builder.Build(ctx, node) if err != nil { return nil, nil, err diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 4a2b5c0f546f9..f5d87b5b2ea5c 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -471,6 +471,8 @@ type PlanBuilder struct { // 1. use `inside insert`, `update`, `delete` or `select for update` statement // 2. isolation level is RC isForUpdateRead bool + // disableSubQueryPreprocessing indicates whether to pre-process uncorrelated sub-queries in rewriting stage. + disableSubQueryPreprocessing bool } type handleColHelper struct { @@ -571,24 +573,48 @@ func (b *PlanBuilder) popSelectOffset() { b.selectOffset = b.selectOffset[:len(b.selectOffset)-1] } -// NewPlanBuilder creates a new PlanBuilder. Return the original PlannerSelectBlockAsName as well, callers decide if +// 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(opts ...PlanBuilderOpt) *PlanBuilder { + builder := &PlanBuilder{ + 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. +// Return the original PlannerSelectBlockAsName as well, callers decide if // PlannerSelectBlockAsName should be restored after using this builder. -func NewPlanBuilder(sctx sessionctx.Context, is infoschema.InfoSchema, processor *hint.BlockHintProcessor) (*PlanBuilder, []ast.HintTable) { +func (b *PlanBuilder) Init(sctx sessionctx.Context, is infoschema.InfoSchema, processor *hint.BlockHintProcessor) (*PlanBuilder, []ast.HintTable) { savedBlockNames := sctx.GetSessionVars().PlannerSelectBlockAsName if processor == nil { sctx.GetSessionVars().PlannerSelectBlockAsName = nil } else { sctx.GetSessionVars().PlannerSelectBlockAsName = make([]ast.HintTable, processor.MaxSelectStmtOffset()+1) } - return &PlanBuilder{ - ctx: sctx, - is: is, - colMapper: make(map[*ast.ColumnNameExpr]int), - handleHelper: &handleColHelper{id2HandleMapStack: make([]map[int64][]HandleCols, 0)}, - hintProcessor: processor, - correlatedAggMapper: make(map[*ast.AggregateFuncExpr]*expression.CorrelatedColumn), - isForUpdateRead: sctx.GetSessionVars().IsPessimisticReadConsistency(), - }, savedBlockNames + + b.ctx = sctx + b.is = is + b.hintProcessor = processor + b.isForUpdateRead = sctx.GetSessionVars().IsPessimisticReadConsistency() + return b, savedBlockNames } // Build builds the ast node to a Plan. diff --git a/planner/core/planbuilder_test.go b/planner/core/planbuilder_test.go index f3da2e6d0dba9..0f9205be76412 100644 --- a/planner/core/planbuilder_test.go +++ b/planner/core/planbuilder_test.go @@ -114,7 +114,7 @@ func (s *testPlanBuilderSuite) TestGetPathByIndexName(c *C) { } func (s *testPlanBuilderSuite) TestRewriterPool(c *C) { - builder, _ := NewPlanBuilder(MockContext(), nil, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(MockContext(), nil, &hint.BlockHintProcessor{}) // Make sure PlanBuilder.getExpressionRewriter() provides clean rewriter from pool. // First, pick one rewriter from the pool and make it dirty. @@ -168,7 +168,7 @@ func (s *testPlanBuilderSuite) TestDisableFold(c *C) { stmt := st.(*ast.SelectStmt) expr := stmt.Fields.Fields[0].Expr - builder, _ := NewPlanBuilder(ctx, nil, &hint.BlockHintProcessor{}) + builder, _ := NewPlanBuilder().Init(ctx, nil, &hint.BlockHintProcessor{}) builder.rewriterCounter++ rewriter := builder.getExpressionRewriter(context.TODO(), nil) c.Assert(rewriter, NotNil) diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index 8de50601a17b6..49011757276f4 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -196,7 +196,7 @@ func (s *testPlanSerialSuite) TestPrepareCacheDeferredFunction(c *C) { stmt, err := s.ParseOneStmt(sql1, "", "") c.Check(err, IsNil) is := tk.Se.GetSessionVars().TxnCtx.InfoSchema.(infoschema.InfoSchema) - builder, _ := core.NewPlanBuilder(tk.Se, is, &hint.BlockHintProcessor{}) + builder, _ := core.NewPlanBuilder().Init(tk.Se, is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Check(err, IsNil) execPlan, ok := p.(*core.Execute) diff --git a/planner/core/stats_test.go b/planner/core/stats_test.go index 6b00782719bb6..811793f4c7f45 100644 --- a/planner/core/stats_test.go +++ b/planner/core/stats_test.go @@ -76,7 +76,7 @@ func (s *testStatsSuite) TestGroupNDVs(c *C) { stmt, err := s.ParseOneStmt(tt, "", "") c.Assert(err, IsNil, comment) core.Preprocess(tk.Se, stmt, is) - builder, _ := core.NewPlanBuilder(tk.Se, is, &hint.BlockHintProcessor{}) + builder, _ := core.NewPlanBuilder().Init(tk.Se, is, &hint.BlockHintProcessor{}) p, err := builder.Build(ctx, stmt) c.Assert(err, IsNil, comment) p, err = core.LogicalOptimize(ctx, builder.GetOptFlag(), p.(core.LogicalPlan)) diff --git a/planner/optimize.go b/planner/optimize.go index 06f679f71d199..e02b395f14450 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -227,7 +227,7 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in sctx.GetSessionVars().PlanColumnID = 0 hintProcessor := &hint.BlockHintProcessor{Ctx: sctx} node.Accept(hintProcessor) - builder, _ := plannercore.NewPlanBuilder(sctx, is, hintProcessor) + builder, _ := plannercore.NewPlanBuilder().Init(sctx, is, hintProcessor) // reset fields about rewrite sctx.GetSessionVars().RewritePhaseInfo.Reset() @@ -420,7 +420,7 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, execAst *ast.ExecuteStmt, is infoschema.InfoSchema) (plannercore.Plan, error) { defer trace.StartRegion(ctx, "Optimize").End() var err error - builder, _ := plannercore.NewPlanBuilder(sctx, is, nil) + builder, _ := plannercore.NewPlanBuilder().Init(sctx, is, nil) p, err := builder.Build(ctx, execAst) if err != nil { return nil, err