$sth->{Active} may throw during destruction >.<
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Cursor.pm
CommitLineData
5cf243f6 1package DBIx::Class::Storage::DBI::Cursor;
28927b50 2
28927b50 3use strict;
4use warnings;
5
48a76fcf 6use base qw/DBIx::Class::Cursor/;
a3a526cc 7
9780718f 8use Try::Tiny;
fd323bf1 9use namespace::clean;
9780718f 10
a3a526cc 11__PACKAGE__->mk_group_accessors('simple' =>
12 qw/sth/
13);
2ad62d97 14
5cf243f6 15=head1 NAME
16
17DBIx::Class::Storage::DBI::Cursor - Object representing a query cursor on a
18resultset.
19
20=head1 SYNOPSIS
21
22 my $cursor = $schema->resultset('CD')->cursor();
23 my $first_cd = $cursor->next;
24
25=head1 DESCRIPTION
26
27A Cursor represents a query cursor on a L<DBIx::Class::ResultSet> object. It
28allows for traversing the result set with L</next>, retrieving all results with
29L</all> and resetting the cursor with L</reset>.
30
31Usually, you would use the cursor methods built into L<DBIx::Class::ResultSet>
32to traverse it. See L<DBIx::Class::ResultSet/next>,
33L<DBIx::Class::ResultSet/reset> and L<DBIx::Class::ResultSet/all> for more
34information.
35
36=head1 METHODS
37
38=head2 new
39
5cf243f6 40Returns a new L<DBIx::Class::Storage::DBI::Cursor> object.
41
42=cut
43
28927b50 44sub new {
cb5f2eea 45 my ($class, $storage, $args, $attrs) = @_;
cb5f2eea 46 $class = ref $class if ref $class;
2007929b 47
28927b50 48 my $new = {
cb5f2eea 49 storage => $storage,
28927b50 50 args => $args,
51 pos => 0,
1346e22d 52 attrs => $attrs,
dbaee748 53 _dbh_gen => $storage->{_dbh_gen},
1346e22d 54 };
55
cb5f2eea 56 return bless ($new, $class);
28927b50 57}
58
5cf243f6 59=head2 next
60
21b5c39d 61=over 4
62
ebc77b53 63=item Arguments: none
21b5c39d 64
d601dc88 65=item Return Value: \@row_columns
21b5c39d 66
5cf243f6 67=back
68
685dad64 69Advances the cursor to the next row and returns an array of column
70values (the result of L<DBI/fetchrow_array> method).
5cf243f6 71
72=cut
73
dbaee748 74sub _dbh_next {
75 my ($storage, $dbh, $self) = @_;
1346e22d 76
dbaee748 77 $self->_check_dbh_gen;
22ed9526 78 if (
79 $self->{attrs}{software_limit}
80 && $self->{attrs}{rows}
81 && $self->{pos} >= $self->{attrs}{rows}
82 ) {
a3a526cc 83 $self->sth->finish if $self->sth->{Active};
84 $self->sth(undef);
cb5f2eea 85 $self->{done} = 1;
86 }
87 return if $self->{done};
a3a526cc 88 unless ($self->sth) {
89 $self->sth(($storage->_select(@{$self->{args}}))[1]);
5c91499f 90 if ($self->{attrs}{software_limit}) {
91 if (my $offset = $self->{attrs}{offset}) {
a3a526cc 92 $self->sth->fetch for 1 .. $offset;
5c91499f 93 }
94 }
28927b50 95 }
a3a526cc 96 my @row = $self->sth->fetchrow_array;
cb5f2eea 97 if (@row) {
98 $self->{pos}++;
99 } else {
a3a526cc 100 $self->sth(undef);
cb5f2eea 101 $self->{done} = 1;
102 }
28927b50 103 return @row;
104}
105
dbaee748 106sub next {
107 my ($self) = @_;
108 $self->{storage}->dbh_do($self->can('_dbh_next'), $self);
109}
110
5cf243f6 111=head2 all
112
21b5c39d 113=over 4
114
ebc77b53 115=item Arguments: none
21b5c39d 116
d601dc88 117=item Return Value: \@row_columns+
21b5c39d 118
5cf243f6 119=back
120
21b5c39d 121Returns a list of arrayrefs of column values for all rows in the
122L<DBIx::Class::ResultSet>.
5cf243f6 123
124=cut
125
dbaee748 126sub _dbh_all {
127 my ($storage, $dbh, $self) = @_;
1346e22d 128
dbaee748 129 $self->_check_dbh_gen;
b4ad6d39 130 $self->sth->finish if $self->sth && $self->sth->{Active};
a3a526cc 131 $self->sth(undef);
dbaee748 132 my ($rv, $sth) = $storage->_select(@{$self->{args}});
1a14aa3f 133 return @{$sth->fetchall_arrayref};
134}
135
dbaee748 136sub all {
137 my ($self) = @_;
6296f45b 138 if ($self->{attrs}{software_limit}
139 && ($self->{attrs}{offset} || $self->{attrs}{rows})) {
c3515436 140 return $self->next::method;
6296f45b 141 }
22ed9526 142
dbaee748 143 $self->{storage}->dbh_do($self->can('_dbh_all'), $self);
144}
145
5cf243f6 146=head2 reset
147
5cf243f6 148Resets the cursor to the beginning of the L<DBIx::Class::ResultSet>.
149
150=cut
151
28927b50 152sub reset {
153 my ($self) = @_;
1346e22d 154
dbaee748 155 # No need to care about failures here
52b420dd 156 try { $self->sth->finish }
157 if $self->sth && $self->sth->{Active};
1346e22d 158 $self->_soft_reset;
b7c79955 159 return undef;
1346e22d 160}
161
162sub _soft_reset {
163 my ($self) = @_;
164
a3a526cc 165 $self->sth(undef);
cb5f2eea 166 delete $self->{done};
dbaee748 167 $self->{pos} = 0;
28927b50 168}
169
dbaee748 170sub _check_dbh_gen {
1346e22d 171 my ($self) = @_;
172
dbaee748 173 if($self->{_dbh_gen} != $self->{storage}->{_dbh_gen}) {
174 $self->{_dbh_gen} = $self->{storage}->{_dbh_gen};
175 $self->_soft_reset;
1346e22d 176 }
177}
178
28927b50 179sub DESTROY {
dbaee748 180 # None of the reasons this would die matter if we're in DESTROY anyways
05b22e33 181 if (my $sth = $_[0]->sth) {
380b6ea1 182 try { $sth->finish } if $sth->FETCH('Active');
05b22e33 183 }
28927b50 184}
185
1861;