From 995b363973cd7e3a612794bcb91d8840057d9746 Mon Sep 17 00:00:00 2001 From: pingcap-github-bot Date: Tue, 23 Jul 2019 17:05:41 +0800 Subject: [PATCH] planner: fix bugs related to TIDB_INLJ hint (#11253) (#11361) --- planner/core/exhaust_physical_plans.go | 10 ++++-- planner/core/logical_plan_builder.go | 9 +++++ planner/core/physical_plan_test.go | 49 ++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/planner/core/exhaust_physical_plans.go b/planner/core/exhaust_physical_plans.go index 53e255fa5f75a..5447b8b15a02c 100644 --- a/planner/core/exhaust_physical_plans.go +++ b/planner/core/exhaust_physical_plans.go @@ -696,15 +696,19 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ } if leftJoins != nil && lhsCardinality < rhsCardinality { - return leftJoins, hasIndexJoinHint + return leftJoins, leftOuter } if rightJoins != nil && rhsCardinality < lhsCardinality { - return rightJoins, hasIndexJoinHint + return rightJoins, rightOuter } + canForceLeft := leftJoins != nil && leftOuter + canForceRight := rightJoins != nil && rightOuter + forced = canForceLeft || canForceRight + joins := append(leftJoins, rightJoins...) - return joins, hasIndexJoinHint && len(joins) != 0 + return joins, forced } return nil, false diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index aa95086bbbb24..b37e3ce58eaa0 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -281,8 +281,17 @@ func (p *LogicalJoin) extractOnCondition(conditions []expression.Expression, der return } +// extractTableAlias returns table alias of the LogicalPlan's columns. +// It will return nil when there are multiple table alias, because the alias is only used to check if +// the logicalPlan match some optimizer hints, and hints are not expected to take effect in this case. func extractTableAlias(p LogicalPlan) *model.CIStr { if p.Schema().Len() > 0 && p.Schema().Columns[0].TblName.L != "" { + tblName := p.Schema().Columns[0].TblName.L + for _, column := range p.Schema().Columns { + if column.TblName.L != tblName { + return nil + } + } return &(p.Schema().Columns[0].TblName) } return nil diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go index 3d1bce80e281d..3e69977e21754 100644 --- a/planner/core/physical_plan_test.go +++ b/planner/core/physical_plan_test.go @@ -1393,3 +1393,52 @@ func (s *testPlanSuite) TestUnmatchedTableInHint(c *C) { } } } + +func (s *testPlanSuite) TestIndexJoinHint(c *C) { + defer testleak.AfterTest(c)() + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + defer func() { + dom.Close() + store.Close() + }() + se, err := session.CreateSession4Test(store) + c.Assert(err, IsNil) + _, err = se.Execute(context.Background(), "use test") + c.Assert(err, IsNil) + + tests := []struct { + sql string + best string + warning string + }{ + { + sql: "select /*+ TIDB_INLJ(t1) */ t1.a, t2.a, t3.a from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a;", + best: "MergeInnerJoin{IndexJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t2.a,test.t1.a)->TableReader(Table(t))}(test.t2.a,test.t3.a)", + warning: "", + }, + { + sql: "select /*+ TIDB_INLJ(t1) */ t1.b, t2.a from t t1, t t2 where t1.b = t2.a;", + best: "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t1.b,test.t2.a)", + warning: "[planner:1815]Optimizer Hint /*+ TIDB_INLJ(t1) */ is inapplicable", + }, + } + for i, test := range tests { + comment := Commentf("case:%v sql:%s", i, test) + stmt, err := s.ParseOneStmt(test.sql, "", "") + c.Assert(err, IsNil, comment) + + p, err := core.Optimize(se, stmt, s.is) + c.Assert(err, IsNil) + c.Assert(core.ToString(p), Equals, test.best) + + warnings := se.GetSessionVars().StmtCtx.GetWarnings() + if test.warning == "" { + c.Assert(len(warnings), Equals, 0) + } else { + c.Assert(len(warnings), Equals, 1) + c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning) + c.Assert(warnings[0].Err.Error(), Equals, test.warning) + } + } +}