oops, forgot to put the drop for the extended tests back in the pg 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
1ff9c30d 42sub _get_pg_search_path {
43 my ($self,$dbh) = @_;
44 # cache the search path as ['schema','schema',...] in the storage
45 # obj
46 $self->{_pg_search_path} ||= do {
47 my @search_path;
48 my ($sp_string) = $dbh->selectrow_array('SHOW search_path');
49 while( $sp_string =~ s/("[^"]+"|[^,]+),?// ) {
50 unless( defined $1 and length $1 ) {
51 $self->throw_exception("search path sanity check failed: '$1'")
52 }
53 push @search_path, $1;
54 }
55 \@search_path
56 };
57}
58
d4f16b21 59sub _dbh_get_autoinc_seq {
c01a6b75 60 my ($self, $dbh, $schema, $table, $col) = @_;
0680ac39 61
c01a6b75 62
5e14a204 63 my @where = ( 'c.relname = ?', 'a.attname = ?' );
64 my @bind = ($table, $col);
65 if( defined $schema && length $schema ) {
66 push @where, 'n.nspname = ?';
67 push @bind, $schema;
68 } else {
69 push @where, 'pg_catalog.pg_table_is_visible(c.oid)';
c01a6b75 70 }
5e14a204 71 my $where = join ' AND ', @where;
72
73 my ($seq_expr) = $dbh->selectrow_array(<<EOS,undef,@bind);
74SELECT
75 (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
76 FROM pg_catalog.pg_attrdef d
77 WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
78FROM pg_catalog.pg_class c
79 JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
80 JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
81WHERE
82 $where
83 AND a.attnum > 0 AND NOT a.attisdropped
84EOS
85
86 $seq_expr =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i
87 or $self->throw_exception("could not parse sequence expression '$seq_expr'");
88
89 return $1;
843f8ecd 90}
91
92sub get_autoinc_seq {
ca48cd7d 93 my ($self,$source,$col) = @_;
d4daee7b 94
80625830 95 my $schema;
96 my $table = $source->name;
97
98 if (ref $table eq 'SCALAR') {
99 $table = $$table;
100 }
101 elsif ($table =~ /^(.+)\.(.+)$/) {
102 ($schema, $table) = ($1, $2);
103 }
a9f32dbc 104
c01a6b75 105 $self->dbh_do('_dbh_get_autoinc_seq', $schema, $table, $col);
843f8ecd 106}
107
4f533e8c 108sub sqlt_type {
109 return 'PostgreSQL';
110}
111
45fa8288 112sub datetime_parser_type { return "DateTime::Format::Pg"; }
113
a71859b4 114sub bind_attribute_by_data_type {
115 my ($self,$data_type) = @_;
116
117 my $bind_attributes = {
eda28767 118 bytea => { pg_type => DBD::Pg::PG_BYTEA },
5ba88f68 119 blob => { pg_type => DBD::Pg::PG_BYTEA },
a71859b4 120 };
d4daee7b 121
a71859b4 122 if( defined $bind_attributes->{$data_type} ) {
9fdf90df 123 return $bind_attributes->{$data_type};
a71859b4 124 }
125 else {
126 return;
127 }
128}
129
f04b2839 130sub _sequence_fetch {
131 my ( $self, $type, $seq ) = @_;
9ae966b9 132 my ($id) = $self->_get_dbh->selectrow_array("SELECT nextval('${seq}')");
f04b2839 133 return $id;
134}
135
adb3554a 136sub _svp_begin {
eeb8cfeb 137 my ($self, $name) = @_;
adb3554a 138
9ae966b9 139 $self->_get_dbh->pg_savepoint($name);
adb3554a 140}
141
142sub _svp_release {
eeb8cfeb 143 my ($self, $name) = @_;
adb3554a 144
9ae966b9 145 $self->_get_dbh->pg_release($name);
adb3554a 146}
147
148sub _svp_rollback {
eeb8cfeb 149 my ($self, $name) = @_;
adb3554a 150
9ae966b9 151 $self->_get_dbh->pg_rollback_to($name);
adb3554a 152}
153
843f8ecd 1541;
155
fd159e2a 156__END__
157
75d07914 158=head1 NAME
843f8ecd 159
160DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
161
162=head1 SYNOPSIS
163
164 # In your table classes
165 __PACKAGE__->load_components(qw/PK::Auto Core/);
166 __PACKAGE__->set_primary_key('id');
167 __PACKAGE__->sequence('mysequence');
168
169=head1 DESCRIPTION
170
171This class implements autoincrements for PostgreSQL.
172
7c0176a1 173=head1 POSTGRESQL SCHEMA SUPPORT
174
175This supports multiple PostgreSQL schemas, with one caveat: for
176performance reasons, the schema search path is queried the first time it is
177needed and CACHED for subsequent uses.
178
179For this reason, you should do any necessary manipulation of the
180PostgreSQL search path BEFORE instantiating your schema object, or as
181part of the on_connect_do option to connect(), for example:
182
183 my $schema = My::Schema->connect
184 ( $dsn,$user,$pass,
185 { on_connect_do =>
186 [ 'SET search_path TO myschema, foo, public' ],
187 },
188 );
189
7ff926e6 190=head1 AUTHORS
7c0176a1 191
7ff926e6 192See L<DBIx::Class/CONTRIBUTORS>
843f8ecd 193
194=head1 LICENSE
195
196You may distribute this code under the same terms as Perl itself.
197
198=cut