3218a26796492c731ea3b1821d0408fe7a6e1414
[DBIx-DBSchema.git] / DBSchema / DBD / Pg.pm
1 package DBIx::DBSchema::DBD::Pg;
2
3 use strict;
4 use vars qw($VERSION @ISA %typemap);
5 use DBD::Pg 1.32;
6 die "DBD::Pg version 1.32 or 1.41 (or later) required--".
7     "this is only version $DBD::Pg::VERSION\n"
8   if $DBD::Pg::VERSION != 1.32 && $DBD::Pg::VERSION < 1.41;
9 use DBIx::DBSchema::DBD;
10
11 $VERSION = '0.10';
12 @ISA = qw(DBIx::DBSchema::DBD);
13
14 %typemap = (
15   'BLOB' => 'BYTEA',
16   'LONG VARBINARY' => 'BYTEA',
17 );
18
19 =head1 NAME
20
21 DBIx::DBSchema::DBD::Pg - PostgreSQL native driver for DBIx::DBSchema
22
23 =head1 SYNOPSIS
24
25 use DBI;
26 use DBIx::DBSchema;
27
28 $dbh = DBI->connect('dbi:Pg:dbname=database', 'user', 'pass');
29 $schema = new_native DBIx::DBSchema $dbh;
30
31 =head1 DESCRIPTION
32
33 This module implements a PostgreSQL-native driver for DBIx::DBSchema.
34
35 =cut
36
37 sub default_db_schema  { 'public'; }
38
39 sub columns {
40   my($proto, $dbh, $table) = @_;
41   my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
42     SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull,
43            a.atthasdef, a.attnum
44     FROM pg_class c, pg_attribute a, pg_type t
45     WHERE c.relname = '$table'
46       AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
47     ORDER BY a.attnum
48 END
49   $sth->execute or die $sth->errstr;
50
51   map {
52
53     my $default = '';
54     if ( $_->{atthasdef} ) {
55       my $attnum = $_->{attnum};
56       my $d_sth = $dbh->prepare(<<END) or die $dbh->errstr;
57         SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c
58         WHERE c.relname = '$table' AND c.oid = d.adrelid AND d.adnum = $attnum
59 END
60       $d_sth->execute or die $d_sth->errstr;
61
62       $default = $d_sth->fetchrow_arrayref->[0];
63     };
64
65     my $len = '';
66     if ( $_->{attlen} == -1 && $_->{atttypmod} != -1 
67          && $_->{typname} ne 'text'                  ) {
68       $len = $_->{atttypmod} - 4;
69       if ( $_->{typname} eq 'numeric' ) {
70         $len = ($len >> 16). ','. ($len & 0xffff);
71       }
72     }
73
74     my $type = $_->{'typname'};
75     $type = 'char' if $type eq 'bpchar';
76
77     [
78       $_->{'attname'},
79       $type,
80       ! $_->{'attnotnull'},
81       $len,
82       $default,
83       ''  #local
84     ];
85
86   } @{ $sth->fetchall_arrayref({}) };
87 }
88
89 sub primary_key {
90   my($proto, $dbh, $table) = @_;
91   my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
92     SELECT a.attname, a.attnum
93     FROM pg_class c, pg_attribute a, pg_type t
94     WHERE c.relname = '${table}_pkey'
95       AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
96 END
97   $sth->execute or die $sth->errstr;
98   my $row = $sth->fetchrow_hashref or return '';
99   $row->{'attname'};
100 }
101
102 sub unique {
103   my($proto, $dbh, $table) = @_;
104   my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $_ ) ] }
105       grep { $proto->_is_unique($dbh, $_ ) }
106         $proto->_all_indices($dbh, $table)
107   };
108 }
109
110 sub index {
111   my($proto, $dbh, $table) = @_;
112   my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $_ ) ] }
113       grep { ! $proto->_is_unique($dbh, $_ ) }
114         $proto->_all_indices($dbh, $table)
115   };
116 }
117
118 sub _all_indices {
119   my($proto, $dbh, $table) = @_;
120   my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
121     SELECT c2.relname
122     FROM pg_class c, pg_class c2, pg_index i
123     WHERE c.relname = '$table' AND c.oid = i.indrelid AND i.indexrelid = c2.oid
124 END
125   $sth->execute or die $sth->errstr;
126   map { $_->{'relname'} }
127     grep { $_->{'relname'} !~ /_pkey$/ }
128       @{ $sth->fetchall_arrayref({}) };
129 }
130
131 sub _index_fields {
132   my($proto, $dbh, $index) = @_;
133   my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
134     SELECT a.attname, a.attnum
135     FROM pg_class c, pg_attribute a, pg_type t
136     WHERE c.relname = '$index'
137       AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
138 END
139   $sth->execute or die $sth->errstr;
140   map { $_->{'attname'} } @{ $sth->fetchall_arrayref({}) };
141 }
142
143 sub _is_unique {
144   my($proto, $dbh, $index) = @_;
145   my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
146     SELECT i.indisunique
147     FROM pg_index i, pg_class c, pg_am a
148     WHERE i.indexrelid = c.oid AND c.relname = '$index' AND c.relam = a.oid
149 END
150   $sth->execute or die $sth->errstr;
151   my $row = $sth->fetchrow_hashref or die 'guru meditation #420';
152   $row->{'indisunique'};
153 }
154
155 =head1 AUTHOR
156
157 Ivan Kohler <ivan-dbix-dbschema@420.am>
158
159 =head1 COPYRIGHT
160
161 Copyright (c) 2000 Ivan Kohler
162 Copyright (c) 2000 Mail Abuse Prevention System LLC
163 All rights reserved.
164 This program is free software; you can redistribute it and/or modify it under
165 the same terms as Perl itself.
166
167 =head1 BUGS
168
169 Yes.
170
171 columns doesn't return column default information.
172
173 =head1 SEE ALSO
174
175 L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD>, L<DBI>, L<DBI::DBD>
176
177 =cut 
178
179 1;
180