upload 0.05003
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / DBI / Pg.pm
1 package DBIx::Class::Schema::Loader::DBI::Pg;
2
3 use strict;
4 use warnings;
5 use base qw/
6     DBIx::Class::Schema::Loader::DBI::Component::QuotedDefault
7     DBIx::Class::Schema::Loader::DBI
8 /;
9 use Carp::Clan qw/^DBIx::Class/;
10 use Class::C3;
11
12 our $VERSION = '0.05003';
13
14 =head1 NAME
15
16 DBIx::Class::Schema::Loader::DBI::Pg - DBIx::Class::Schema::Loader::DBI
17 PostgreSQL Implementation.
18
19 =head1 SYNOPSIS
20
21   package My::Schema;
22   use base qw/DBIx::Class::Schema::Loader/;
23
24   __PACKAGE__->loader_options( debug => 1 );
25
26   1;
27
28 =head1 DESCRIPTION
29
30 See L<DBIx::Class::Schema::Loader::Base>.
31
32 =cut
33
34 sub _setup {
35     my $self = shift;
36
37     $self->next::method(@_);
38     $self->{db_schema} ||= 'public';
39 }
40
41
42 sub _table_uniq_info {
43     my ($self, $table) = @_;
44
45     # Use the default support if available
46     return $self->next::method($table)
47         if $DBD::Pg::VERSION >= 1.50;
48
49     my @uniqs;
50     my $dbh = $self->schema->storage->dbh;
51
52     # Most of the SQL here is mostly based on
53     #   Rose::DB::Object::Metadata::Auto::Pg, after some prodding from
54     #   John Siracusa to use his superior SQL code :)
55
56     my $attr_sth = $self->{_cache}->{pg_attr_sth} ||= $dbh->prepare(
57         q{SELECT attname FROM pg_catalog.pg_attribute
58         WHERE attrelid = ? AND attnum = ?}
59     );
60
61     my $uniq_sth = $self->{_cache}->{pg_uniq_sth} ||= $dbh->prepare(
62         q{SELECT x.indrelid, i.relname, x.indkey
63         FROM
64           pg_catalog.pg_index x
65           JOIN pg_catalog.pg_class c ON c.oid = x.indrelid
66           JOIN pg_catalog.pg_class i ON i.oid = x.indexrelid
67           JOIN pg_catalog.pg_constraint con ON con.conname = i.relname
68           LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
69         WHERE
70           x.indisunique = 't' AND
71           c.relkind     = 'r' AND
72           i.relkind     = 'i' AND
73           con.contype   = 'u' AND
74           n.nspname     = ? AND
75           c.relname     = ?}
76     );
77
78     $uniq_sth->execute($self->db_schema, $table);
79     while(my $row = $uniq_sth->fetchrow_arrayref) {
80         my ($tableid, $indexname, $col_nums) = @$row;
81         $col_nums =~ s/^\s+//;
82         my @col_nums = split(/\s+/, $col_nums);
83         my @col_names;
84
85         foreach (@col_nums) {
86             $attr_sth->execute($tableid, $_);
87             my $name_aref = $attr_sth->fetchrow_arrayref;
88             push(@col_names, $name_aref->[0]) if $name_aref;
89         }
90
91         if(!@col_names) {
92             warn "Failed to parse UNIQUE constraint $indexname on $table";
93         }
94         else {
95             push(@uniqs, [ $indexname => \@col_names ]);
96         }
97     }
98
99     return \@uniqs;
100 }
101
102 sub _table_comment {
103     my ( $self, $table ) = @_;
104      my ($table_comment) = $self->schema->storage->dbh->selectrow_array(
105         q{SELECT obj_description(oid) 
106             FROM pg_class 
107             WHERE relname=? AND relnamespace=(
108                 SELECT oid FROM pg_namespace WHERE nspname=?)
109         }, undef, $table, $self->db_schema
110         );   
111     return $table_comment
112 }
113
114
115 sub _column_comment {
116     my ( $self, $table, $column_number ) = @_;
117      my ($table_oid) = $self->schema->storage->dbh->selectrow_array(
118         q{SELECT oid
119             FROM pg_class 
120             WHERE relname=? AND relnamespace=(
121                 SELECT oid FROM pg_namespace WHERE nspname=?)
122         }, undef, $table, $self->db_schema
123         );   
124     return $self->schema->storage->dbh->selectrow_array('SELECT col_description(?,?)', undef, $table_oid,
125     $column_number );
126 }
127
128 # Make sure data_type's that don't need it don't have a 'size' column_info, and
129 # set the correct precision for datetime and varbit types.
130 sub _columns_info_for {
131     my $self = shift;
132     my ($table) = @_;
133
134     my $result = $self->next::method(@_);
135
136     foreach my $col (keys %$result) {
137         my $data_type = $result->{$col}{data_type};
138
139         # these types are fixed size
140         if ($data_type =~
141 /^(?:bigint|int8|bigserial|serial8|bit|boolean|bool|box|bytea|cidr|circle|date|double precision|float8|inet|integer|int|int4|line|lseg|macaddr|money|path|point|polygon|real|float4|smallint|int2|serial|serial4|text)\z/i) {
142             delete $result->{$col}{size};
143         }
144 # for datetime types, check if it has a precision or not
145         elsif ($data_type =~ /^(?:interval|time|timestamp)\b/i) {
146             my ($precision) = $self->schema->storage->dbh
147                 ->selectrow_array(<<EOF, {}, $table, $col);
148 SELECT datetime_precision
149 FROM information_schema.columns
150 WHERE table_name = ? and column_name = ?
151 EOF
152
153             if ($data_type =~ /^time\b/i) {
154                 if ((not $precision) || $precision !~ /^\d/) {
155                     delete $result->{$col}{size};
156                 }
157                 else {
158                     my ($integer_datetimes) = $self->schema->storage->dbh
159                         ->selectrow_array('show integer_datetimes');
160
161                     my $max_precision =
162                         $integer_datetimes =~ /^on\z/i ? 6 : 10;
163
164                     if ($precision == $max_precision) {
165                         delete $result->{$col}{size};
166                     }
167                     else {
168                         $result->{$col}{size} = $precision;
169                     }
170                 }
171             }
172             elsif ((not $precision) || $precision !~ /^\d/ || $precision == 6) {
173                 delete $result->{$col}{size};
174             }
175             else {
176                 $result->{$col}{size} = $precision;
177             }
178         }
179         elsif ($data_type =~ /^(?:bit varying|varbit)\z/i) {
180             my ($precision) = $self->schema->storage->dbh
181                 ->selectrow_array(<<EOF, {}, $table, $col);
182 SELECT character_maximum_length
183 FROM information_schema.columns
184 WHERE table_name = ? and column_name = ?
185 EOF
186
187             $result->{$col}{size} = $precision;
188         }
189         elsif ($data_type =~ /^(?:numeric|decimal)\z/i) {
190             my $size = $result->{$col}{size};
191             $size =~ s/\s*//g;
192
193             my ($scale, $precision) = split /,/, $size;
194
195             $result->{$col}{size} = [ $precision, $scale ];
196         }
197     }
198
199     return $result;
200 }
201
202 sub _extra_column_info {
203     my ($self, $info) = @_;
204     my %extra_info;
205
206     if ($info->{COLUMN_DEF} && $info->{COLUMN_DEF} =~ /\bnextval\(/i) {
207         $extra_info{is_auto_increment} = 1;
208     }
209
210     return \%extra_info;
211 }
212
213 =head1 SEE ALSO
214
215 L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,
216 L<DBIx::Class::Schema::Loader::DBI>
217
218 =head1 AUTHOR
219
220 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
221
222 =head1 LICENSE
223
224 This library is free software; you can redistribute it and/or modify it under
225 the same terms as Perl itself.
226
227 =cut
228
229 1;