Fix incorrect handling of auto-generated COUNT(*) queries when there are GROUP BY or DISTINCT clauses

This commit is contained in:
Kijin Sung 2021-01-07 00:55:43 +09:00
parent c80a80f986
commit 3f766a937c
2 changed files with 30 additions and 15 deletions

View file

@ -437,6 +437,7 @@ class DB
// Compose the output object.
$output = new \BaseObject;
$output->add('_count', $query_string);
$output->total_count = $total_count;
$output->total_page = $total_page;
$output->page = $page;

View file

@ -115,27 +115,16 @@ class Query extends VariableBase
*/
protected function _getSelectQueryString(bool $count_only = false): string
{
// Initialize the query string.
$result = 'SELECT ';
if ($this->select_distinct)
{
$result .= 'DISTINCT ';
}
// Compose the column list.
$columns = array();
if ($count_only)
if ($this->_column_list)
{
$result .= 'COUNT(*) AS `count`';
}
elseif ($this->_column_list)
{
$result .= implode(', ', array_map(function($str) {
$column_list = implode(', ', array_map(function($str) {
return self::quoteName($str);
}, $this->_column_list));
}
else
{
$columns = array();
foreach ($this->columns as $column)
{
if ($column instanceof self)
@ -156,7 +145,26 @@ class Query extends VariableBase
$columns[] = self::quoteName($column->name) . ($column->alias ? (' AS ' . self::quoteName($column->alias)) : '');
}
}
$result .= implode(', ', $columns);
$column_list = implode(', ', $columns);
}
// Replace the column list if this is a count-only query.
if ($count_only)
{
$count_wrap = ($this->groupby || $this->select_distinct || preg_match('/\bDISTINCT\b/i', $column_list));
if ($count_wrap && ($column_list === '*' || preg_match('/\\.\\*/', $column_list)))
{
$result = 'SELECT 1';
}
else
{
$result = 'SELECT COUNT(*) AS `count`';
}
}
else
{
$count_wrap = false;
$result = 'SELECT ' . ($this->select_distinct ? 'DISTINCT ' : '') . $column_list;
}
// Compose the FROM clause.
@ -225,6 +233,12 @@ class Query extends VariableBase
$result .= ' LIMIT ' . $this->_arrangeLimitOffset($this->navigation);
}
// Wrap in a subquery if necesary.
if ($count_wrap)
{
$result = 'SELECT COUNT(*) AS `count` FROM (' . $result . ') AS `subquery`';
}
// Return the final query string.
return $result;
}