Check DBD::Pg >= 2.17.2 with Pg >= 9.0 for BYTEA
[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
be860760 6use base qw/
7 DBIx::Class::Storage::DBI::MultiColumnIn
be860760 8/;
ac45262b 9use mro 'c3';
843f8ecd 10
4d4dc518 11use Scope::Guard ();
6298a324 12use Context::Preserve 'preserve_context';
ee53ca0f 13use DBIx::Class::Carp;
9aec3ec6 14use Try::Tiny;
6298a324 15use namespace::clean;
843f8ecd 16
6a247f33 17__PACKAGE__->sql_limit_dialect ('LimitOffset');
2b8cc2f2 18__PACKAGE__->sql_quote_char ('"');
6f7a118e 19__PACKAGE__->datetime_parser_type ('DateTime::Format::Pg');
6a247f33 20
bbdda281 21sub _determine_supports_insert_returning {
22 return shift->_server_info->{normalized_dbms_version} >= 8.002
23 ? 1
24 : 0
25 ;
38d5ea9f 26}
27
e96a93df 28sub with_deferred_fk_checks {
29 my ($self, $sub) = @_;
30
4d4dc518 31 my $txn_scope_guard = $self->txn_scope_guard;
32
33 $self->_do_query('SET CONSTRAINTS ALL DEFERRED');
38d5ea9f 34
4d4dc518 35 my $sg = Scope::Guard->new(sub {
36 $self->_do_query('SET CONSTRAINTS ALL IMMEDIATE');
37 });
38
6298a324 39 return preserve_context { $sub->() } after => sub { $txn_scope_guard->commit };
e96a93df 40}
41
bab40dee 42# only used when INSERT ... RETURNING is disabled
38d5ea9f 43sub last_insert_id {
44 my ($self,$source,@cols) = @_;
45
46 my @values;
47
52416317 48 my $col_info = $source->columns_info(\@cols);
49
38d5ea9f 50 for my $col (@cols) {
52416317 51 my $seq = ( $col_info->{$col}{sequence} ||= $self->dbh_do('_dbh_get_autoinc_seq', $source, $col) )
38d5ea9f 52 or $self->throw_exception( sprintf(
53 'could not determine sequence for column %s.%s, please consider adding a schema-qualified sequence to its column info',
54 $source->name,
55 $col,
56 ));
57
58 push @values, $self->_dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
59 }
60
61 return @values;
62}
63
4d4dc518 64sub _sequence_fetch {
65 my ($self, $function, $sequence) = @_;
66
67 $self->throw_exception('No sequence to fetch') unless $sequence;
38d5ea9f 68
4d4dc518 69 my ($val) = $self->_get_dbh->selectrow_array(
07cda1c5 70 sprintf ("select %s('%s')", $function, (ref $sequence eq 'SCALAR') ? $$sequence : $sequence)
4d4dc518 71 );
72
73 return $val;
38d5ea9f 74}
9a0b7b26 75
2d424996 76sub _dbh_get_autoinc_seq {
77 my ($self, $dbh, $source, $col) = @_;
0063119f 78
2d424996 79 my $schema;
80 my $table = $source->name;
0063119f 81
2d424996 82 # deref table name if it needs it
83 $table = $$table
84 if ref $table eq 'SCALAR';
0063119f 85
2d424996 86 # parse out schema name if present
87 if( $table =~ /^(.+)\.(.+)$/ ) {
88 ( $schema, $table ) = ( $1, $2 );
89 }
0680ac39 90
2d424996 91 # get the column default using a Postgres-specific pg_catalog query
92 my $seq_expr = $self->_dbh_get_column_default( $dbh, $schema, $table, $col );
93
94 # if no default value is set on the column, or if we can't parse the
95 # default value as a sequence, throw.
5861223d 96 unless ( defined $seq_expr and $seq_expr =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i ) {
2d424996 97 $seq_expr = '' unless defined $seq_expr;
98 $schema = "$schema." if defined $schema && length $schema;
d3fdc7b8 99 $self->throw_exception( sprintf (
100 'no sequence found for %s%s.%s, check the RDBMS table definition or explicitly set the '.
101 "'sequence' for this column in %s",
102 $schema ? "$schema." : '',
103 $table,
104 $col,
105 $source->source_name,
106 ));
777f7527 107 }
2d424996 108
109 return $1;
777f7527 110}
111
2d424996 112# custom method for fetching column default, since column_info has a
113# bug with older versions of DBD::Pg
114sub _dbh_get_column_default {
115 my ( $self, $dbh, $schema, $table, $col ) = @_;
116
117 # Build and execute a query into the pg_catalog to find the Pg
118 # expression for the default value for this column in this table.
119 # If the table name is schema-qualified, query using that specific
120 # schema name.
121
122 # Otherwise, find the table in the standard Postgres way, using the
123 # search path. This is done with the pg_catalog.pg_table_is_visible
124 # function, which returns true if a given table is 'visible',
125 # meaning the first table of that name to be found in the search
126 # path.
127
128 # I *think* we can be assured that this query will always find the
129 # correct column according to standard Postgres semantics.
130 #
131 # -- rbuels
132
133 my $sqlmaker = $self->sql_maker;
134 local $sqlmaker->{bindtype} = 'normal';
135
136 my ($where, @bind) = $sqlmaker->where ({
137 'a.attnum' => {'>', 0},
138 'c.relname' => $table,
139 'a.attname' => $col,
140 -not_bool => 'a.attisdropped',
141 (defined $schema && length $schema)
142 ? ( 'n.nspname' => $schema )
143 : ( -bool => \'pg_catalog.pg_table_is_visible(c.oid)' )
144 });
145
146 my ($seq_expr) = $dbh->selectrow_array(<<EOS,undef,@bind);
147
148SELECT
149 (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
150 FROM pg_catalog.pg_attrdef d
151 WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
152FROM pg_catalog.pg_class c
153 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
154 JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
155$where
156
157EOS
158
159 return $seq_expr;
160}
161
162
4f533e8c 163sub sqlt_type {
164 return 'PostgreSQL';
165}
166
ee53ca0f 167my $type_cache;
a71859b4 168sub bind_attribute_by_data_type {
169 my ($self,$data_type) = @_;
170
ee53ca0f 171 # Ask for a DBD::Pg with array support
172 # pg uses (used?) version::qv()
173 require DBD::Pg;
9aec3ec6 174
175 if ($self->_server_info->{normalized_dbms_version} >= 9.0) {
176 if (not try { DBD::Pg->VERSION('2.17.2') }) {
177 carp_once( __PACKAGE__.': BYTEA columns are known to not work on Pg >='
178 . " 9.0 with DBD::Pg < 2.17.2\n" );
179 }
180 }
181 elsif (not try { DBD::Pg->VERSION('2.9.2') }) {
182 carp_once( __PACKAGE__.': DBD::Pg 2.9.2 or greater is strongly recommended'
183 . "for BYTEA column support.\n" );
a71859b4 184 }
ee53ca0f 185
186 # cache the result of _is_binary_lob_type
187 if (!exists $type_cache->{$data_type}) {
188 $type_cache->{$data_type} = $self->_is_binary_lob_type($data_type)
189 ? +{ pg_type => DBD::Pg::PG_BYTEA() }
190 : undef
a71859b4 191 }
ee53ca0f 192
193 $type_cache->{$data_type};
a71859b4 194}
195
90d7422f 196sub _exec_svp_begin {
eeb8cfeb 197 my ($self, $name) = @_;
adb3554a 198
90d7422f 199 $self->_dbh->pg_savepoint($name);
adb3554a 200}
201
90d7422f 202sub _exec_svp_release {
eeb8cfeb 203 my ($self, $name) = @_;
adb3554a 204
90d7422f 205 $self->_dbh->pg_release($name);
adb3554a 206}
207
90d7422f 208sub _exec_svp_rollback {
eeb8cfeb 209 my ($self, $name) = @_;
adb3554a 210
90d7422f 211 $self->_dbh->pg_rollback_to($name);
adb3554a 212}
213
c6375b4d 214sub deployment_statements {
215 my $self = shift;;
216 my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
217
218 $sqltargs ||= {};
219
96736321 220 if (
221 ! exists $sqltargs->{producer_args}{postgres_version}
222 and
223 my $dver = $self->_server_info->{normalized_dbms_version}
224 ) {
225 $sqltargs->{producer_args}{postgres_version} = $dver;
c6375b4d 226 }
227
228 $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
229}
230
843f8ecd 2311;
232
fd159e2a 233__END__
234
75d07914 235=head1 NAME
843f8ecd 236
237DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
238
239=head1 SYNOPSIS
240
d88ecca6 241 # In your result (table) classes
242 use base 'DBIx::Class::Core';
843f8ecd 243 __PACKAGE__->set_primary_key('id');
843f8ecd 244
245=head1 DESCRIPTION
246
247This class implements autoincrements for PostgreSQL.
248
7c0176a1 249=head1 POSTGRESQL SCHEMA SUPPORT
250
4f609014 251This driver supports multiple PostgreSQL schemas, with one caveat: for
6ff1d58c 252performance reasons, data about the search path, sequence names, and
253so forth is queried as needed and CACHED for subsequent uses.
7c0176a1 254
4f609014 255For this reason, once your schema is instantiated, you should not
256change the PostgreSQL schema search path for that schema's database
257connection. If you do, Bad Things may happen.
258
259You should do any necessary manipulation of the search path BEFORE
260instantiating your schema object, or as part of the on_connect_do
261option to connect(), for example:
7c0176a1 262
263 my $schema = My::Schema->connect
264 ( $dsn,$user,$pass,
265 { on_connect_do =>
266 [ 'SET search_path TO myschema, foo, public' ],
267 },
268 );
269
7ff926e6 270=head1 AUTHORS
7c0176a1 271
7ff926e6 272See L<DBIx::Class/CONTRIBUTORS>
843f8ecd 273
274=head1 LICENSE
275
276You may distribute this code under the same terms as Perl itself.
277
278=cut