Merge 'trunk' into 'void_populate_resultset_cond'
Peter Rabbitson [Tue, 17 Nov 2009 23:42:13 +0000 (23:42 +0000)]
r7765@Thesaurus (orig r7753):  ribasushi | 2009-10-03 15:49:14 +0200
Test reorg (no changes)
r7766@Thesaurus (orig r7754):  ribasushi | 2009-10-03 15:55:25 +0200
Add failing tests for RT#50003
r7767@Thesaurus (orig r7755):  caelum | 2009-10-03 16:09:45 +0200
fix on_connect_ with coderef connect_info
r7771@Thesaurus (orig r7759):  ribasushi | 2009-10-04 13:17:53 +0200
Fix AutoCast's POD
r7782@Thesaurus (orig r7770):  ribasushi | 2009-10-09 06:57:20 +0200
 r7777@Thesaurus (orig r7765):  frew | 2009-10-07 20:05:05 +0200
 add method to check if an rs is paginated
 r7778@Thesaurus (orig r7766):  frew | 2009-10-07 20:31:02 +0200
 is_paginated method and test
 r7780@Thesaurus (orig r7768):  frew | 2009-10-09 06:45:36 +0200
 change name of method
 r7781@Thesaurus (orig r7769):  frew | 2009-10-09 06:47:31 +0200
 add message to changelog for is_paged

r7785@Thesaurus (orig r7773):  ribasushi | 2009-10-09 11:00:36 +0200
Ugh CRLF
r7786@Thesaurus (orig r7774):  ribasushi | 2009-10-09 11:04:35 +0200
Skip versioning test on really old perls lacking Time::HiRes
r7787@Thesaurus (orig r7775):  ribasushi | 2009-10-09 11:04:50 +0200
Changes
r7788@Thesaurus (orig r7776):  triode | 2009-10-09 22:32:04 +0200
added troubleshooting case of excessive memory allocation involving TEXT/BLOB/etc
columns and large LongReadLen

r7789@Thesaurus (orig r7777):  triode | 2009-10-09 22:44:21 +0200
added my name to contributors list

r7790@Thesaurus (orig r7778):  ribasushi | 2009-10-10 18:49:15 +0200
Whoops, this isn't right
r7791@Thesaurus (orig r7779):  ribasushi | 2009-10-11 15:44:18 +0200
More ordered fixes
r7793@Thesaurus (orig r7781):  norbi | 2009-10-13 11:27:18 +0200
 r7982@vger:  mendel | 2009-10-13 11:26:11 +0200
 Fixed a typo and a POD error.

r7805@Thesaurus (orig r7793):  ribasushi | 2009-10-16 14:28:35 +0200
Fix test to stop failing when DT-support is not present
r7811@Thesaurus (orig r7799):  caelum | 2009-10-18 11:13:29 +0200
 r20728@hlagh (orig r7703):  ribasushi | 2009-09-20 18:51:16 -0400
 Another try at a clean sybase branch
 r20730@hlagh (orig r7705):  ribasushi | 2009-09-20 18:58:09 -0400
 Part one of the sybase work by Caelum (mostly reviewed)
 r20731@hlagh (orig r7706):  ribasushi | 2009-09-20 19:18:40 -0400
 main sybase branch ready
 r21051@hlagh (orig r7797):  caelum | 2009-10-18 04:57:43 -0400
  r20732@hlagh (orig r7707):  ribasushi | 2009-09-20 19:20:00 -0400
  Branch for bulk insert
  r20733@hlagh (orig r7708):  ribasushi | 2009-09-20 20:06:21 -0400
  All sybase bulk-insert code by Caelum
  r20750@hlagh (orig r7725):  caelum | 2009-09-24 02:47:39 -0400
  clean up set_identity stuff
  r20751@hlagh (orig r7726):  caelum | 2009-09-24 05:21:18 -0400
  minor cleanups, test update of blob to NULL
  r20752@hlagh (orig r7727):  caelum | 2009-09-24 08:45:04 -0400
  remove some duplicate code
  r20753@hlagh (orig r7728):  caelum | 2009-09-24 09:57:58 -0400
  fix insert with all defaults
  r20786@hlagh (orig r7732):  caelum | 2009-09-25 21:17:16 -0400
  some cleanups
  r20804@hlagh (orig r7736):  caelum | 2009-09-28 05:31:38 -0400
  minor changes
  r20805@hlagh (orig r7737):  caelum | 2009-09-28 06:25:48 -0400
  fix DT stuff
  r20809@hlagh (orig r7741):  caelum | 2009-09-28 22:25:55 -0400
  removed some dead code, added fix and test for _execute_array_empty
  r20811@hlagh (orig r7743):  caelum | 2009-09-29 13:36:20 -0400
  minor changes after review
  r20812@hlagh (orig r7744):  caelum | 2009-09-29 14:16:03 -0400
  do not clobber $rv from execute_array
  r20813@hlagh (orig r7745):  caelum | 2009-09-29 14:38:14 -0400
  make insert_bulk atomic
  r20815@hlagh (orig r7747):  caelum | 2009-09-29 20:35:26 -0400
  remove _exhaaust_statements
  r20816@hlagh (orig r7748):  caelum | 2009-09-29 21:48:38 -0400
  fix insert_bulk when not using bulk api inside a txn
  r20831@hlagh (orig r7749):  caelum | 2009-09-30 02:53:42 -0400
  added test for populate being atomic
  r20832@hlagh (orig r7750):  caelum | 2009-09-30 03:00:59 -0400
  factor out subclass-specific _execute_array callback
  r20833@hlagh (orig r7751):  caelum | 2009-10-01 11:59:30 -0400
  remove a piece of dead code
  r20840@hlagh (orig r7758):  caelum | 2009-10-03 15:46:56 -0400
  remove _pretty_print
  r20842@hlagh (orig r7760):  caelum | 2009-10-04 16:19:56 -0400
  minor optimization for insert_bulk
  r21050@hlagh (orig r7796):  caelum | 2009-10-18 04:56:54 -0400
  error checking related to literal SQL for insert_bulk

r7820@Thesaurus (orig r7808):  caelum | 2009-10-21 03:10:39 +0200
add test for populate with literal sql mixed with binds, improve error messages
r7823@Thesaurus (orig r7811):  ribasushi | 2009-10-21 16:33:45 +0200
Show what's wrong with the current populate code
r7824@Thesaurus (orig r7812):  caelum | 2009-10-22 11:10:38 +0200
stringify values passed to populate/insert_bulk
r7825@Thesaurus (orig r7813):  ribasushi | 2009-10-22 13:17:41 +0200
Some smoker run the suite for 30 *minutes* - the timeout seems to be too short for them (boggle)
r7826@Thesaurus (orig r7814):  caelum | 2009-10-22 14:41:37 +0200
a few extra tests can never hurt, right? :)
r7827@Thesaurus (orig r7815):  ribasushi | 2009-10-23 10:51:05 +0200
Prevent sqlt from failing silently
r7828@Thesaurus (orig r7816):  ribasushi | 2009-10-23 10:52:49 +0200
{ is_foreign_key_constraint => 0, on_delete => undef } is a valid construct - no need to carp
r7832@Thesaurus (orig r7820):  robkinyon | 2009-10-26 20:11:22 +0100
Fixed bad if-check in columns()
r7840@Thesaurus (orig r7828):  caelum | 2009-10-31 14:01:56 +0100
change repository in meta to point to real svn url rather than svnweb
r7842@Thesaurus (orig r7830):  caelum | 2009-10-31 21:04:39 +0100
pass sqlite_version to SQLT
r7843@Thesaurus (orig r7831):  caelum | 2009-10-31 21:22:37 +0100
fix regex to numify sqlite_version
r7844@Thesaurus (orig r7832):  caelum | 2009-10-31 23:59:19 +0100
work-around disconnect bug with DBD::Pg 2.15.1
r7855@Thesaurus (orig r7843):  ribasushi | 2009-11-04 10:55:51 +0100
 r7817@Thesaurus (orig r7805):  rbuels | 2009-10-21 02:37:28 +0200
 making a branch, here we go again with the pg_unqualified_schema
 r7818@Thesaurus (orig r7806):  rbuels | 2009-10-21 02:38:59 +0200
 more pg unqualified schema tests, which expose a gap in the coverage
 r7819@Thesaurus (orig r7807):  rbuels | 2009-10-21 03:10:38 +0200
 gutted Pg storage driver's sequence discovery to just rely on DBD::Pg's last_insert_id.  this needs testing with older versions of DBD::Pg
 r7821@Thesaurus (orig r7809):  rbuels | 2009-10-21 04:00:39 +0200
 more coverage in Pg sequence-discovery tests.  i think this shows why last_insert_id cannot be used.
 r7822@Thesaurus (orig r7810):  rbuels | 2009-10-21 04:07:05 +0200
 reverted [7807], and just changed code to use the custom pg_catalog query, which is the only thing that works in the pathological case where DBIC is told a different primary key from the primary key that is set on the table in the DB ([7809] added testing for this)
 r7852@Thesaurus (orig r7840):  rbuels | 2009-11-03 18:47:05 +0100
 added Changes line mentioning tweak to Pg auto-inc fix
 r7854@Thesaurus (orig r7842):  ribasushi | 2009-11-04 10:55:35 +0100
 Cleanup exceptions

r7858@Thesaurus (orig r7846):  caelum | 2009-11-06 16:01:30 +0100
transactions for MSSQL over DBD::Sybase
r7861@Thesaurus (orig r7849):  caelum | 2009-11-10 13:16:18 +0100
made commit/rollback when disconnected an exception
r7862@Thesaurus (orig r7850):  robkinyon | 2009-11-10 17:19:57 +0100
Added a note about select
r7863@Thesaurus (orig r7851):  ribasushi | 2009-11-10 18:23:10 +0100
Changes
r7867@Thesaurus (orig r7855):  frew | 2009-11-11 21:56:37 +0100
RT50874
r7868@Thesaurus (orig r7856):  frew | 2009-11-11 23:50:43 +0100
RT50828
r7869@Thesaurus (orig r7857):  frew | 2009-11-11 23:54:15 +0100
clearer test message
r7870@Thesaurus (orig r7858):  frew | 2009-11-12 00:37:27 +0100
some cleanup for $rs->populate
r7872@Thesaurus (orig r7860):  ribasushi | 2009-11-12 01:35:36 +0100
Fix find on resultset with custom result_class
r7873@Thesaurus (orig r7861):  ribasushi | 2009-11-12 01:40:14 +0100
Fix return value of in_storage
r7874@Thesaurus (orig r7862):  ribasushi | 2009-11-12 01:43:48 +0100
Extra FAQ entry
r7875@Thesaurus (orig r7863):  ribasushi | 2009-11-12 02:11:25 +0100
Sanify _determine_driver handling in ::Storage::DBI
r7876@Thesaurus (orig r7864):  ribasushi | 2009-11-12 02:14:37 +0100
Add mysql determine_driver test by Pedro Melo
r7881@Thesaurus (orig r7869):  ribasushi | 2009-11-12 11:10:04 +0100
_cond_for_update_delete is hopelessly broken attempting to introspect SQLA1. Replace with a horrific but effective hack
r7882@Thesaurus (orig r7870):  ribasushi | 2009-11-12 11:15:12 +0100
Clarifying comment
r7884@Thesaurus (orig r7872):  ribasushi | 2009-11-13 00:13:40 +0100
The real fix for the non-introspectable condition bug, mst++
r7885@Thesaurus (orig r7873):  ribasushi | 2009-11-13 00:24:56 +0100
Some cleanup
r7887@Thesaurus (orig r7875):  frew | 2009-11-13 10:01:37 +0100
fix subtle bug with Sybase database type determination
r7892@Thesaurus (orig r7880):  frew | 2009-11-14 00:53:29 +0100
release woo!
r7894@Thesaurus (orig r7882):  caelum | 2009-11-14 03:57:52 +0100
fix oracle dep in Makefile.PL
r7895@Thesaurus (orig r7883):  caelum | 2009-11-14 04:20:53 +0100
skip Oracle BLOB tests on DBD::Oracle == 1.23
r7897@Thesaurus (orig r7885):  caelum | 2009-11-14 09:40:01 +0100
 r7357@pentium (orig r7355):  caelum | 2009-08-20 17:58:23 -0400
 branch to support MSSQL over ADO
 r7358@pentium (orig r7356):  caelum | 2009-08-21 00:32:14 -0400
 something apparently working
 r7359@pentium (orig r7357):  caelum | 2009-08-21 00:53:53 -0400
 slightly better mars test, still passes

r7899@Thesaurus (orig r7887):  caelum | 2009-11-14 09:41:54 +0100
 r7888@pentium (orig r7886):  caelum | 2009-11-14 03:41:25 -0500
 add TODO test for large column list in select

r7901@Thesaurus (orig r7889):  caelum | 2009-11-14 09:47:16 +0100
add ADO/MSSQL to Changes
r7902@Thesaurus (orig r7890):  caelum | 2009-11-14 10:27:29 +0100
fix the large column list test for ADO/MSSQL, now passes
r7904@Thesaurus (orig r7892):  caelum | 2009-11-14 12:20:58 +0100
fix Changes (ADO change in wrong release)
r7905@Thesaurus (orig r7893):  ribasushi | 2009-11-14 19:23:23 +0100
Release 0.08114
r7907@Thesaurus (orig r7895):  ribasushi | 2009-11-15 12:09:17 +0100
Failing test to highlight mssql autoconnect regression
r7908@Thesaurus (orig r7896):  ribasushi | 2009-11-15 12:20:25 +0100
Fix plan
r7913@Thesaurus (orig r7901):  ribasushi | 2009-11-15 13:11:38 +0100
 r7773@Thesaurus (orig r7761):  norbi | 2009-10-05 14:49:06 +0200
 Created branch 'prefetch_bug-unqualified_column_in_search_related_cond': A bug that manifests when a prefetched table's column is referenced without the table name in the condition of a search_related() on an M:N relationship.
 r7878@Thesaurus (orig r7866):  ribasushi | 2009-11-12 02:36:08 +0100
 Factor some code out
 r7879@Thesaurus (orig r7867):  ribasushi | 2009-11-12 09:11:03 +0100
 Factor out more stuff
 r7880@Thesaurus (orig r7868):  ribasushi | 2009-11-12 09:21:04 +0100
 Saner naming/comments
 r7910@Thesaurus (orig r7898):  ribasushi | 2009-11-15 12:39:29 +0100
 Move more code to DBIHacks, put back the update/delete rs check, just in case
 r7911@Thesaurus (orig r7899):  ribasushi | 2009-11-15 13:01:34 +0100
 TODOify test until we get an AST
 r7912@Thesaurus (orig r7900):  ribasushi | 2009-11-15 13:10:15 +0100
 Hide from pause

r7921@Thesaurus (orig r7909):  ribasushi | 2009-11-15 14:17:48 +0100
 r7871@Thesaurus (orig r7859):  ribasushi | 2009-11-12 00:46:07 +0100
 Branches to test some ideas
 r7889@Thesaurus (orig r7877):  abraxxa | 2009-11-13 12:05:50 +0100
 added rels to view result classes in test schema

 r7890@Thesaurus (orig r7878):  abraxxa | 2009-11-13 13:05:45 +0100
 seems I found the bugger

 r7917@Thesaurus (orig r7905):  ribasushi | 2009-11-15 13:29:23 +0100
 FK constraints towards a view don't quite work
 r7918@Thesaurus (orig r7906):  ribasushi | 2009-11-15 14:10:10 +0100
 Turn into a straight-inheritance view class
 r7919@Thesaurus (orig r7907):  ribasushi | 2009-11-15 14:11:03 +0100
 Extensive test of virtual and classic view relationships
 r7920@Thesaurus (orig r7908):  ribasushi | 2009-11-15 14:17:23 +0100
 Fix non-sqlt schema file

r7923@Thesaurus (orig r7911):  caelum | 2009-11-15 18:31:37 +0100
fix MSSQL via DBD::Sybase regression
r7930@Thesaurus (orig r7918):  ribasushi | 2009-11-16 19:15:45 +0100
 r7864@Thesaurus (orig r7852):  edenc | 2009-11-10 20:15:15 +0100
 branching for fixes related to prefetch, distinct and group by
 r7865@Thesaurus (orig r7853):  edenc | 2009-11-10 20:21:38 +0100
 added test case for ensuring a column mentioned in the order by clause is also included in the group by clause
 r7926@Thesaurus (orig r7914):  ribasushi | 2009-11-16 08:09:30 +0100
 Make _resolve_column_info function without supplying column names
 r7927@Thesaurus (orig r7915):  ribasushi | 2009-11-16 08:11:17 +0100
 Fix order_by/distinct bug

1  2 
lib/DBIx/Class/ResultSet.pm

@@@ -357,9 -357,9 +357,9 @@@ sub search_rs 
    }
  
    my $rs = (ref $self)->new($self->result_source, $new_attrs);
-   if ($rows) {
-     $rs->set_cache($rows);
-   }
+   $rs->set_cache($rows) if ($rows);
    return $rs;
  }
  
@@@ -519,7 -519,7 +519,7 @@@ sub find 
      # in ::Relationship::Base::search_related (the row method), and furthermore
      # the relationship is of the 'single' type. This means that the condition
      # provided by the relationship (already attached to $self) is sufficient,
-     # as there can be only one row in the databse that would satisfy the 
+     # as there can be only one row in the databse that would satisfy the
      # relationship
    }
    else {
    }
  
    # Run the query
-   my $rs = $self->search ($query, $attrs);
+   my $rs = $self->search ($query, {result_class => $self->result_class, %$attrs});
    if (keys %{$rs->_resolved_attrs->{collapse}}) {
      my $row = $rs->next;
      carp "Query returned more than one row" if $rs->next;
@@@ -1240,7 -1240,7 +1240,7 @@@ sub _count_rs 
  
    my $tmp_attrs = { %$attrs };
  
-   # take off any limits, record_filter is cdbi, and no point of ordering a count 
+   # take off any limits, record_filter is cdbi, and no point of ordering a count
    delete $tmp_attrs->{$_} for (qw/select as rows offset order_by record_filter/);
  
    # overwrite the selector (supplied by the storage)
    $tmp_attrs->{as} = 'count';
  
    # read the comment on top of the actual function to see what this does
-   $tmp_attrs->{from} = $self->_switch_to_inner_join_if_needed (
+   $tmp_attrs->{from} = $self->result_source->schema->storage->_straight_join_to_node (
      $tmp_attrs->{from}, $tmp_attrs->{alias}
    );
  
@@@ -1280,11 -1280,13 +1280,13 @@@ sub _count_subq_rs 
    $sub_attrs->{select} = $rsrc->storage->_subq_count_select ($rsrc, $sub_attrs);
  
    # read the comment on top of the actual function to see what this does
-   $sub_attrs->{from} = $self->_switch_to_inner_join_if_needed (
+   $sub_attrs->{from} = $self->result_source->schema->storage->_straight_join_to_node (
      $sub_attrs->{from}, $sub_attrs->{alias}
    );
  
-   # this is so that ordering can be thrown away in things like Top limit
+   # this is so that the query can be simplified e.g.
+   # * non-limiting joins can be pruned
+   # * ordering can be thrown away in things like Top limit
    $sub_attrs->{-for_count_only} = 1;
  
    my $sub_rs = $rsrc->resultset_class->new ($rsrc, $sub_attrs);
    return $self->_count_rs ($attrs);
  }
  
- # The DBIC relationship chaining implementation is pretty simple - every
- # new related_relationship is pushed onto the {from} stack, and the {select}
- # window simply slides further in. This means that when we count somewhere
- # in the middle, we got to make sure that everything in the join chain is an
- # actual inner join, otherwise the count will come back with unpredictable
- # results (a resultset may be generated with _some_ rows regardless of if
- # the relation which the $rs currently selects has rows or not). E.g.
- # $artist_rs->cds->count - normally generates:
- # SELECT COUNT( * ) FROM artist me LEFT JOIN cd cds ON cds.artist = me.artistid
- # which actually returns the number of artists * (number of cds || 1)
- #
- # So what we do here is crawl {from}, determine if the current alias is at
- # the top of the stack, and if not - make sure the chain is inner-joined down
- # to the root.
- #
- sub _switch_to_inner_join_if_needed {
-   my ($self, $from, $alias) = @_;
-   # subqueries and other oddness is naturally not supported
-   return $from if (
-     ref $from ne 'ARRAY'
-       ||
-     @$from <= 1
-       ||
-     ref $from->[0] ne 'HASH'
-       ||
-     ! $from->[0]{-alias}
-       ||
-     $from->[0]{-alias} eq $alias
-   );
-   my $switch_branch;
-   JOINSCAN:
-   for my $j (@{$from}[1 .. $#$from]) {
-     if ($j->[0]{-alias} eq $alias) {
-       $switch_branch = $j->[0]{-join_path};
-       last JOINSCAN;
-     }
-   }
-   # something else went wrong
-   return $from unless $switch_branch;
-   # So it looks like we will have to switch some stuff around.
-   # local() is useless here as we will be leaving the scope
-   # anyway, and deep cloning is just too fucking expensive
-   # So replace the inner hashref manually
-   my @new_from = ($from->[0]);
-   my $sw_idx = { map { $_ => 1 } @$switch_branch };
-   for my $j (@{$from}[1 .. $#$from]) {
-     my $jalias = $j->[0]{-alias};
-     if ($sw_idx->{$jalias}) {
-       my %attrs = %{$j->[0]};
-       delete $attrs{-join_type};
-       push @new_from, [
-         \%attrs,
-         @{$j}[ 1 .. $#$j ],
-       ];
-     }
-     else {
-       push @new_from, $j;
-     }
-   }
-   return \@new_from;
- }
  sub _bool {
    return 1;
  }
@@@ -1495,8 -1426,12 +1426,12 @@@ sub _rs_update_delete 
  
    my $rsrc = $self->result_source;
  
+   # if a condition exists we need to strip all table qualifiers
+   # if this is not possible we'll force a subquery below
+   my $cond = $rsrc->schema->storage->_strip_cond_qualifiers ($self->{cond});
    my $needs_group_by_subq = $self->_has_resolved_attr (qw/collapse group_by -join/);
-   my $needs_subq = $self->_has_resolved_attr (qw/row offset/);
+   my $needs_subq = (not defined $cond) || $self->_has_resolved_attr(qw/row offset/);
  
    if ($needs_group_by_subq or $needs_subq) {
  
      return $rsrc->storage->$op(
        $rsrc,
        $op eq 'update' ? $values : (),
-       $self->_cond_for_update_delete,
+       $cond,
      );
    }
  }
  
- # _cond_for_update_delete
- #
- # update/delete require the condition to be modified to handle
- # the differing SQL syntax available.  This transforms the $self->{cond}
- # appropriately, returning the new condition.
- sub _cond_for_update_delete {
-   my ($self, $full_cond) = @_;
-   my $cond = {};
-   $full_cond ||= $self->{cond};
-   # No-op. No condition, we're updating/deleting everything
-   return $cond unless ref $full_cond;
-   if (ref $full_cond eq 'ARRAY') {
-     $cond = [
-       map {
-         my %hash;
-         foreach my $key (keys %{$_}) {
-           $key =~ /([^.]+)$/;
-           $hash{$1} = $_->{$key};
-         }
-         \%hash;
-       } @{$full_cond}
-     ];
-   }
-   elsif (ref $full_cond eq 'HASH') {
-     if ((keys %{$full_cond})[0] eq '-and') {
-       $cond->{-and} = [];
-       my @cond = @{$full_cond->{-and}};
-        for (my $i = 0; $i < @cond; $i++) {
-         my $entry = $cond[$i];
-         my $hash;
-         if (ref $entry eq 'HASH') {
-           $hash = $self->_cond_for_update_delete($entry);
-         }
-         else {
-           $entry =~ /([^.]+)$/;
-           $hash->{$1} = $cond[++$i];
-         }
-         push @{$cond->{-and}}, $hash;
-       }
-     }
-     else {
-       foreach my $key (keys %{$full_cond}) {
-         $key =~ /([^.]+)$/;
-         $cond->{$1} = $full_cond->{$key};
-       }
-     }
-   }
-   else {
-     $self->throw_exception("Can't update/delete on resultset with condition unless hash or array");
-   }
-   return $cond;
- }
  =head2 update
  
  =over 4
@@@ -1794,10 -1670,19 +1670,19 @@@ sub populate 
      }
      return wantarray ? @created : \@created;
    } else {
-     my ($first, @rest) = @$data;
+     my $first = $data->[0];
+     # if a column is a registered relationship, and is a non-blessed hash/array, consider
+     # it relationship data
+     my (@rels, @columns);
+     for (keys %$first) {
+       my $ref = ref $first->{$_};
+       $self->result_source->has_relationship($_) && ($ref eq 'ARRAY' or $ref eq 'HASH')
+         ? push @rels, $_
+         : push @columns, $_
+       ;
+     }
  
-     my @names = grep {!ref $first->{$_}} keys %$first;
-     my @rels = grep { $self->result_source->has_relationship($_) } keys %$first;
      my @pks = $self->result_source->primary_columns;
  
      ## do the belongs_to relationships
          delete $data->[$index]->{$rel};
          $data->[$index] = {%{$data->[$index]}, %$related};
  
-         push @names, keys %$related if $index == 0;
+         push @columns, keys %$related if $index == 0;
        }
      }
  
 +    ## merge with the conditions from $self (inherited conditions)
 +    my ($inherited_cond) = $self->_merge_with_cond({});
 +    delete @{$inherited_cond}{@names};
 +    my @inherited_names = keys %$inherited_cond;
 +    my @values;
 +    foreach my $row (@$data) {
 +      my %row_data;
 +      @row_data{@names} = @{$row}{@names};
 +      my ($merged_cond) = $self->_merge_with_cond(\%row_data);
 +      push @values, [ @{$merged_cond}{@names, @inherited_names} ];
 +    }
 +    push @names, @inherited_names;
 +
      ## do bulk insert on current row
      $self->result_source->storage->insert_bulk(
        $self->result_source,
-       \@names,
-       \@values,
+       \@columns,
+       [ map { [ @$_{@columns} ] } @$data ],
      );
  
      ## do the has_many relationships
        foreach my $rel (@rels) {
          next unless $item->{$rel} && ref $item->{$rel} eq "ARRAY";
  
-         my $parent = $self->find(map {{$_=>$item->{$_}} } @pks)
+         my $parent = $self->find({map { $_ => $item->{$_} } @pks})
       || $self->throw_exception('Cannot find the relating object.');
  
          my $child = $parent->$rel;
@@@ -1984,39 -1856,15 +1869,39 @@@ sub new_result 
    $self->throw_exception( "new_result needs a hash" )
      unless (ref $values eq 'HASH');
  
 -  my %new;
 +  my ($merged_cond, $from_resultset) = $self->_merge_with_cond($values);
 +
 +  my %new = (
 +    %$merged_cond,
 +    @$from_resultset
 +      ? (-from_resultset => $from_resultset)
 +      : (),
 +    -source_handle => $self->_source_handle,
 +    -result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED
 +  );
 +
 +  return $self->result_class->new(\%new);
 +}
 +
 +# _merge_with_cond
 +#
 +# Merges $values (a hashref) with the condition in the resultset and returns
 +# the resulting hashref and an arrayref that contains the keys that are coming
 +# from related resultsets.
 +
 +sub _merge_with_cond {
 +  my ($self, $values) = @_;
 +
 +  my (%merged_cond, @from_resultset);
 +
    my $alias = $self->{attrs}{alias};
  
    if (
      defined $self->{cond}
      && $self->{cond} eq $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION
    ) {
 -    %new = %{ $self->{attrs}{related_objects} || {} };  # nothing might have been inserted yet
 -    $new{-from_resultset} = [ keys %new ] if keys %new;
 +    %merged_cond = %{ $self->{attrs}{related_objects} || {} };  # nothing might have been inserted yet
 +    @from_resultset = keys %merged_cond;
    } else {
      $self->throw_exception(
        "Can't abstract implicit construct, condition not a hash"
  
      # precendence must be given to passed values over values inherited from
      # the cond, so the order here is important.
 -    my %implied =  %{$self->_remove_alias($collapsed_cond, $alias)};
 -    while( my($col,$value) = each %implied ){
 -      if(ref($value) eq 'HASH' && keys(%$value) && (keys %$value)[0] eq '='){
 -        $new{$col} = $value->{'='};
 +    my %implied = %{$self->_remove_alias($collapsed_cond, $alias)};
 +    while ( my($col, $value) = each %implied ) {
 +      if (ref($value) eq 'HASH' && keys(%$value) && (keys %$value)[0] eq '=') {
 +        $merged_cond{$col} = $value->{'='};
          next;
        }
 -      $new{$col} = $value if $self->_is_deterministic_value($value);
 +      $merged_cond{$col} = $value if $self->_is_deterministic_value($value);
      }
    }
  
 -  %new = (
 -    %new,
 +  %merged_cond = (
 +    %merged_cond,
      %{ $self->_remove_alias($values, $alias) },
 -    -source_handle => $self->_source_handle,
 -    -result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED
    );
  
 -  return $self->result_class->new(\%new);
 +  return (\%merged_cond, \@from_resultset);
  }
  
  # _is_deterministic_value
@@@ -2597,6 -2447,23 +2482,23 @@@ sub clear_cache 
    shift->set_cache(undef);
  }
  
+ =head2 is_paged
+ =over 4
+ =item Arguments: none
+ =item Return Value: true, if the resultset has been paginated
+ =back
+ =cut
+ sub is_paged {
+   my ($self) = @_;
+   return !!$self->{attrs}{page};
+ }
  =head2 related_resultset
  
  =over 4
@@@ -2744,8 -2611,8 +2646,8 @@@ sub _chain_relationship 
    }];
  
    my $seen = { %{$attrs->{seen_join} || {} } };
-   my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}}) 
-     ? $from->[-1][0]{-join_path} 
+   my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}})
+     ? $from->[-1][0]{-join_path}
      : [];
  
  
@@@ -2953,6 -2820,22 +2855,22 @@@ sub _resolved_attrs 
      }
      else {
        $attrs->{group_by} = [ grep { !ref($_) || (ref($_) ne 'HASH') } @{$attrs->{select}} ];
+       # add any order_by parts that are not already present in the group_by
+       # we need to be careful not to add any named functions/aggregates
+       # i.e. select => [ ... { count => 'foo', -as 'foocount' } ... ]
+       my %already_grouped = map { $_ => 1 } (@{$attrs->{group_by}});
+       my $storage = $self->result_source->schema->storage;
+       my $rs_column_list = $storage->_resolve_column_info ($attrs->{from});
+       my @chunks = $storage->sql_maker->_order_by_chunks ($attrs->{order_by});
+       for my $chunk (map { ref $_ ? @$_ : $_ } (@chunks) ) {
+         $chunk =~ s/\s+ (?: ASC|DESC ) \s* $//ix;
+         if ($rs_column_list->{$chunk} && not $already_grouped{$chunk}++) {
+           push @{$attrs->{group_by}}, $chunk;
+         }
+       }
      }
    }
  
    # even though it doesn't make much sense, this is what pre 081xx has
    # been doing
    if (my $page = delete $attrs->{page}) {
-     $attrs->{offset} = 
+     $attrs->{offset} =
        ($attrs->{rows} * ($page - 1))
              +
        ($attrs->{offset} || 0)
@@@ -3176,7 -3059,7 +3094,7 @@@ These are in no particular order
  
  =back
  
- Which column(s) to order the results by. 
+ Which column(s) to order the results by.
  
  [The full list of suitable values is documented in
  L<SQL::Abstract/"ORDER BY CLAUSES">; the following is a summary of
@@@ -3271,6 -3154,9 +3189,9 @@@ When you use function/stored procedure 
  attribute, the column names returned are storage-dependent. E.g. MySQL would
  return a column named C<count(employeeid)> in the above example.
  
+ B<NOTE:> You will almost always need a corresponding 'as' entry when you use
+ 'select'.
  =head2 +select
  
  =over 4
@@@ -3468,12 -3354,12 +3389,12 @@@ exactly as you might expect
  
  =over 4
  
- =item * 
+ =item *
  
  Prefetch uses the L</cache> to populate the prefetched relationships. This
  may or may not be what you want.
  
- =item * 
+ =item *
  
  If you specify a condition on a prefetched relationship, ONLY those
  rows that match the prefetched condition will be fetched into that relationship.
@@@ -3585,8 -3471,8 +3506,8 @@@ Adds to the WHERE clause
    # only return rows WHERE deleted IS NULL for all searches
    __PACKAGE__->resultset_attributes({ where => { deleted => undef } }); )
  
- Can be overridden by passing C<{ where => undef }> as an attribute
- to a resulset.
+ Can be overridden by passing C<< { where => undef } >> as an attribute
+ to a resultset.
  
  =back