From 9dd20ef7f4c9cee32304b7bd62cca14c5674b0cd Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Mon, 20 Apr 2020 11:49:14 +0800 Subject: [PATCH] parser: add order by clause in group_concat (#813) --- ast/functions.go | 15 +++++++++++++++ ast/functions_test.go | 4 ++++ parser.go | 6 +++++- parser.y | 6 +++++- parser_test.go | 2 +- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ast/functions.go b/ast/functions.go index 2beb24053..ac612f056 100755 --- a/ast/functions.go +++ b/ast/functions.go @@ -700,6 +700,8 @@ type AggregateFuncExpr struct { // For example, column c1 values are "1", "2", "2", "sum(c1)" is "5", // but "sum(distinct c1)" is "3". Distinct bool + // Order is only used in GROUP_CONCAT + Order *OrderByClause } // Restore implements Node interface. @@ -719,6 +721,12 @@ func (n *AggregateFuncExpr) Restore(ctx *format.RestoreCtx) error { return errors.Annotatef(err, "An error occurred while restore AggregateFuncExpr.Args[%d]", i) } } + if n.Order != nil { + ctx.WritePlain(" ") + if err := n.Order.Restore(ctx); err != nil { + return errors.Annotate(err, "An error occur while restore AggregateFuncExpr.Args Order") + } + } ctx.WriteKeyWord(" SEPARATOR ") if err := n.Args[len(n.Args)-1].Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore AggregateFuncExpr.Args SEPARATOR") @@ -756,6 +764,13 @@ func (n *AggregateFuncExpr) Accept(v Visitor) (Node, bool) { } n.Args[i] = node.(ExprNode) } + if n.Order != nil { + node, ok := n.Order.Accept(v) + if !ok { + return n, false + } + n.Order = node.(*OrderByClause) + } return v.Leave(n) } diff --git a/ast/functions_test.go b/ast/functions_test.go index edcc18461..b0f91a0c3 100644 --- a/ast/functions_test.go +++ b/ast/functions_test.go @@ -140,6 +140,10 @@ func (ts *testFunctionsSuite) TestAggregateFuncExprRestore(c *C) { {"VAR_SAMP(test_score)", "VAR_SAMP(`test_score`)"}, {"VARIANCE(test_score)", "VAR_POP(`test_score`)"}, {"JSON_OBJECTAGG(test_score, results)", "JSON_OBJECTAGG(`test_score`, `results`)"}, + {"GROUP_CONCAT(a)", "GROUP_CONCAT(`a` SEPARATOR ',')"}, + {"GROUP_CONCAT(a separator '--')", "GROUP_CONCAT(`a` SEPARATOR '--')"}, + {"GROUP_CONCAT(a order by b desc, c)", "GROUP_CONCAT(`a` ORDER BY `b` DESC,`c` SEPARATOR ',')"}, + {"GROUP_CONCAT(a order by b desc, c separator '--')", "GROUP_CONCAT(`a` ORDER BY `b` DESC,`c` SEPARATOR '--')"}, } extractNodeFunc := func(node Node) Node { return node.(*SelectStmt).Fields.Fields[0].Expr diff --git a/parser.go b/parser.go index af39d4a4f..5a9d347df 100644 --- a/parser.go +++ b/parser.go @@ -13600,7 +13600,11 @@ yynewstate: if yyS[yypt-0].item != nil { parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-7].ident, Args: args, Distinct: yyS[yypt-5].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} } else { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-7].ident, Args: args, Distinct: yyS[yypt-5].item.(bool)} + agg := &ast.AggregateFuncExpr{F: yyS[yypt-7].ident, Args: args, Distinct: yyS[yypt-5].item.(bool)} + if yyS[yypt-3].item != nil { + agg.Order = yyS[yypt-3].item.(*ast.OrderByClause) + } + parser.yyVAL.expr = agg } } case 1154: diff --git a/parser.y b/parser.y index 1ad00c603..49d0aab45 100644 --- a/parser.y +++ b/parser.y @@ -6320,7 +6320,11 @@ SumExpr: if $8 != nil { $$ = &ast.WindowFuncExpr{F: $1, Args: args, Distinct: $3.(bool), Spec: *($8.(*ast.WindowSpec))} } else { - $$ = &ast.AggregateFuncExpr{F: $1, Args: args, Distinct: $3.(bool)} + agg := &ast.AggregateFuncExpr{F: $1, Args: args, Distinct: $3.(bool)} + if $5 != nil { + agg.Order = $5.(*ast.OrderByClause) + } + $$ = agg } } | builtinMax '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause diff --git a/parser_test.go b/parser_test.go index 5a52be88f..97a1848a8 100644 --- a/parser_test.go +++ b/parser_test.go @@ -1802,7 +1802,7 @@ func (s *testParserSuite) TestBuiltin(c *C) { {`select group_concat(c2,c1 SEPARATOR ';') from t group by c1;`, true, "SELECT GROUP_CONCAT(`c2`, `c1` SEPARATOR ';') FROM `t` GROUP BY `c1`"}, {`select group_concat(distinct c2,c1) from t group by c1;`, true, "SELECT GROUP_CONCAT(DISTINCT `c2`, `c1` SEPARATOR ',') FROM `t` GROUP BY `c1`"}, {`select group_concat(distinctrow c2,c1) from t group by c1;`, true, "SELECT GROUP_CONCAT(DISTINCT `c2`, `c1` SEPARATOR ',') FROM `t` GROUP BY `c1`"}, - {`SELECT student_name, GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ') FROM student GROUP BY student_name;`, true, "SELECT `student_name`,GROUP_CONCAT(DISTINCT `test_score` SEPARATOR ' ') FROM `student` GROUP BY `student_name`"}, + {`SELECT student_name, GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ') FROM student GROUP BY student_name;`, true, "SELECT `student_name`,GROUP_CONCAT(DISTINCT `test_score` ORDER BY `test_score` DESC SEPARATOR ' ') FROM `student` GROUP BY `student_name`"}, {`select std(c1), std(all c1), std(distinct c1) from t`, true, "SELECT STD(`c1`),STD(`c1`),STD(DISTINCT `c1`) FROM `t`"}, {`select std(c1, c2) from t`, false, ""}, {`select stddev(c1), stddev(all c1), stddev(distinct c1) from t`, true, "SELECT STDDEV(`c1`),STDDEV(`c1`),STDDEV(DISTINCT `c1`) FROM `t`"},