diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 5871dac96962f..89c2108648d3e 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -3007,7 +3007,7 @@ func (g *gbyResolver) Enter(inNode ast.Node) (ast.Node, bool) { return inNode, true case *driver.ParamMarkerExpr: g.isParam = true - if g.exprDepth == 1 { + if g.exprDepth == 1 && !n.UseAsValueInGbyByClause { _, isNull, isExpectedType := getUintFromNode(g.ctx, n) // For constant uint expression in top level, it should be treated as position expression. if !isNull && isExpectedType { @@ -3045,6 +3045,9 @@ func (g *gbyResolver) Leave(inNode ast.Node) (ast.Node, bool) { } else if ast.HasWindowFlag(ret) { err = ErrIllegalReference.GenWithStackByArgs(v.Name.OrigColName(), "reference to window function") } else { + if isParam, ok := ret.(*driver.ParamMarkerExpr); ok { + isParam.UseAsValueInGbyByClause = true + } return ret, true } } diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index ae493a7f9ab55..e81843b9d70ba 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -124,6 +124,18 @@ func TestIssue41626(t *testing.T) { tk.MustQuery(`show warnings`).Check(testkit.Rows("Warning 1105 skip plan-cache: '12' may be converted to INT")) } +func TestIssue53872(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + + tk.MustExec(`use test`) + tk.MustExec(`create table test(id int, col int)`) + tk.MustExec(`prepare stmt from "select id, ? as col1 from test where col=? group by id,col1"`) + tk.MustExec(`set @a=100, @b=100`) + tk.MustQuery(`execute stmt using @a,@b`).Check(testkit.Rows()) // no error + tk.MustQuery(`execute stmt using @a,@b`).Check(testkit.Rows()) +} + func TestIssue38269(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) diff --git a/types/parser_driver/value_expr.go b/types/parser_driver/value_expr.go index b100f1302e3a6..0fe87fce2d193 100644 --- a/types/parser_driver/value_expr.go +++ b/types/parser_driver/value_expr.go @@ -240,6 +240,14 @@ type ParamMarkerExpr struct { Offset int Order int InExecute bool + + // For "select ? as c from t group by c", the optimizer replaces the `c` in the by-clause to `group by ?`, + // but this conversion conflicts with the original semantic. The original `group by c` means grouping by the column `c`, + // while the converted `group by ?` means grouping by the `?-th` column in the select-list, for example, `group by 3` means + // grouping the result by the 3rd column. + // Use this flag to let the optimizer know whether `group by ?` is converted from this case and if it is, use this + // marker as normal value instead of column index in the by-clause. + UseAsValueInGbyByClause bool } // Restore implements Node interface.