Skip to content

Commit 3827166

Browse files
committed
Fixing SELECT COUNT(DISTINCT ...) on several columns in Oracle and PgSQL
+ another bug regarding quoting aliases
1 parent a9de52f commit 3827166

File tree

1 file changed

+92
-13
lines changed

1 file changed

+92
-13
lines changed

src/QueryFactory/FindObjectsFromRawSqlQueryFactory.php

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use TheCodingMachine\TDBM\TDBMService;
1010
use PHPSQLParser\PHPSQLCreator;
1111
use PHPSQLParser\PHPSQLParser;
12+
use function array_merge;
1213

1314
/**
1415
* This class is in charge of formatting the SQL passed to findObjectsFromRawSql method.
@@ -224,7 +225,7 @@ private function formatSelect(array $baseSelect): array
224225
],
225226
'alias' => [
226227
'as' => true,
227-
'name' => $alias,
228+
'name' => $connection->quoteIdentifier($alias),
228229
]
229230
];
230231
$formattedSelect[] = $astColumn;
@@ -352,20 +353,98 @@ private function generateGroupedSqlCount(array $parsedSql): array
352353
{
353354
$group = $parsedSql['GROUP'];
354355
unset($parsedSql['GROUP']);
355-
$parsedSql['SELECT'] = [[
356-
'expr_type' => 'aggregate_function',
357-
'alias' => [
358-
'as' => true,
359-
'name' => 'cnt',
360-
],
361-
'base_expr' => 'COUNT',
362-
'sub_tree' => array_merge([[
356+
357+
// Count(DISTINCT ...) on multiple columns is only valid in MySQL (unsupported on Pgsql or Oracle). For those, we need to do a subquery.
358+
if (count($group) === 1 || $this->tdbmService->getConnection()->getDatabasePlatform() instanceof MySqlPlatform) {
359+
$parsedSql['SELECT'] = [[
360+
'expr_type' => 'aggregate_function',
361+
'alias' => [
362+
'as' => true,
363+
'name' => 'cnt',
364+
],
365+
'base_expr' => 'COUNT',
366+
'sub_tree' => array_merge([[
367+
'expr_type' => 'reserved',
368+
'base_expr' => 'DISTINCT',
369+
'delim' => ','
370+
]], $group),
371+
'delim' => false,
372+
]];
373+
} else {
374+
$innerColumns = [[
363375
'expr_type' => 'reserved',
364376
'base_expr' => 'DISTINCT',
365-
'delim' => ','
366-
]], $group),
367-
'delim' => false,
368-
]];
377+
'delim' => ' '
378+
]];
379+
foreach ($group as $item) {
380+
$item['delim'] = ',';
381+
$innerColumns[] = $item;
382+
}
383+
$innerColumns[count($innerColumns)-1]['delim'] = false;
384+
$parsedSql['SELECT'] = $innerColumns;
385+
386+
$parsedSql = [
387+
'SELECT' =>
388+
[
389+
0 =>
390+
[
391+
'expr_type' => 'aggregate_function',
392+
'alias' =>
393+
[
394+
'as' => true,
395+
'name' => 'cnt',
396+
'base_expr' => 'AS cnt',
397+
'no_quotes' =>
398+
[
399+
'delim' => false,
400+
'parts' =>
401+
[
402+
0 => 'cnt',
403+
],
404+
],
405+
],
406+
'base_expr' => 'COUNT',
407+
'sub_tree' =>
408+
[
409+
0 =>
410+
[
411+
'expr_type' => 'colref',
412+
'base_expr' => '*',
413+
'sub_tree' => false,
414+
],
415+
],
416+
'delim' => false,
417+
],
418+
],
419+
'FROM' =>
420+
[
421+
0 =>
422+
[
423+
'expr_type' => 'subquery',
424+
'alias' =>
425+
[
426+
'as' => false,
427+
'name' => 'subquery',
428+
'no_quotes' =>
429+
[
430+
'delim' => false,
431+
'parts' =>
432+
[
433+
0 => 'subquery',
434+
],
435+
],
436+
'base_expr' => 'subquery',
437+
],
438+
'hints' => false,
439+
'join_type' => 'JOIN',
440+
'ref_type' => false,
441+
'ref_clause' => false,
442+
//'base_expr' => 'SELECT id FROM country',
443+
'sub_tree' => $parsedSql
444+
],
445+
],
446+
];
447+
}
369448
return $parsedSql;
370449
}
371450

0 commit comments

Comments
 (0)