fixed my tests
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Pg.pm
CommitLineData
843f8ecd 1package DBIx::Class::Storage::DBI::Pg;
2
3use strict;
4use warnings;
5
4ce3b851 6use base qw/DBIx::Class::Storage::DBI::MultiColumnIn/;
ac45262b 7use mro 'c3';
843f8ecd 8
ac45262b 9use DBD::Pg qw(:pg_types);
843f8ecd 10
ac45262b 11# Ask for a DBD::Pg with array support
c70c716e 12warn "DBD::Pg 2.9.2 or greater is strongly recommended\n"
ac45262b 13 if ($DBD::Pg::VERSION < 2.009002); # pg uses (used?) version::qv()
17614944 14
e96a93df 15sub with_deferred_fk_checks {
16 my ($self, $sub) = @_;
17
9ae966b9 18 $self->_get_dbh->do('SET CONSTRAINTS ALL DEFERRED');
e96a93df 19 $sub->();
20}
21
843f8ecd 22sub last_insert_id {
ca48cd7d 23 my ($self,$source,$col) = @_;
5f70776f 24 my $seq = ($source->column_info($col)->{sequence} ||= $self->get_autoinc_seq($source,$col))
25 or $self->throw_exception( "could not determine sequence for "
26 . $source->name
27 . ".$col, please consider adding a "
28 . "schema-qualified sequence to its column info"
29 );
9a0b7b26 30
31 $self->_dbh_last_insert_id ($self->_dbh, $seq);
0680ac39 32}
33
9a0b7b26 34# there seems to be absolutely no reason to have this as a separate method,
35# but leaving intact in case someone is already overriding it
36sub _dbh_last_insert_id {
37 my ($self, $dbh, $seq) = @_;
38 $dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
39}
40
41
6ff1d58c 42# get the postgres search path, and cache it
1ff9c30d 43sub _get_pg_search_path {
44 my ($self,$dbh) = @_;
45 # cache the search path as ['schema','schema',...] in the storage
46 # obj
47 $self->{_pg_search_path} ||= do {
48 my @search_path;
49 my ($sp_string) = $dbh->selectrow_array('SHOW search_path');
50 while( $sp_string =~ s/("[^"]+"|[^,]+),?// ) {
51 unless( defined $1 and length $1 ) {
52 $self->throw_exception("search path sanity check failed: '$1'")
53 }
54 push @search_path, $1;
55 }
56 \@search_path
57 };
58}
59
d4f16b21 60sub _dbh_get_autoinc_seq {
c01a6b75 61 my ($self, $dbh, $schema, $table, $col) = @_;
0680ac39 62
c01a6b75 63
5e14a204 64 my @where = ( 'c.relname = ?', 'a.attname = ?' );
65 my @bind = ($table, $col);
66 if( defined $schema && length $schema ) {
67 push @where, 'n.nspname = ?';
68 push @bind, $schema;
69 } else {
70 push @where, 'pg_catalog.pg_table_is_visible(c.oid)';
c01a6b75 71 }
5e14a204 72 my $where = join ' AND ', @where;
73
74 my ($seq_expr) = $dbh->selectrow_array(<<EOS,undef,@bind);
75SELECT
76 (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
77 FROM pg_catalog.pg_attrdef d
78 WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
79FROM pg_catalog.pg_class c
80 JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
81 JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
82WHERE
83 $where
84 AND a.attnum > 0 AND NOT a.attisdropped
85EOS
86
87 $seq_expr =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i
88 or $self->throw_exception("could not parse sequence expression '$seq_expr'");
89
90 return $1;
843f8ecd 91}
92
93sub get_autoinc_seq {
ca48cd7d 94 my ($self,$source,$col) = @_;
d4daee7b 95
80625830 96 my $schema;
97 my $table = $source->name;
98
99 if (ref $table eq 'SCALAR') {
100 $table = $$table;
101 }
102 elsif ($table =~ /^(.+)\.(.+)$/) {
103 ($schema, $table) = ($1, $2);
104 }
a9f32dbc 105
c01a6b75 106 $self->dbh_do('_dbh_get_autoinc_seq', $schema, $table, $col);
843f8ecd 107}
108
4f533e8c 109sub sqlt_type {
110 return 'PostgreSQL';
111}
112
45fa8288 113sub datetime_parser_type { return "DateTime::Format::Pg"; }
114
a71859b4 115sub bind_attribute_by_data_type {
116 my ($self,$data_type) = @_;
117
118 my $bind_attributes = {
eda28767 119 bytea => { pg_type => DBD::Pg::PG_BYTEA },
5ba88f68 120 blob => { pg_type => DBD::Pg::PG_BYTEA },
a71859b4 121 };
d4daee7b 122
a71859b4 123 if( defined $bind_attributes->{$data_type} ) {
9fdf90df 124 return $bind_attributes->{$data_type};
a71859b4 125 }
126 else {
127 return;
128 }
129}
130
f04b2839 131sub _sequence_fetch {
132 my ( $self, $type, $seq ) = @_;
9ae966b9 133 my ($id) = $self->_get_dbh->selectrow_array("SELECT nextval('${seq}')");
f04b2839 134 return $id;
135}
136
adb3554a 137sub _svp_begin {
eeb8cfeb 138 my ($self, $name) = @_;
adb3554a 139
9ae966b9 140 $self->_get_dbh->pg_savepoint($name);
adb3554a 141}
142
143sub _svp_release {
eeb8cfeb 144 my ($self, $name) = @_;
adb3554a 145
9ae966b9 146 $self->_get_dbh->pg_release($name);
adb3554a 147}
148
149sub _svp_rollback {
eeb8cfeb 150 my ($self, $name) = @_;
adb3554a 151
9ae966b9 152 $self->_get_dbh->pg_rollback_to($name);
adb3554a 153}
154
843f8ecd 1551;
156
fd159e2a 157__END__
158
75d07914 159=head1 NAME
843f8ecd 160
161DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
162
163=head1 SYNOPSIS
164
165 # In your table classes
166 __PACKAGE__->load_components(qw/PK::Auto Core/);
167 __PACKAGE__->set_primary_key('id');
168 __PACKAGE__->sequence('mysequence');
169
170=head1 DESCRIPTION
171
172This class implements autoincrements for PostgreSQL.
173
7c0176a1 174=head1 POSTGRESQL SCHEMA SUPPORT
175
176This supports multiple PostgreSQL schemas, with one caveat: for
6ff1d58c 177performance reasons, data about the search path, sequence names, and
178so forth is queried as needed and CACHED for subsequent uses.
7c0176a1 179
180For this reason, you should do any necessary manipulation of the
181PostgreSQL search path BEFORE instantiating your schema object, or as
182part of the on_connect_do option to connect(), for example:
183
184 my $schema = My::Schema->connect
185 ( $dsn,$user,$pass,
186 { on_connect_do =>
187 [ 'SET search_path TO myschema, foo, public' ],
188 },
189 );
190
7ff926e6 191=head1 AUTHORS
7c0176a1 192
7ff926e6 193See L<DBIx::Class/CONTRIBUTORS>
843f8ecd 194
195=head1 LICENSE
196
197You may distribute this code under the same terms as Perl itself.
198
199=cut