[nextgen-gallery] Check ORDER BY in SELECT DISTINCT

MySQL supports ordering by columns which do not appear in the field list
for a SELECT DISTINCT statement while PostgreSQL does not.  This results
in errors such as:

Error running :
SELECT DISTINCT pid , GROUP_CONCAT(CONCAT_WS('@@', meta_key, meta_value)) AS `extras` FROM `wp_ngg_pictures` LEFT OUTER JOIN `wp_postmeta` ON `wp_postmeta`.`post_id` = `extras_post_id`  WHERE (`exclude` = 0) AND (`galleryid` IN (2)) GROUP BY wp_ngg_pictures.pid ORDER BY `sortorder` ASC
---- converted to ----
SELECT DISTINCT pid , string_agg(CONCAT_WS('@@', meta_key, meta_value), ',') AS extras FROM wp_ngg_pictures LEFT OUTER JOIN wp_postmeta ON wp_postmeta.post_id = extras_post_id  WHERE (exclude = 0) AND (galleryid IN (2)) GROUP BY wp_ngg_pictures.pid ORDER BY sortorder ASC
----> ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
LINE 1: ...yid IN (2)) GROUP BY wp_ngg_pictures.pid ORDER BY sortorder ...
                                                             ^
To avoid this error, ensure that the field listed in the ORDER BY
statement also appears in the SELECT statement.  To support GROUP BY
statements, ensure that it is aggregated using MIN() to mimic the MySQL
behavior.

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
This commit is contained in:
Kevin Locke
2015-06-06 20:33:15 -06:00
parent c2f5a06ae6
commit a9edb3a572

View File

@ -227,6 +227,24 @@
$sql = preg_replace( $pattern, 'SELECT COUNT($1) $2', $sql);
}
// Ensure that ORDER BY column appears in SELECT DISTINCT fields
$pattern = '/^SELECT DISTINCT.*ORDER BY\s+(\S+)/';
if( preg_match( $pattern, $sql, $matches) &&
strpos( $sql, $matches[1]) > strpos( $sql, 'ORDER BY') &&
false === strpos( $sql, '*'))
{
if( false !== strpos( $sql, 'GROUP BY'))
{
$pattern = '/ FROM /';
$sql = preg_replace( $pattern, ', MIN('.$matches[1].') AS '.$matches[1].' FROM ', $sql, 1);
}
else
{
$pattern = '/ FROM /';
$sql = preg_replace( $pattern, ', '.$matches[1].' FROM ', $sql, 1);
}
}
// Convert CONVERT to CAST
$pattern = '/CONVERT\(([^()]*(\(((?>[^()]+)|(?-2))*\))?[^()]*),\s*([^\s]+)\)/x';
$sql = preg_replace( $pattern, 'CAST($1 AS $4)', $sql);