X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=282651f0cd1e5e8218d4d0c303a5bd404a78f52a;hb=194311161bdbebd2402c457ded300fc83b773f02;hp=13e11744ffd256e0d5f95847ac1c233dbf810e18;hpb=639cf8f9d212c3e950ae5bae680133762c1df0aa;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 13e1174..282651f 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -46,27 +46,13 @@ A new ResultSet is returned from calling L on an existing ResultSet. The new one will contain all the conditions of the original, plus any new conditions added in the C call. -A ResultSet is also an iterator. L is used to return all the -Ls the ResultSet represents. +A ResultSet also incorporates an implicit iterator. L and L +can be used to walk through all the Ls the ResultSet +represents. The query that the ResultSet represents is B executed against the database when these methods are called: - -=over - -=item L - -=item L - -=item L - -=item L - -=item L - -=item L - -=back +L L L L L L =head1 EXAMPLES @@ -674,7 +660,9 @@ L for more information. sub cursor { my ($self) = @_; - my $attrs = { %{$self->_resolved_attrs} }; + my $attrs = $self->_resolved_attrs_copy; + $attrs->{_virtual_order_by} = $self->_gen_virtual_order; + return $self->{cursor} ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select}, $attrs->{where},$attrs); @@ -725,7 +713,9 @@ sub single { $self->throw_exception('single() only takes search conditions, no attributes. You want ->search( $cond, $attrs )->single()'); } - my $attrs = { %{$self->_resolved_attrs} }; + my $attrs = $self->_resolved_attrs_copy; + $attrs->{_virtual_order_by} = $self->_gen_virtual_order; + if ($where) { if (defined $attrs->{where}) { $attrs->{where} = { @@ -752,6 +742,16 @@ sub single { return (@data ? ($self->_construct_object(@data))[0] : undef); } +# _gen_virtual_order +# +# This is a horrble hack, but seems like the best we can do at this point +# Some limit emulations (Top) require an ordered resultset in order to +# function at all. So supply a PK order to be used if necessary + +sub _gen_virtual_order { + return [ shift->result_source->primary_columns ]; +} + # _is_unique_query # # Try to determine if the specified query is guaranteed to be unique, based on @@ -870,10 +870,10 @@ instead. An example conversion is: sub search_like { my $class = shift; - carp join ("\n", - 'search_like() is deprecated and will be removed in 0.09.', - 'Instead use ->search({ x => { -like => "y%" } })', - '(note the outer pair of {}s - they are important!)' + carp ( + 'search_like() is deprecated and will be removed in DBIC version 0.09.' + .' Instead use ->search({ x => { -like => "y%" } })' + .' (note the outer pair of {}s - they are important!)' ); my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {}); my $query = ref $_[0] eq 'HASH' ? { %{shift()} }: {@_}; @@ -1145,8 +1145,8 @@ sub result_class { =back Performs an SQL C with the same query as the resultset was built -with to find the number of elements. If passed arguments, does a search -on the resultset and counts the results of that. +with to find the number of elements. Passing arguments is equivalent to +C<< $rs->search ($cond, \%attrs)->count >> =cut @@ -1155,39 +1155,53 @@ sub count { return $self->search(@_)->count if @_ and defined $_[0]; return scalar @{ $self->get_cache } if $self->get_cache; - my @subq_attrs = qw/prefetch collapse distinct group_by having having_bind/; + my @grouped_subq_attrs = qw/prefetch collapse distinct group_by having/; + my @subq_attrs = (); + my $attrs = $self->_resolved_attrs; - # if we are not paged - we are simply asking for a limit if (not $attrs->{page} and not $attrs->{software_limit}) { push @subq_attrs, qw/rows offset/; } - return $self->_has_attr (@subq_attrs) - ? $self->_count_subq + my $need_subq = $self->_has_attr (@subq_attrs); + my $need_group_subq = $self->_has_attr (@grouped_subq_attrs); + + return ($need_subq || $need_group_subq) + ? $self->_count_subq ($need_group_subq) : $self->_count_simple } sub _count_subq { - my $self = shift; + my ($self, $add_group_by) = @_; - my $attrs = { %{$self->_resolved_attrs} }; + my $attrs = $self->_resolved_attrs_copy; # copy for the subquery, we need to do some adjustments to it too my $sub_attrs = { %$attrs }; - # these can not go in the subquery either - delete $sub_attrs->{$_} for qw/prefetch select +select as +as columns +columns/; + # these can not go in the subquery, and there is no point of ordering it + delete $sub_attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns order_by/; - # force a group_by and the same set of columns (most databases require this) - $sub_attrs->{columns} = $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ]; + # if needed force a group_by and the same set of columns (most databases require this) + if ($add_group_by) { + + # if we prefetch, we group_by primary keys only as this is what we would get out of the rs via ->next/->all + # simply deleting group_by suffices, as the code below will re-fill it + # Note: we check $attrs, as $sub_attrs has collapse deleted + if (ref $attrs->{collapse} and keys %{$attrs->{collapse}} ) { + delete $sub_attrs->{group_by}; + } + + $sub_attrs->{columns} = $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ]; + } $attrs->{from} = [{ count_subq => (ref $self)->new ($self->result_source, $sub_attrs )->as_query }]; # the subquery replaces this - delete $attrs->{$_} for qw/where bind prefetch collapse group_by having/; + delete $attrs->{$_} for qw/where bind prefetch collapse distinct group_by having having_bind/; return $self->__count ($attrs); } @@ -1200,9 +1214,10 @@ sub _count_simple { # need to take offset from resolved attrs - $count -= $self->{_attrs}{offset} if $self->{_attrs}{offset}; - $count = $self->{attrs}{rows} if - $self->{attrs}{rows} and $self->{attrs}{rows} < $count; + my $attrs = $self->_resolved_attrs; + + $count -= $attrs->{offset} if $attrs->{offset}; + $count = $attrs->{rows} if $attrs->{rows} and $attrs->{rows} < $count; $count = 0 if ($count < 0); return $count; } @@ -1210,7 +1225,7 @@ sub _count_simple { sub __count { my ($self, $attrs) = @_; - $attrs ||= { %{$self->_resolved_attrs} }; + $attrs ||= $self->_resolved_attrs_copy; # take off any column specs, any pagers, record_filter is cdbi, and no point of ordering a count delete $attrs->{$_} for (qw/columns +columns select +select as +as rows offset page pager order_by record_filter/); @@ -1351,9 +1366,9 @@ sub _rs_update_delete { if ($needs_group_by_subq or $needs_subq) { # make a new $rs selecting only the PKs (that's all we really need) - my $attrs = $self->_resolved_attrs; + my $attrs = $self->_resolved_attrs_copy; - delete $attrs->{$_} for qw/prefetch select +select as +as columns +columns/; + delete $attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns/; $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ]; if ($needs_group_by_subq) { @@ -1512,7 +1527,7 @@ sub update_all { =item Arguments: none -=item Return Value: 1 +=item Return Value: $storage_rv =back @@ -1520,11 +1535,8 @@ Deletes the contents of the resultset from its result source. Note that this will not run DBIC cascade triggers. See L if you need triggers to run. See also L. -delete may not generate correct SQL for a query with joins or a resultset -chained from a related resultset. In this case it will generate a warning:- - -In these cases you may find that delete_all is more appropriate, or you -need to respecify your query in a way that can be expressed without a join. +Return value will be the amount of rows deleted; exact type of return value +is storage-dependent. =cut @@ -2509,6 +2521,12 @@ sub _resolve_from { return ($from,$seen); } +# too many times we have to do $attrs = { %{$self->_resolved_attrs} } +sub _resolved_attrs_copy { + my $self = shift; + return { %{$self->_resolved_attrs (@_)} }; +} + sub _resolved_attrs { my $self = shift; return $self->{_attrs} if $self->{_attrs}; @@ -2609,8 +2627,6 @@ sub _resolved_attrs { } - $attrs->{group_by} ||= $attrs->{select} - if delete $attrs->{distinct}; if ( $attrs->{order_by} ) { $attrs->{order_by} = ( ref( $attrs->{order_by} ) eq 'ARRAY' @@ -2637,6 +2653,11 @@ sub _resolved_attrs { } push( @{ $attrs->{order_by} }, @pre_order ); } + + if (delete $attrs->{distinct}) { + $attrs->{group_by} ||= [ grep { !ref($_) || (ref($_) ne 'HASH') } @{$attrs->{select}} ]; + } + $attrs->{collapse} = $collapse; if ( $attrs->{page} and not defined $attrs->{offset} ) {