Roll back massive unrelated test changeset introduced in 74b5397c
[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
be64931c 6use base qw/DBIx::Class::Storage::DBI/;
843f8ecd 7
4d4dc518 8use Scope::Guard ();
6298a324 9use Context::Preserve 'preserve_context';
ee53ca0f 10use DBIx::Class::Carp;
9aec3ec6 11use Try::Tiny;
6298a324 12use namespace::clean;
843f8ecd 13
6a247f33 14__PACKAGE__->sql_limit_dialect ('LimitOffset');
2b8cc2f2 15__PACKAGE__->sql_quote_char ('"');
6f7a118e 16__PACKAGE__->datetime_parser_type ('DateTime::Format::Pg');
be64931c 17__PACKAGE__->_use_multicolumn_in (1);
6a247f33 18
bbdda281 19sub _determine_supports_insert_returning {
20 return shift->_server_info->{normalized_dbms_version} >= 8.002
21 ? 1
22 : 0
23 ;
38d5ea9f 24}
25
e96a93df 26sub with_deferred_fk_checks {
27 my ($self, $sub) = @_;
28
4d4dc518 29 my $txn_scope_guard = $self->txn_scope_guard;
30
31 $self->_do_query('SET CONSTRAINTS ALL DEFERRED');
38d5ea9f 32
2131aa2e 33 return preserve_context {
2aa3f4c0 34 my $inner_self = $self; # avoid nested closure leak on 5.8
2131aa2e 35 my $sg = Scope::Guard->new(sub {
2aa3f4c0 36 $inner_self->_do_query('SET CONSTRAINTS ALL IMMEDIATE');
2131aa2e 37 });
38 $sub->()
39 } 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(
e705f529 53 "Could not determine sequence for column '%s.%s', please consider adding a schema-qualified sequence to its column info",
38d5ea9f 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 (
e705f529 100 "No sequence found for '%s%s.%s', check the RDBMS table definition or explicitly set the ".
d3fdc7b8 101 "'sequence' for this column in %s",
102 $schema ? "$schema." : '',
103 $table,
104 $col,
105 $source->source_name,
106 ));
777f7527 107 }
2d424996 108
d77ee505 109 return $1; # exception thrown unless match is made above
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
a71859b4 167sub bind_attribute_by_data_type {
168 my ($self,$data_type) = @_;
169
8892d8e5 170 if ($self->_is_binary_lob_type($data_type)) {
171 # this is a hot-ish codepath, use an escape flag to minimize
172 # amount of function/method calls
173 # additionally version.pm is cock, and memleaks on multiple
174 # ->VERSION calls
175 # the flag is stored in the DBD namespace, so that Class::Unload
176 # will work (unlikely, but still)
177 unless ($DBD::Pg::__DBIC_DBD_VERSION_CHECK_DONE__) {
178 if ($self->_server_info->{normalized_dbms_version} >= 9.0) {
179 try { DBD::Pg->VERSION('2.17.2'); 1 } or carp (
180 __PACKAGE__.': BYTEA columns are known to not work on Pg >= 9.0 with DBD::Pg < 2.17.2'
181 );
182 }
183 elsif (not try { DBD::Pg->VERSION('2.9.2'); 1 } ) { carp (
184 __PACKAGE__.': DBD::Pg 2.9.2 or greater is strongly recommended for BYTEA column support'
185 )}
186
187 $DBD::Pg::__DBIC_DBD_VERSION_CHECK_DONE__ = 1;
9aec3ec6 188 }
ee53ca0f 189
8892d8e5 190 return { pg_type => DBD::Pg::PG_BYTEA() };
191 }
192 else {
193 return undef;
a71859b4 194 }
195}
196
90d7422f 197sub _exec_svp_begin {
eeb8cfeb 198 my ($self, $name) = @_;
adb3554a 199
90d7422f 200 $self->_dbh->pg_savepoint($name);
adb3554a 201}
202
90d7422f 203sub _exec_svp_release {
eeb8cfeb 204 my ($self, $name) = @_;
adb3554a 205
90d7422f 206 $self->_dbh->pg_release($name);
adb3554a 207}
208
90d7422f 209sub _exec_svp_rollback {
eeb8cfeb 210 my ($self, $name) = @_;
adb3554a 211
90d7422f 212 $self->_dbh->pg_rollback_to($name);
adb3554a 213}
214
c6375b4d 215sub deployment_statements {
216 my $self = shift;;
217 my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
218
219 $sqltargs ||= {};
220
96736321 221 if (
222 ! exists $sqltargs->{producer_args}{postgres_version}
223 and
224 my $dver = $self->_server_info->{normalized_dbms_version}
225 ) {
226 $sqltargs->{producer_args}{postgres_version} = $dver;
c6375b4d 227 }
228
229 $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
230}
231
843f8ecd 2321;
233
fd159e2a 234__END__
235
75d07914 236=head1 NAME
843f8ecd 237
238DBIx::Class::Storage::DBI::Pg - Automatic primary key class for PostgreSQL
239
240=head1 SYNOPSIS
241
d88ecca6 242 # In your result (table) classes
243 use base 'DBIx::Class::Core';
843f8ecd 244 __PACKAGE__->set_primary_key('id');
843f8ecd 245
246=head1 DESCRIPTION
247
248This class implements autoincrements for PostgreSQL.
249
7c0176a1 250=head1 POSTGRESQL SCHEMA SUPPORT
251
4f609014 252This driver supports multiple PostgreSQL schemas, with one caveat: for
6ff1d58c 253performance reasons, data about the search path, sequence names, and
254so forth is queried as needed and CACHED for subsequent uses.
7c0176a1 255
4f609014 256For this reason, once your schema is instantiated, you should not
257change the PostgreSQL schema search path for that schema's database
258connection. If you do, Bad Things may happen.
259
260You should do any necessary manipulation of the search path BEFORE
261instantiating your schema object, or as part of the on_connect_do
262option to connect(), for example:
7c0176a1 263
264 my $schema = My::Schema->connect
265 ( $dsn,$user,$pass,
266 { on_connect_do =>
267 [ 'SET search_path TO myschema, foo, public' ],
268 },
269 );
270
a2bd3796 271=head1 FURTHER QUESTIONS?
7c0176a1 272
a2bd3796 273Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
843f8ecd 274
a2bd3796 275=head1 COPYRIGHT AND LICENSE
843f8ecd 276
a2bd3796 277This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
278by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
279redistribute it and/or modify it under the same terms as the
280L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.