Fix duplicated columns for count()
André Walker [Wed, 13 Feb 2013 15:47:17 +0000 (13:47 -0200)]
When a same aggregate function was used more than once in a 'having'
clause, count() added that function more than once to 'select'.

Changes
lib/DBIx/Class.pm
lib/DBIx/Class/ResultSet.pm
t/count/count_rs.t

diff --git a/Changes b/Changes
index c69cc72..5b1d6ea 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,10 @@
 Revision history for DBIx::Class
 
+    * Fixes
+        - Fix duplicated selected columns when calling 'count' when a same
+          aggregate function is used more than once in a 'having' clause
+          (RT#83305)
+
 0.08206 2013-02-08
     * Fixes
         - Fix dbh_do() failing to properly reconnect (regression in 0.08205)
index 66fc8a3..eafc15a 100644 (file)
@@ -303,6 +303,8 @@ amiri: Amiri Barksdale <amiri@metalabel.com>
 
 amoore: Andrew Moore <amoore@cpan.org>
 
+andrewalker: Andre Walker <andre@andrewalker.net>
+
 andyg: Andy Grundman <andy@hybridized.org>
 
 ank: Andres Kievsky
index 545f993..10905b2 100644 (file)
@@ -1591,18 +1591,22 @@ sub _count_subq_rs {
 
       my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep);
 
-      my $sql = $sql_maker->_parse_rs_attrs ({ having => $attrs->{having} });
+      my $having_sql = $sql_maker->_parse_rs_attrs ({ having => $attrs->{having} });
+      my %seen_having;
 
       # search for both a proper quoted qualified string, for a naive unquoted scalarref
       # and if all fails for an utterly naive quoted scalar-with-function
-      while ($sql =~ /
+      while ($having_sql =~ /
         $rquote $sep $lquote (.+?) $rquote
           |
         [\s,] \w+ \. (\w+) [\s,]
           |
         [\s,] $lquote (.+?) $rquote [\s,]
       /gx) {
-        push @parts, ($1 || $2 || $3);  # one of them matched if we got here
+        my $part = $1 || $2 || $3;  # one of them matched if we got here
+        unless ($seen_having{$part}++) {
+          push @parts, $part;
+        }
       }
     }
 
index 88961c8..83b6257 100644 (file)
@@ -168,4 +168,42 @@ my $schema = DBICTest->init_schema();
   is ($crs->next, 2, 'Correct artist count (each with one 2001 cd)');
 }
 
+# count with two having clauses
+{
+  my $rs = $schema->resultset("Artist")->search(
+    {},
+    {
+      join      => 'cds',
+      group_by  => 'me.artistid',
+      '+select' => [ { max => 'cds.year', -as => 'newest_cd_year' } ],
+      '+as'     => ['newest_cd_year'],
+      having    => { 'newest_cd_year' => [ '1998', '2001' ] }
+    }
+  );
+
+  my $crs = $rs->count_rs;
+
+  is_same_sql_bind (
+    $crs->as_query,
+    '(SELECT COUNT( * )
+      FROM (
+        SELECT me.artistid, MAX( cds.year ) AS newest_cd_year
+          FROM artist me
+          LEFT JOIN cd cds ON cds.artist = me.artistid
+        GROUP BY me.artistid
+        HAVING newest_cd_year = ? OR newest_cd_year = ?
+      ) me
+    )',
+    [
+      [ { dbic_colname => 'newest_cd_year' }
+          => '1998' ],
+      [ { dbic_colname => 'newest_cd_year' }
+          => '2001' ],
+    ],
+    'count with having clause keeps sql as alias',
+  );
+
+  is ($crs->next, 3, 'Correct artist count (each with one 1998 or 2001 cd)');
+}
+
 done_testing;