Skip to content

Commit 2ed3ee0

Browse files
authored
fix group_concat with order by subquery clauses (#3041)
1 parent caed79c commit 2ed3ee0

File tree

4 files changed

+83
-22
lines changed

4 files changed

+83
-22
lines changed

enginetest/queries/script_queries.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,12 +2775,10 @@ CREATE TABLE tab3 (
27752775
},
27762776
Assertions: []ScriptTestAssertion{
27772777
{
2778-
Skip: true,
27792778
Query: "SELECT category, group_concat(name ORDER BY (SELECT COUNT(*) FROM test_data t2 WHERE t2.category = test_data.category AND t2.age < test_data.age)) FROM test_data GROUP BY category ORDER BY category",
27802779
Expected: []sql.Row{{"A", "Charlie,Alice,Frank"}, {"B", "Bob,Eve"}, {"C", "Diana"}},
27812780
},
27822781
{
2783-
Skip: true,
27842782
Query: "SELECT group_concat(name ORDER BY (SELECT AVG(age) FROM test_data t2 WHERE t2.category = test_data.category), id) FROM test_data;",
27852783
Expected: []sql.Row{{"Alice,Charlie,Frank,Diana,Bob,Eve"}},
27862784
},
@@ -2804,22 +2802,18 @@ CREATE TABLE tab3 (
28042802
},
28052803
Assertions: []ScriptTestAssertion{
28062804
{
2807-
Skip: true,
28082805
Query: "SELECT category_id, GROUP_CONCAT(name ORDER BY (SELECT rating FROM suppliers WHERE suppliers.id = products.supplier_id) DESC, id ASC) FROM products GROUP BY category_id ORDER BY category_id",
28092806
Expected: []sql.Row{{1, "Laptop,Keyboard,Mouse,Monitor"}, {2, "Chair,Desk"}},
28102807
},
28112808
{
2812-
Skip: true,
28132809
Query: "SELECT GROUP_CONCAT(name ORDER BY (SELECT COUNT(*) FROM products p2 WHERE p2.price < products.price), id) FROM products",
28142810
Expected: []sql.Row{{"Mouse,Keyboard,Chair,Monitor,Desk,Laptop"}},
28152811
},
28162812
{
2817-
Skip: true,
28182813
Query: "SELECT category_id, GROUP_CONCAT(DISTINCT supplier_id ORDER BY (SELECT rating FROM suppliers WHERE suppliers.id = products.supplier_id)) FROM products GROUP BY category_id",
28192814
Expected: []sql.Row{{1, "2,1"}, {2, "3"}},
28202815
},
28212816
{
2822-
Skip: true,
28232817
Query: "SELECT GROUP_CONCAT(name ORDER BY (SELECT priority FROM categories WHERE categories.id = products.category_id), price) FROM products",
28242818
Expected: []sql.Row{{"Mouse,Keyboard,Monitor,Laptop,Chair,Desk"}},
28252819
},
@@ -2861,21 +2855,31 @@ CREATE TABLE tab3 (
28612855
Assertions: []ScriptTestAssertion{
28622856
{
28632857
// Test with subquery returning NULL values
2864-
Skip: true,
2865-
Query: "SELECT category, GROUP_CONCAT(name ORDER BY (SELECT CASE WHEN complex_test.value > 80 THEN NULL ELSE complex_test.value END), name) FROM complex_test GROUP BY category ORDER BY category",
2866-
Expected: []sql.Row{{"X", "Alpha,Gamma"}, {"Y", "Epsilon,Beta"}, {"Z", "Delta"}},
2858+
Query: "SELECT category, GROUP_CONCAT(name ORDER BY (SELECT CASE WHEN complex_test.value > 80 THEN NULL ELSE complex_test.value END), name) FROM complex_test GROUP BY category ORDER BY category",
2859+
Expected: []sql.Row{
2860+
{"X", "Alpha,Gamma"},
2861+
{"Y", "Epsilon,Beta"},
2862+
{"Z", "Delta"},
2863+
},
28672864
},
28682865
{
28692866
// Test with correlated subquery using multiple tables
2870-
Skip: true,
28712867
Query: "SELECT GROUP_CONCAT(name ORDER BY (SELECT COUNT(*) FROM complex_test c2 WHERE c2.category = complex_test.category AND c2.value > complex_test.value), name) FROM complex_test",
28722868
Expected: []sql.Row{{"Alpha,Delta,Epsilon,Beta,Gamma"}},
28732869
},
2870+
{
2871+
// Test with subquery using multiple columns errors
2872+
Query: "SELECT category, GROUP_CONCAT(name ORDER BY (SELECT AVG(value), name FROM complex_test c2 WHERE c2.id <= complex_test.id HAVING AVG(value) > 50) DESC) FROM complex_test GROUP BY category ORDER BY category",
2873+
ExpectedErr: sql.ErrInvalidOperandColumns,
2874+
},
28742875
{
28752876
// Test with subquery using aggregate functions with HAVING
2876-
Skip: true,
2877-
Query: "SELECT category, GROUP_CONCAT(name ORDER BY (SELECT AVG(value), name FROM complex_test c2 WHERE c2.id <= complex_test.id HAVING AVG(value) > 50) DESC) FROM complex_test GROUP BY category ORDER BY category",
2878-
Expected: []sql.Row{{"X", "Alpha,Gamma"}, {"Y", "Beta,Epsilon"}, {"Z", "Delta"}},
2877+
Query: "SELECT category, GROUP_CONCAT(name ORDER BY (SELECT AVG(value) FROM complex_test c2 WHERE c2.id <= complex_test.id HAVING AVG(value) > 50) DESC) FROM complex_test GROUP BY category ORDER BY category",
2878+
Expected: []sql.Row{
2879+
{"X", "Alpha,Gamma"},
2880+
{"Y", "Beta,Epsilon"},
2881+
{"Z", "Delta"},
2882+
},
28792883
},
28802884
{
28812885
// Test with DISTINCT and complex subquery
@@ -2884,9 +2888,8 @@ CREATE TABLE tab3 (
28842888
},
28852889
{
28862890
// Test with nested subqueries
2887-
Skip: true,
2888-
Query: "SELECT GROUP_CONCAT(name ORDER BY (SELECT COUNT(*) FROM complex_test c2 WHERE c2.value > (SELECT MIN(value) FROM complex_test c3 WHERE c3.category = complex_test.category))) FROM complex_test",
2889-
Expected: []sql.Row{{"Gamma,Alpha,Epsilon,Beta,Delta"}},
2891+
Query: "SELECT GROUP_CONCAT(name ORDER BY (SELECT SUM(value) FROM complex_test c2 WHERE c2.value != (SELECT MIN(value) FROM complex_test c3 where c3.id = complex_test.id))) FROM complex_test;",
2892+
Expected: []sql.Row{{"Alpha,Epsilon,Gamma,Beta,Delta"}},
28902893
},
28912894
},
28922895
},
@@ -2905,13 +2908,11 @@ CREATE TABLE tab3 (
29052908
},
29062909
{
29072910
// Test with subquery using LIMIT
2908-
Skip: true,
29092911
Query: "SELECT GROUP_CONCAT(data ORDER BY (SELECT weight FROM perf_test p2 WHERE p2.id = perf_test.id LIMIT 1)) FROM perf_test",
29102912
Expected: []sql.Row{{"C,A,E,B,D"}},
29112913
},
29122914
{
29132915
// Test with very small decimal differences in ORDER BY subquery
2914-
Skip: true,
29152916
Query: "SELECT GROUP_CONCAT(data ORDER BY (SELECT weight + 0.001 * perf_test.id FROM perf_test p2 WHERE p2.id = perf_test.id)) FROM perf_test",
29162917
Expected: []sql.Row{{"C,A,E,B,D"}},
29172918
},

sql/aggregates.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ type WindowFrame interface {
115115
StartNFollowing() Expression
116116
// EndNPreceding returns whether a frame end preceding Expression or nil
117117
EndNPreceding() Expression
118-
// EndNPreceding returns whether a frame end following Expression or nil
118+
// EndNFollowing returns whether a frame end following Expression or nil
119119
EndNFollowing() Expression
120120
}
121121

@@ -135,3 +135,9 @@ type AggregationBuffer interface {
135135
type WindowAggregation interface {
136136
WindowAdaptableExpression
137137
}
138+
139+
// OrderedAggregation are aggregate functions that modify the current working row with additional result columns.
140+
type OrderedAggregation interface {
141+
// OutputExpressions gets a list of return expressions.
142+
OutputExpressions() []Expression
143+
}

sql/analyzer/fix_exec_indexes.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,9 +578,23 @@ func (s *idxScope) visitSelf(n sql.Node) error {
578578
}
579579
if ne, ok := n.(sql.Expressioner); ok {
580580
scope := append(s.parentScopes, s.childScopes...)
581+
// default nodes can't see lateral join nodes, unless we're in lateral
582+
// join and lateral scopes are promoted to parent status
581583
for _, e := range ne.Expressions() {
582-
// default nodes can't see lateral join nodes, unless we're in lateral
583-
// join and lateral scopes are promoted to parent status
584+
// OrderedAggregations are special as they append results to the outer scope row
585+
// We need to account for this extra column in the rows when assigning indexes
586+
// Example: gms/expression/function/aggregation/group_concat.go:groupConcatBuffer.Update()
587+
if ordAgg, isOrdAgg := e.(sql.OrderedAggregation); isOrdAgg {
588+
selExprs := ordAgg.OutputExpressions()
589+
selScope := &idxScope{}
590+
for _, expr := range selExprs {
591+
selScope.columns = append(selScope.columns, expr.String())
592+
if gf, isGf := expr.(*expression.GetField); isGf {
593+
selScope.ids = append(selScope.ids, gf.Id())
594+
}
595+
}
596+
scope = append(scope, selScope)
597+
}
584598
s.expressions = append(s.expressions, fixExprToScope(e, scope...))
585599
}
586600
}

sql/expression/function/aggregation/group_concat.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type GroupConcat struct {
4040
var _ sql.FunctionExpression = &GroupConcat{}
4141
var _ sql.Aggregation = &GroupConcat{}
4242
var _ sql.WindowAdaptableExpression = (*GroupConcat)(nil)
43+
var _ sql.OrderedAggregation = (*GroupConcat)(nil)
4344

4445
func NewEmptyGroupConcat() sql.Expression {
4546
return &GroupConcat{}
@@ -153,6 +154,40 @@ func (g *GroupConcat) String() string {
153154
return sb.String()
154155
}
155156

157+
func (g *GroupConcat) DebugString() string {
158+
sb := strings.Builder{}
159+
sb.WriteString("group_concat(")
160+
if g.distinct != "" {
161+
sb.WriteString(fmt.Sprintf("distinct %s", g.distinct))
162+
}
163+
164+
if g.selectExprs != nil {
165+
var exprs = make([]string, len(g.selectExprs))
166+
for i, expr := range g.selectExprs {
167+
exprs[i] = sql.DebugString(expr)
168+
}
169+
170+
sb.WriteString(strings.Join(exprs, ", "))
171+
}
172+
173+
if len(g.sf) > 0 {
174+
sb.WriteString(" order by ")
175+
for i, ob := range g.sf {
176+
if i > 0 {
177+
sb.WriteString(", ")
178+
}
179+
sb.WriteString(sql.DebugString(ob))
180+
}
181+
}
182+
183+
sb.WriteString(" separator ")
184+
sb.WriteString(fmt.Sprintf("'%s'", g.separator))
185+
186+
sb.WriteString(")")
187+
188+
return sb.String()
189+
}
190+
156191
// Type implements the Expression interface.
157192
// cc: https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat for explanations
158193
// on return type.
@@ -195,6 +230,11 @@ func (g *GroupConcat) WithChildren(children ...sql.Expression) (sql.Expression,
195230
return NewGroupConcat(g.distinct, g.sf.FromExpressions(orderByExpr...), g.separator, children[sortFieldMarker:], g.maxLen), nil
196231
}
197232

233+
// OutputExpressions implements the OrderedAggregation interface.
234+
func (g *GroupConcat) OutputExpressions() []sql.Expression {
235+
return g.selectExprs
236+
}
237+
198238
type groupConcatBuffer struct {
199239
gc *GroupConcat
200240
rows []sql.Row
@@ -257,7 +297,7 @@ func (g *groupConcatBuffer) Update(ctx *sql.Context, originalRow sql.Row) error
257297

258298
// Append the current value to the end of the row. We want to preserve the row's original structure for
259299
// for sort ordering in the final step.
260-
g.rows = append(g.rows, append(originalRow, nil, vs))
300+
g.rows = append(g.rows, append(originalRow, vs))
261301

262302
return nil
263303
}

0 commit comments

Comments
 (0)