Skip to content

Commit 95cf197

Browse files
committed
fix: Support DISTINCT in GROUP_CONCAT
1 parent 839b2fb commit 95cf197

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

src/Parser/ExpressionParser.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,14 @@ private function getListExpression(array $tokens)
137137
$needs_comma = false;
138138
$args = [];
139139

140+
if (isset($tokens[0]) && $tokens[0]->value == "DISTINCT") {
141+
$distinct = true;
142+
$pos++;
143+
}
144+
140145
while ($pos < $token_count) {
141146
$arg = $tokens[$pos];
142147

143-
144148
if ($arg->value === ',') {
145149
if ($needs_comma) {
146150
$needs_comma = false;
@@ -151,14 +155,21 @@ private function getListExpression(array $tokens)
151155
}
152156
}
153157

158+
159+
if ($arg->value === 'ORDER') {
160+
$p = new OrderByParser($pos, $tokens);
161+
[$pos, $order_by] = $p->parse();
162+
continue;
163+
}
164+
154165
$p = new ExpressionParser($tokens, $pos - 1);
155166
list($pos, $expr) = $p->buildWithPointer();
156167
$args[] = $expr;
157168
$pos++;
158169
$needs_comma = true;
159170
}
160171

161-
return [$distinct, $args];
172+
return [$distinct, $args, $order_by ?? null];
162173
}
163174

164175
/**

src/Processor/Expression/FunctionEvaluator.php

+12-7
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public static function evaluate(
6767
case 'CONCAT':
6868
return self::sqlConcat($conn, $scope, $expr, $row, $result);
6969
case 'GROUP_CONCAT':
70-
return self::sqlGroupConcat($conn, $scope, $expr, $row, $result);
70+
return self::sqlGroupConcat($conn, $scope, $expr, $result);
7171
case 'FIELD':
7272
return self::sqlColumn($conn, $scope, $expr, $row, $result);
7373
case 'BINARY':
@@ -941,18 +941,23 @@ private static function sqlGroupConcat(
941941
FakePdoInterface $conn,
942942
Scope $scope,
943943
FunctionExpression $expr,
944-
array $row,
945944
QueryResult $result
946945
): string {
947946
$args = $expr->args;
948947

949-
$final_concat = "";
950-
foreach ($args as $arg) {
951-
$val = (string) Evaluator::evaluate($conn, $scope, $arg, $row, $result);
952-
$final_concat .= $val;
948+
$items = [];
949+
foreach ($result->rows as $row) {
950+
$tmp_str = "";
951+
foreach ($args as $arg) {
952+
$val = (string) Evaluator::evaluate($conn, $scope, $arg, $row, $result);
953+
$tmp_str .= $val;
954+
}
955+
if ($tmp_str !== "" && (!$expr->distinct || !isset($items[$tmp_str]))) {
956+
$items[$tmp_str] = $tmp_str;
957+
}
953958
}
954959

955-
return $final_concat;
960+
return implode(",", array_values($items));
956961
}
957962

958963
/**

tests/EndToEndTest.php

+28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
namespace Vimeo\MysqlEngine\Tests;
34

45
use PDOException;
@@ -911,6 +912,33 @@ public function testInsertWithNullAndEmpty()
911912
);
912913
}
913914

915+
public function testGroupConcat()
916+
{
917+
$pdo = self::getConnectionToFullDB(false);
918+
919+
$query = $pdo->prepare(
920+
'SELECT `type`, GROUP_CONCAT(DISTINCT `profession`) as `profession_list`
921+
FROM `video_game_characters`
922+
GROUP BY `type`'
923+
);
924+
925+
$query->execute();
926+
927+
$this->assertSame(
928+
[
929+
[
930+
"type" => "hero",
931+
"profession_list" => "plumber,hedgehog,earthworm,monkey,pokemon,princess,boxer,yellow circle,dinosaur,not sure,sure"
932+
],
933+
[
934+
"type" => "villain",
935+
"profession_list" => "evil dinosaur,evil doctor,throwing shit from clouds,evil chain dude"
936+
],
937+
],
938+
$query->fetchAll(\PDO::FETCH_ASSOC)
939+
);
940+
}
941+
914942
public function testOrderBySecondDimensionAliased()
915943
{
916944
$pdo = self::getConnectionToFullDB(false);

0 commit comments

Comments
 (0)