X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI%2FCursor.pm;h=be45ce5a5286b7765214b42e77fb10c0eed7584d;hb=a3a526ccbf65e59361a29b753f4bdd9495ad6dd5;hp=cd1926e3d42b5f75aac386b30a4e3e6728f9a504;hpb=c0e7b4e55952cd193b6f1866d0c27ece182397eb;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI/Cursor.pm b/lib/DBIx/Class/Storage/DBI/Cursor.pm index cd1926e..be45ce5 100644 --- a/lib/DBIx/Class/Storage/DBI/Cursor.pm +++ b/lib/DBIx/Class/Storage/DBI/Cursor.pm @@ -1,70 +1,186 @@ -package # hide from PAUSE - DBIx::Class::Storage::DBI::Cursor; - -use base qw/DBIx::Class::Cursor/; +package DBIx::Class::Storage::DBI::Cursor; use strict; use warnings; +use base qw/ + Class::Accessor::Grouped + DBIx::Class::Cursor +/; + +__PACKAGE__->mk_group_accessors('simple' => + qw/sth/ +); + +=head1 NAME + +DBIx::Class::Storage::DBI::Cursor - Object representing a query cursor on a +resultset. + +=head1 SYNOPSIS + + my $cursor = $schema->resultset('CD')->cursor(); + my $first_cd = $cursor->next; + +=head1 DESCRIPTION + +A Cursor represents a query cursor on a L object. It +allows for traversing the result set with L, retrieving all results with +L and resetting the cursor with L. + +Usually, you would use the cursor methods built into L +to traverse it. See L, +L and L for more +information. + +=head1 METHODS + +=head2 new + +Returns a new L object. + +=cut + sub new { my ($class, $storage, $args, $attrs) = @_; - #use Data::Dumper; warn Dumper(@_); $class = ref $class if ref $class; + my $new = { storage => $storage, args => $args, pos => 0, - attrs => $attrs }; + attrs => $attrs, + _dbh_gen => $storage->{_dbh_gen}, + }; + return bless ($new, $class); } -sub next { - my ($self) = @_; - if ($self->{attrs}{rows} && $self->{pos} >= $self->{attrs}{rows}) { - $self->{sth}->finish if $self->{sth}->{Active}; - delete $self->{sth}; +=head2 next + +=over 4 + +=item Arguments: none + +=item Return Value: \@row_columns + +=back + +Advances the cursor to the next row and returns an array of column +values (the result of L method). + +=cut + +sub _dbh_next { + my ($storage, $dbh, $self) = @_; + + $self->_check_dbh_gen; + if ( + $self->{attrs}{software_limit} + && $self->{attrs}{rows} + && $self->{pos} >= $self->{attrs}{rows} + ) { + $self->sth->finish if $self->sth->{Active}; + $self->sth(undef); $self->{done} = 1; } return if $self->{done}; - unless ($self->{sth}) { - $self->{sth} = ($self->{storage}->_select(@{$self->{args}}))[1]; + unless ($self->sth) { + $self->sth(($storage->_select(@{$self->{args}}))[1]); if ($self->{attrs}{software_limit}) { if (my $offset = $self->{attrs}{offset}) { - $self->{sth}->fetch for 1 .. $offset; + $self->sth->fetch for 1 .. $offset; } } } - my @row = $self->{sth}->fetchrow_array; + my @row = $self->sth->fetchrow_array; if (@row) { $self->{pos}++; } else { - delete $self->{sth}; + $self->sth(undef); $self->{done} = 1; } return @row; } -sub all { +sub next { my ($self) = @_; - return $self->SUPER::all if $self->{attrs}{rows}; - $self->{sth}->finish if $self->{sth}->{Active}; - delete $self->{sth}; - my ($rv, $sth) = $self->{storage}->_select(@{$self->{args}}); + $self->{storage}->dbh_do($self->can('_dbh_next'), $self); +} + +=head2 all + +=over 4 + +=item Arguments: none + +=item Return Value: \@row_columns+ + +=back + +Returns a list of arrayrefs of column values for all rows in the +L. + +=cut + +sub _dbh_all { + my ($storage, $dbh, $self) = @_; + + $self->_check_dbh_gen; + $self->sth->finish if $self->sth->{Active}; + $self->sth(undef); + my ($rv, $sth) = $storage->_select(@{$self->{args}}); return @{$sth->fetchall_arrayref}; } +sub all { + my ($self) = @_; + if ($self->{attrs}{software_limit} + && ($self->{attrs}{offset} || $self->{attrs}{rows})) { + return $self->next::method; + } + + $self->{storage}->dbh_do($self->can('_dbh_all'), $self); +} + +=head2 reset + +Resets the cursor to the beginning of the L. + +=cut + sub reset { my ($self) = @_; - $self->{sth}->finish if $self->{sth}->{Active}; - delete $self->{sth}; - $self->{pos} = 0; + + # No need to care about failures here + eval { $self->sth->finish if $self->sth && $self->sth->{Active} }; + $self->_soft_reset; +} + +sub _soft_reset { + my ($self) = @_; + + $self->sth(undef); delete $self->{done}; + $self->{pos} = 0; return $self; } +sub _check_dbh_gen { + my ($self) = @_; + + if($self->{_dbh_gen} != $self->{storage}->{_dbh_gen}) { + $self->{_dbh_gen} = $self->{storage}->{_dbh_gen}; + $self->_soft_reset; + } +} + sub DESTROY { my ($self) = @_; - $self->{sth}->finish if $self->{sth}->{Active}; + + # None of the reasons this would die matter if we're in DESTROY anyways + local $@; + eval { $self->sth->finish if $self->sth && $self->sth->{Active} }; } 1;