Skip to content

Commit

Permalink
*: resolve select fields properly for coalesced columns of natural jo…
Browse files Browse the repository at this point in the history
…in (#25094) (#30049)

close #25041
  • Loading branch information
ti-srebot authored Dec 20, 2021
1 parent c352e53 commit 3bd6e48
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 5 deletions.
29 changes: 29 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9197,6 +9197,35 @@ func (s *testIntegrationSuite) TestIssue23889(c *C) {
testkit.Rows("<nil>", "0"))
}

func (s *testIntegrationSuite) TestRedundantColumnResolve(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int not null)")
tk.MustExec("create table t2(a int not null)")
tk.MustExec("insert into t1 values(1)")
tk.MustExec("insert into t2 values(1)")
tk.MustQuery("select a, count(*) from t1 join t2 using (a) group by a").Check(testkit.Rows("1 1"))
tk.MustQuery("select a, count(*) from t1 natural join t2 group by a").Check(testkit.Rows("1 1"))
err := tk.ExecToErr("select a, count(*) from t1 join t2 on t1.a=t2.a group by a")
c.Assert(err.Error(), Equals, "[planner:1052]Column 'a' in field list is ambiguous")
tk.MustQuery("select t1.a, t2.a from t1 join t2 using (a) group by t1.a").Check(testkit.Rows("1 1"))
err = tk.ExecToErr("select t1.a, t2.a from t1 join t2 using(a) group by a")
c.Assert(err.Error(), Equals, "[planner:1052]Column 'a' in group statement is ambiguous")
tk.MustQuery("select t2.a from t1 join t2 using (a) group by t1.a").Check(testkit.Rows("1"))
tk.MustQuery("select t1.a from t1 join t2 using (a) group by t1.a").Check(testkit.Rows("1"))
tk.MustQuery("select t2.a from t1 join t2 using (a) group by t2.a").Check(testkit.Rows("1"))
// The test below cannot pass now since we do not infer functional dependencies from filters as MySQL, hence would fail in only_full_group_by check.
// tk.MustQuery("select t1.a from t1 join t2 using (a) group by t2.a").Check(testkit.Rows("1"))
tk.MustQuery("select count(*) from t1 join t2 using (a) group by t2.a").Check(testkit.Rows("1"))
tk.MustQuery("select t2.a from t1 join t2 using (a) group by a").Check(testkit.Rows("1"))
tk.MustQuery("select t1.a from t1 join t2 using (a) group by a").Check(testkit.Rows("1"))
tk.MustQuery("select * from t1 join t2 using(a)").Check(testkit.Rows("1"))
tk.MustQuery("select t1.a, t2.a from t1 join t2 using(a)").Check(testkit.Rows("1 1"))
tk.MustQuery("select * from t1 natural join t2").Check(testkit.Rows("1"))
tk.MustQuery("select t1.a, t2.a from t1 natural join t2").Check(testkit.Rows("1 1"))
}

func (s *testIntegrationSuite) TestFloat64Inf(c *C) {
defer s.cleanEnv(c)
tk := testkit.NewTestKit(c, s.store)
Expand Down
6 changes: 6 additions & 0 deletions expression/simple_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ func FindFieldName(names types.NameSlice, astCol *ast.ColumnName) (int, error) {
if idx == -1 {
idx = i
} else {
if names[idx].Redundant || name.Redundant {
if !name.Redundant {
idx = i
}
continue
}
return -1, errNonUniq.GenWithStackByArgs(astCol.String(), "field list")
}
}
Expand Down
12 changes: 8 additions & 4 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ func (b *PlanBuilder) coalesceCommonColumns(p *LogicalJoin, leftPlan, rightPlan
lColumns, rColumns := lsc.Columns, rsc.Columns
lNames, rNames := leftPlan.OutputNames().Shallow(), rightPlan.OutputNames().Shallow()
if joinTp == ast.RightJoin {
leftPlan, rightPlan = rightPlan, leftPlan
lNames, rNames = rNames, lNames
lColumns, rColumns = rsc.Columns, lsc.Columns
}
Expand Down Expand Up @@ -918,16 +919,18 @@ func (b *PlanBuilder) coalesceCommonColumns(p *LogicalJoin, leftPlan, rightPlan

p.SetSchema(expression.NewSchema(schemaCols...))
p.names = names
if joinTp == ast.RightJoin {
leftPlan, rightPlan = rightPlan, leftPlan
}
// We record the full `rightPlan.Schema` as `redundantSchema` in order to
// record the redundant column in `rightPlan` and the output columns order
// of the `rightPlan`.
// For SQL like `select t1.*, t2.* from t1 left join t2 using(a)`, we can
// retrieve the column order of `t2.*` from the `redundantSchema`.
p.redundantSchema = expression.MergeSchema(p.redundantSchema, expression.NewSchema(rightPlan.Schema().Clone().Columns...))
p.redundantNames = append(p.redundantNames.Shallow(), rightPlan.OutputNames().Shallow()...)
p.redundantNames = p.redundantNames.Shallow()
for _, name := range rightPlan.OutputNames() {
cpyName := *name
cpyName.Redundant = true
p.redundantNames = append(p.redundantNames, &cpyName)
}
if joinTp == ast.RightJoin || joinTp == ast.LeftJoin {
resetNotNullFlag(p.redundantSchema, 0, p.redundantSchema.Len())
}
Expand Down Expand Up @@ -2491,6 +2494,7 @@ func (g *gbyResolver) Leave(inNode ast.Node) (ast.Node, bool) {
var index int
index, g.err = resolveFromSelectFields(v, g.fields, false)
if g.err != nil {
g.err = ErrAmbiguous.GenWithStackByArgs(v.Name.Name.L, clauseMsg[groupByClause])
return inNode, false
}
if idx >= 0 {
Expand Down
2 changes: 1 addition & 1 deletion planner/core/logical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@ func (s *testPlanSuite) TestNameResolver(c *C) {
{"select * from t", ""},
{"select t.* from t", ""},
{"select t2.* from t", "[planner:1051]Unknown table 't2'"},
{"select b as a, c as a from t group by a", "[planner:1052]Column 'c' in field list is ambiguous"},
{"select b as a, c as a from t group by a", "[planner:1052]Column 'a' in group statement is ambiguous"},
{"select 1 as a, b as a, c as a from t group by a", ""},
{"select a, b as a from t group by a+1", ""},
{"select c, a as c from t order by c+1", ""},
Expand Down
2 changes: 2 additions & 0 deletions types/field_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type FieldName struct {
ColName model.CIStr

Hidden bool

Redundant bool
}

const emptyName = "EMPTY_NAME"
Expand Down

0 comments on commit 3bd6e48

Please sign in to comment.