From c69a019407c7a3229592b7c20e893f31e989b18b Mon Sep 17 00:00:00 2001 From: Yiding Cui Date: Mon, 7 Aug 2023 17:46:39 +0800 Subject: [PATCH] planner: refactor Join and Limit's ResolveIndices (#45831) close pingcap/tidb#45758, close pingcap/tidb#45805 --- planner/core/issuetest/planner_issue_test.go | 10 +++ planner/core/resolve_indices.go | 92 +++++++++++++++----- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/planner/core/issuetest/planner_issue_test.go b/planner/core/issuetest/planner_issue_test.go index a342c3452634d..4978a0a580049 100644 --- a/planner/core/issuetest/planner_issue_test.go +++ b/planner/core/issuetest/planner_issue_test.go @@ -45,3 +45,13 @@ func TestIssue42732(t *testing.T) { tk.MustExec("INSERT INTO t2 VALUES (1, 1)") tk.MustQuery("SELECT one.a, one.b as b2 FROM t1 one ORDER BY (SELECT two.b FROM t2 two WHERE two.a = one.b)").Check(testkit.Rows("1 1")) } + +func TestIssue45758(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("CREATE TABLE tb1 (cid INT, code INT, class VARCHAR(10))") + tk.MustExec("CREATE TABLE tb2 (cid INT, code INT, class VARCHAR(10))") + // result ok + tk.MustExec("UPDATE tb1, (SELECT code AS cid, code, MAX(class) AS class FROM tb2 GROUP BY code) tb3 SET tb1.cid = tb3.cid, tb1.code = tb3.code, tb1.class = tb3.class") +} diff --git a/planner/core/resolve_indices.go b/planner/core/resolve_indices.go index 3d6efcf4d40d1..a9e1613faf6f0 100644 --- a/planner/core/resolve_indices.go +++ b/planner/core/resolve_indices.go @@ -140,12 +140,25 @@ func (p *PhysicalHashJoin) ResolveIndicesItself() (err error) { shallowColSlice := make([]*expression.Column, p.schema.Len()) copy(shallowColSlice, p.schema.Columns) p.schema = expression.NewSchema(shallowColSlice...) - for i := 0; i < colsNeedResolving; i++ { - newCol, err := p.schema.Columns[i].ResolveIndices(mergedSchema) - if err != nil { - return err + foundCnt := 0 + // The two column sets are all ordered. And the colsNeedResolving is the subset of the mergedSchema. + // So we can just move forward j if there's no matching is found. + // We don't use the normal ResolvIndices here since there might be duplicate columns in the schema. + // e.g. The schema of child_0 is [col0, col0, col1] + // ResolveIndices will only resolve all col0 reference of the current plan to the first col0. + for i, j := 0, 0; i < colsNeedResolving && j < len(mergedSchema.Columns); { + if !p.schema.Columns[i].Equal(nil, mergedSchema.Columns[j]) { + j++ + continue } - p.schema.Columns[i] = newCol.(*expression.Column) + p.schema.Columns[i] = p.schema.Columns[i].Clone().(*expression.Column) + p.schema.Columns[i].Index = j + i++ + j++ + foundCnt++ + } + if foundCnt < colsNeedResolving { + return errors.Errorf("Some columns of %v cannot find the reference from its child(ren)", p.ExplainID().String()) } return @@ -213,12 +226,25 @@ func (p *PhysicalMergeJoin) ResolveIndices() (err error) { shallowColSlice := make([]*expression.Column, p.schema.Len()) copy(shallowColSlice, p.schema.Columns) p.schema = expression.NewSchema(shallowColSlice...) - for i := 0; i < colsNeedResolving; i++ { - newCol, err := p.schema.Columns[i].ResolveIndices(mergedSchema) - if err != nil { - return err + foundCnt := 0 + // The two column sets are all ordered. And the colsNeedResolving is the subset of the mergedSchema. + // So we can just move forward j if there's no matching is found. + // We don't use the normal ResolvIndices here since there might be duplicate columns in the schema. + // e.g. The schema of child_0 is [col0, col0, col1] + // ResolveIndices will only resolve all col0 reference of the current plan to the first col0. + for i, j := 0, 0; i < colsNeedResolving && j < len(mergedSchema.Columns); { + if !p.schema.Columns[i].Equal(nil, mergedSchema.Columns[j]) { + j++ + continue } - p.schema.Columns[i] = newCol.(*expression.Column) + p.schema.Columns[i] = p.schema.Columns[i].Clone().(*expression.Column) + p.schema.Columns[i].Index = j + i++ + j++ + foundCnt++ + } + if foundCnt < colsNeedResolving { + return errors.Errorf("Some columns of %v cannot find the reference from its child(ren)", p.ExplainID().String()) } return } @@ -296,12 +322,25 @@ func (p *PhysicalIndexJoin) ResolveIndices() (err error) { shallowColSlice := make([]*expression.Column, p.schema.Len()) copy(shallowColSlice, p.schema.Columns) p.schema = expression.NewSchema(shallowColSlice...) - for i := 0; i < colsNeedResolving; i++ { - newCol, err := p.schema.Columns[i].ResolveIndices(mergedSchema) - if err != nil { - return err + foundCnt := 0 + // The two column sets are all ordered. And the colsNeedResolving is the subset of the mergedSchema. + // So we can just move forward j if there's no matching is found. + // We don't use the normal ResolvIndices here since there might be duplicate columns in the schema. + // e.g. The schema of child_0 is [col0, col0, col1] + // ResolveIndices will only resolve all col0 reference of the current plan to the first col0. + for i, j := 0, 0; i < colsNeedResolving && j < len(mergedSchema.Columns); { + if !p.schema.Columns[i].Equal(nil, mergedSchema.Columns[j]) { + j++ + continue } - p.schema.Columns[i] = newCol.(*expression.Column) + p.schema.Columns[i] = p.schema.Columns[i].Clone().(*expression.Column) + p.schema.Columns[i].Index = j + i++ + j++ + foundCnt++ + } + if foundCnt < colsNeedResolving { + return errors.Errorf("Some columns of %v cannot find the reference from its child(ren)", p.ExplainID().String()) } return @@ -631,12 +670,25 @@ func (p *PhysicalLimit) ResolveIndices() (err error) { shallowColSlice := make([]*expression.Column, p.schema.Len()) copy(shallowColSlice, p.schema.Columns) p.schema = expression.NewSchema(shallowColSlice...) - for i, col := range p.schema.Columns { - newCol, err := col.ResolveIndices(p.children[0].Schema()) - if err != nil { - return err + foundCnt := 0 + // The two column sets are all ordered. And the colsNeedResolving is the subset of the mergedSchema. + // So we can just move forward j if there's no matching is found. + // We don't use the normal ResolvIndices here since there might be duplicate columns in the schema. + // e.g. The schema of child_0 is [col0, col0, col1] + // ResolveIndices will only resolve all col0 reference of the current plan to the first col0. + for i, j := 0, 0; i < p.schema.Len() && j < p.children[0].Schema().Len(); { + if !p.schema.Columns[i].Equal(nil, p.children[0].Schema().Columns[j]) { + j++ + continue } - p.schema.Columns[i] = newCol.(*expression.Column) + p.schema.Columns[i] = p.schema.Columns[i].Clone().(*expression.Column) + p.schema.Columns[i].Index = j + i++ + j++ + foundCnt++ + } + if foundCnt < p.schema.Len() { + return errors.Errorf("Some columns of %v cannot find the reference from its child(ren)", p.ExplainID().String()) } return }