refactored how Pg storage driver calls sequence search, made erorror message more...
[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) = @_;
0063119f 24 my $seq = ( $source->column_info($col)->{sequence} ||= $self->dbh_do('_dbh_get_autoinc_seq', $source, $col) )
5f70776f 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
d4f16b21 42sub _dbh_get_autoinc_seq {
0063119f 43 my ($self, $dbh, $source, $col) = @_;
44
45 my $schema;
46 my $table = $source->name;
47
48 # deref table name if it needs it
49 $table = $$table
50 if ref $table eq 'SCALAR';
51
52 # parse out schema name if present
53 if( $table =~ /^(.+)\.(.+)$/ ) {
54 ( $schema, $table ) = ( $1, $2 );
55 }
0680ac39 56
20f43d0c 57 my $sqlmaker = $self->sql_maker;
58 local $sqlmaker->{bindtype} = 'normal';
59
0063119f 60 my ($where, @bind) = $sqlmaker->where ({
20f43d0c 61 'a.attnum' => {'>', 0},
62 'c.relname' => $table,
63 'a.attname' => $col,
64 -not_bool => 'a.attisdropped',
65 (defined $schema && length $schema)
66 ? ( 'n.nspname' => $schema )
67 : ( -bool => \'pg_catalog.pg_table_is_visible(c.oid)' )
68 });
5e14a204 69
70 my ($seq_expr) = $dbh->selectrow_array(<<EOS,undef,@bind);
20f43d0c 71
5e14a204 72SELECT
73 (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
74 FROM pg_catalog.pg_attrdef d
75 WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
76FROM pg_catalog.pg_class c
0063119f 77 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
5e14a204 78 JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
20f43d0c 79$where
80
5e14a204 81EOS
82
0063119f 83 defined $seq_expr and length $seq_expr
84 or $self->throw_exception( "no sequence found for $table.$col, check table definition, "
85 . "or explicitly set the 'sequence' for this column in the "
86 . $source->source_name
87 . " class"
88 );
89
90 unless ( $seq_expr =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i ){
20f43d0c 91 $seq_expr = '' unless defined $seq_expr;
0063119f 92 $schema = $schema . "." if defined $schema && length $schema;
93 $self->throw_exception("could not parse nextval expression for $schema$table.$col: '$seq_expr'");
20f43d0c 94 }
5e14a204 95
96 return $1;
843f8ecd 97}
98
99sub get_autoinc_seq {
ca48cd7d 100 my ($self,$source,$col) = @_;
d4daee7b 101
843f8ecd 102}
103
4f533e8c 104sub sqlt_type {
105 return 'PostgreSQL';
106}
107
45fa8288 108sub datetime_parser_type { return "DateTime::Format::Pg"; }
109
a71859b4 110sub bind_attribute_by_data_type {
111 my ($self,$data_type) = @_;
112
113 my $bind_attributes = {
eda28767 114 bytea => { pg_type => DBD::Pg::PG_BYTEA },
5ba88f68 115 blob => { pg_type => DBD::Pg::PG_BYTEA },
a71859b4 116 };
d4daee7b 117
a71859b4 118 if( defined $bind_attributes->{$data_type} ) {
9fdf90df 119 return $bind_attributes->{$data_type};
a71859b4 120 }
121 else {
122 return;
123 }
124}
125
f04b2839 126sub _sequence_fetch {
127 my ( $self, $type, $seq ) = @_;
9ae966b9 128 my ($id) = $self->_get_dbh->selectrow_array("SELECT nextval('${seq}')");
f04b2839 129 return $id;
130}
131
adb3554a 132sub _svp_begin {
eeb8cfeb 133 my ($self, $name) = @_;
adb3554a 134
9ae966b9 135 $self->_get_dbh->pg_savepoint($name);
adb3554a 136}
137
138sub _svp_release {
eeb8cfeb 139 my ($self, $name) = @_;
adb3554a 140
9ae966b9 141 $self->_get_dbh->pg_release($name);
adb3554a 142}
143
144sub _svp_rollback {
eeb8cfeb 145 my ($self, $name) = @_;
adb3554a 146
9ae966b9 147 $self->_get_dbh->pg_rollback_to($name);
adb3554a 148}
149
843f8ecd 1501;
151
fd159e2a 152__END__
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
4f609014 171This driver supports multiple PostgreSQL schemas, with one caveat: for
6ff1d58c 172performance reasons, data about the search path, sequence names, and
173so forth is queried as needed and CACHED for subsequent uses.
7c0176a1 174
4f609014 175For this reason, once your schema is instantiated, you should not
176change the PostgreSQL schema search path for that schema's database
177connection. If you do, Bad Things may happen.
178
179You should do any necessary manipulation of the search path BEFORE
180instantiating your schema object, or as part of the on_connect_do
181option to connect(), for example:
7c0176a1 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