4 use vars qw($DEBUG $buffer);
5 use FS::Record qw(dbh);
6 use Scalar::Util qw(refaddr);
10 # this might become a parameter at some point, but right now, you can
11 # "local $FS::Cursor::buffer = X;"
16 FS::Cursor - Iterator for querying large data sets
22 my $search = FS::Cursor->new('table', { field => 'value' ... });
23 while ( my $row = $search->fetch ) {
33 Constructs a cursored search. Accepts all the same arguments as qsearch,
34 and returns an FS::Cursor object to fetch the rows one at a time.
40 my $q = FS::Record::_query(@_); # builds the statement and parameter list
44 class => 'FS::' . ($q->{table} || 'Record'),
49 # the class of record object to return
50 $self->{class} = "FS::".($q->{table} || 'Record');
52 # save for later, so forked children will not destroy me when they exit
55 $self->{id} = sprintf('cursor%08x', refaddr($self));
56 my $statement = "DECLARE ".$self->{id}." CURSOR FOR ".$q->{statement};
58 my $sth = dbh->prepare($statement)
61 foreach my $value ( @{ $q->{value} } ) {
62 my $bind_type = shift @{ $q->{bind_type} };
63 $sth->bind_param($bind++, $value, $bind_type );
66 $sth->execute or die $sth->errstr;
68 $self->{fetch} = dbh->prepare("FETCH FORWARD $buffer FROM ".$self->{id});
81 Fetch the next row from the search results.
86 # might be a little more efficient to do a FETCH NEXT 1000 or something
87 # and buffer them locally, but the semantics are simpler this way
89 if (@{ $self->{buffer} } == 0) {
90 my $rows = $self->refill;
91 return undef if !$rows;
93 $self->{class}->new(shift @{ $self->{buffer} });
98 my $sth = $self->{fetch};
99 $sth->execute or die $sth->errstr;
100 my $result = $self->{fetch}->fetchall_arrayref( {} );
101 $self->{buffer} = $result;
107 return unless $self->{pid} eq $$;
108 dbh->do('CLOSE '. $self->{id}) or die dbh->errstr; # clean-up the cursor in Pg
115 Replace all uses of qsearch with this.
119 Doesn't support MySQL.
121 The cursor will close prematurely if any code issues a rollback/commit. If
122 you need protection against this use qsearch or fork and get a new dbh
124 Normally this issue will represent itself this message.
125 ERROR: cursor "cursorXXXXXXX" does not exist.