added more tests for multi-schema support in 72pg.t
[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
d4f16b21 22sub _dbh_last_insert_id {
23 my ($self, $dbh, $seq) = @_;
24 $dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
0680ac39 25}
26
843f8ecd 27sub last_insert_id {
ca48cd7d 28 my ($self,$source,$col) = @_;
29 my $seq = ($source->column_info($col)->{sequence} ||= $self->get_autoinc_seq($source,$col));
d12926f6 30 $self->throw_exception("could not fetch primary key for " . $source->name . ", could not "
31 . "get autoinc sequence for $col (check that table and column specifications are correct "
32 . "and in the correct case)") unless defined $seq;
373940e1 33 $self->dbh_do('_dbh_last_insert_id', $seq);
0680ac39 34}
35
1ff9c30d 36sub _get_pg_search_path {
37 my ($self,$dbh) = @_;
38 # cache the search path as ['schema','schema',...] in the storage
39 # obj
40 $self->{_pg_search_path} ||= do {
41 my @search_path;
42 my ($sp_string) = $dbh->selectrow_array('SHOW search_path');
43 while( $sp_string =~ s/("[^"]+"|[^,]+),?// ) {
44 unless( defined $1 and length $1 ) {
45 $self->throw_exception("search path sanity check failed: '$1'")
46 }
47 push @search_path, $1;
48 }
49 \@search_path
50 };
51}
52
d4f16b21 53sub _dbh_get_autoinc_seq {
54 my ($self, $dbh, $schema, $table, @pri) = @_;
0680ac39 55
7dfe289b 56 # get the list of postgres schemas to search. if we have a schema
57 # specified, use that. otherwise, use the search path
58 my @search_path;
59 if( defined $schema and length $schema ) {
60 @search_path = ( $schema );
61 } else {
1ff9c30d 62 @search_path = @{ $self->_get_pg_search_path($dbh) };
7dfe289b 63 }
64
65 foreach my $search_schema (@search_path) {
66 foreach my $col (@pri) {
67 my $info = $dbh->column_info(undef,$search_schema,$table,$col)->fetchrow_hashref;
68 if($info) {
69 # if we get here, we have definitely found the right
70 # column.
71 if( defined $info->{COLUMN_DEF} and
72 $info->{COLUMN_DEF}
73 =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i
74 ) {
75 my $seq = $1;
76 return $seq =~ /\./ ? $seq : $info->{TABLE_SCHEM} . "." . $seq;
77 } else {
78 # we have found the column, but cannot figure out
79 # the nextval seq
80 return;
81 }
82 }
83 }
0680ac39 84 }
85 return;
843f8ecd 86}
87
88sub get_autoinc_seq {
ca48cd7d 89 my ($self,$source,$col) = @_;
d4daee7b 90
843f8ecd 91 my @pri = $source->primary_columns;
80625830 92
93 my $schema;
94 my $table = $source->name;
95
96 if (ref $table eq 'SCALAR') {
97 $table = $$table;
98 }
99 elsif ($table =~ /^(.+)\.(.+)$/) {
100 ($schema, $table) = ($1, $2);
101 }
a9f32dbc 102
373940e1 103 $self->dbh_do('_dbh_get_autoinc_seq', $schema, $table, @pri);
843f8ecd 104}
105
4f533e8c 106sub sqlt_type {
107 return 'PostgreSQL';
108}
109
45fa8288 110sub datetime_parser_type { return "DateTime::Format::Pg"; }
111
a71859b4 112sub bind_attribute_by_data_type {
113 my ($self,$data_type) = @_;
114
115 my $bind_attributes = {
eda28767 116 bytea => { pg_type => DBD::Pg::PG_BYTEA },
5ba88f68 117 blob => { pg_type => DBD::Pg::PG_BYTEA },
a71859b4 118 };
d4daee7b 119
a71859b4 120 if( defined $bind_attributes->{$data_type} ) {
9fdf90df 121 return $bind_attributes->{$data_type};
a71859b4 122 }
123 else {
124 return;
125 }
126}
127
f04b2839 128sub _sequence_fetch {
129 my ( $self, $type, $seq ) = @_;
9ae966b9 130 my ($id) = $self->_get_dbh->selectrow_array("SELECT nextval('${seq}')");
f04b2839 131 return $id;
132}
133
adb3554a 134sub _svp_begin {
eeb8cfeb 135 my ($self, $name) = @_;
adb3554a 136
9ae966b9 137 $self->_get_dbh->pg_savepoint($name);
adb3554a 138}
139
140sub _svp_release {
eeb8cfeb 141 my ($self, $name) = @_;
adb3554a 142
9ae966b9 143 $self->_get_dbh->pg_release($name);
adb3554a 144}
145
146sub _svp_rollback {
eeb8cfeb 147 my ($self, $name) = @_;
adb3554a 148
9ae966b9 149 $self->_get_dbh->pg_rollback_to($name);
adb3554a 150}
151
843f8ecd 1521;
153
75d07914 154=head1 NAME
843f8ecd 155
156DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
157
158=head1 SYNOPSIS
159
160 # In your table classes
161 __PACKAGE__->load_components(qw/PK::Auto Core/);
162 __PACKAGE__->set_primary_key('id');
163 __PACKAGE__->sequence('mysequence');
164
165=head1 DESCRIPTION
166
167This class implements autoincrements for PostgreSQL.
168
7c0176a1 169=head1 POSTGRESQL SCHEMA SUPPORT
170
171This supports multiple PostgreSQL schemas, with one caveat: for
172performance reasons, the schema search path is queried the first time it is
173needed and CACHED for subsequent uses.
174
175For this reason, you should do any necessary manipulation of the
176PostgreSQL search path BEFORE instantiating your schema object, or as
177part of the on_connect_do option to connect(), for example:
178
179 my $schema = My::Schema->connect
180 ( $dsn,$user,$pass,
181 { on_connect_do =>
182 [ 'SET search_path TO myschema, foo, public' ],
183 },
184 );
185
186=head1 CONTRIBUTORS
187
188Robert Buels <rbuels@cpan.org>
189
190=head1 AUTHOR
843f8ecd 191
192Marcus Ramberg <m.ramberg@cpan.org>
193
194=head1 LICENSE
195
196You may distribute this code under the same terms as Perl itself.
197
198=cut