__PACKAGE__->mk_group_accessors('simple' =>
'_pg_cursor_number');
+# these are package-vars to allow for evil global overrides
our $DEFAULT_USE_PG_CURSORS=0;
our $DEFAULT_PG_CURSORS_PAGE_SIZE=1000;
sub _populate_dbh {
my ($self) = @_;
+ # cursors are per-connection, so reset the numbering
$self->_pg_cursor_number(1);
return $self->SUPER::_populate_dbh();
}
my $self = shift;
my ($ident, $select, $where, $attrs) = @_;
+ # ugly ugly ugly, but this is the last sub in the call chain that receives $attrs
local $self->{_use_pg_cursors}=$self->_should_use_pg_cursors($attrs);
local $self->{_pg_cursor_page_size}=$self->_get_pg_cursor_page_size($attrs);
=head1 NAME
-DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
+DBIx::Class::Storage::DBI::Pg - PostgreSQL-specific storage
=head1 SYNOPSIS
+Automatic primary key support:
+
# In your result (table) classes
use base 'DBIx::Class::Core';
__PACKAGE__->set_primary_key('id');
+Using PostgreSQL cursors on fetches:
+
+ my $schema = MySchemaClass->connection(
+ $dsn, $user, $pass,
+ {
+ use_pg_cursors => 1,
+ pg_cursors_page_size => 1000,
+ });
+
+ # override at ResultSet level
+ my $rs = $schema->resultset('Something')
+ ->search({}, { use_pg_cursors => 0});
+
=head1 DESCRIPTION
This class implements autoincrements for PostgreSQL.
+It also implements fetching data via PostgreSQL cursors, as explained
+in the documentation for L<DBD::Pg>.
+
+=head1 CURSORS FETCHING SUPPORT
+
+By default, PostgreSQL cursors are not used. You can turn them on (or
+off again) either via the connection attributes, or via the ResultSet
+attributes (the latter take precedence).
+
+Fetching data using PostgreSQL cursors uses less memory, but is
+slightly slower. You can tune the memory / speed trade-off using the
+C<pg_cursors_page_size> attribute, which defines how many rows to
+fetch at a time (defaults to 1000).
+
=head1 POSTGRESQL SCHEMA SUPPORT
This driver supports multiple PostgreSQL schemas, with one caveat: for
__PACKAGE__->mk_group_accessors('simple' =>
'storage',
- 'cursor_id', 'cursor_created',
+ 'cursor_id', 'cursor_sql',
+ 'cursor_created',
'cursor_sth', 'fetch_sth',
'page_size',
);
$storage->_get_next_pg_cursor_number()
);
my $hold= ($sql =~ /\bFOR\s+UPDATE\s*\z/i) ? '' : 'WITH HOLD';
- $sql="DECLARE $csr_id CURSOR $hold FOR $sql";
+ $self->cursor_sql("DECLARE $csr_id CURSOR $hold FOR $sql");
$self->cursor_id($csr_id);
- $self->cursor_sth($storage->_dbh_sth($dbh,$sql));
+ $self->cursor_sth(undef);
$self->cursor_created(0);
$self->page_size($page_size);
return $self;
}
else {
- die "Can only be used for SELECTS";
+ die "Can only be used for SELECTs";
}
}
return 'dbic_pg_cursor_'.$_[1];
}
+sub _prepare_cursor_sth {
+ my ($self)=@_;
+
+ return if $self->cursor_sth;
+
+ $self->cursor_sth($self->storage->sth($self->cursor_sql));
+}
+
sub _cleanup_sth {
my ($self)=@_;
sub bind_param {
my ($self,@bind_args)=@_;
+ $self->_prepare_cursor_sth;
+
return $self->cursor_sth->bind_param(@bind_args);
}
sub execute {
my ($self,@bind_values)=@_;
- $self->cursor_created(1);
- return $self->cursor_sth->execute(@bind_values);
+ $self->_prepare_cursor_sth;
+
+ my $ret=$self->cursor_sth->execute(@bind_values);
+ $self->cursor_created(1) if $ret;
+ return $ret;
}
# bind_param_array & execute_array not used for SELECT statements, so
$self->fetch_sth->finish if $self->fetch_sth;
return $self->cursor_sth->finish if $self->cursor_sth;
- return 0;
+ return 1;
}
sub _check_cursor_end {
my ($self)=@_;
if (!$self->cursor_created) {
- $self->cursor_sth->execute();
+ $self->execute();
}
$self->fetch_sth->finish if $self->fetch_sth;