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

*: resolve select fields properly for coalesced columns of natural join (#25094) #30051

Merged
merged 7 commits into from
Apr 15, 2022
29 changes: 29 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9714,6 +9714,35 @@ func (s *testIntegrationSuite) TestGlobalCacheCorrectness(c *C) {
tk.MustExec("SET GLOBAL max_connections=151")
}

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) TestControlFunctionWithEnumOrSet(c *C) {
defer s.cleanEnv(c)

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 @@ -840,6 +840,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 @@ -937,16 +938,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 @@ -2545,6 +2548,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 @@ -1456,7 +1456,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 @@ -34,6 +34,8 @@ type FieldName struct {
// update stmt can write `writeable` column implicitly but cannot use non-public columns explicit.
// e.g. update t set a = 10 where b = 10; which `b` is in `writeOnly` state
NotExplicitUsable bool

Redundant bool
}

const emptyName = "EMPTY_NAME"
Expand Down