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