/[pgdiff]/Pg/Scheme.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /Pg/Scheme.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations)
Fri Aug 15 22:52:05 2003 UTC (20 years, 8 months ago) by dpavlin
Branch: MAIN
Changes since 1.2: +24 -0 lines
triggers support

1 dpavlin 1.1 package Pg::Scheme;
2    
3     use strict;
4     use warnings;
5     use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
6     use Carp;
7    
8    
9     use Exporter ();
10     our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
11    
12     $VERSION = 1.00;
13     @ISA = qw(Exporter);
14     @EXPORT = qw(&func1 &func2 &func4);
15     %EXPORT_TAGS = ( ); # eg: TAG => [ qw!name1 name2! ],
16    
17     @EXPORT_OK = qw(
18     &list_tables
19 dpavlin 1.2 &get_table_oid
20     &explain
21     &pg_attribute
22     &cols
23     &cols_notnull
24     &cols_null
25     &cols_pk
26     &cols_notpk
27 dpavlin 1.1 );
28    
29     my $debug;
30    
31     sub new {
32     my ($class, %args) = @_;
33     my $self = {};
34     bless($self, $class);
35     $debug = $args{'DEBUG'};
36     $self->{dbh} = $args{'dbh'} || croak "new needs to be called with 'dbh' which is handle to opened database";
37     @{$self->{tables}} = ();
38     $self ? return $self : return undef;
39     # XXX begin transaction?
40     }
41    
42     sub list_tables {
43     my $self = shift;
44     my $tables = shift;
45    
46     my @tables;
47    
48     if ($tables) {
49     @tables = split(/,/,$tables);
50     } else {
51     # take all tables
52     #$sql="select tablename from pg_tables where tablename not like 'pg_%' and tablename not like '_rserv_%'";
53     # show tables (based on psql \dt)
54     my $sql = "
55     SELECT c.relname as table
56     FROM pg_catalog.pg_class c
57     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
58     WHERE c.relkind = 'r'
59     AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
60     AND pg_catalog.pg_table_is_visible(c.oid)
61     and c.relname not like '_rserv_%'
62     ";
63     foreach my $table (@tables) {
64     $sql .= " and c.relname like '$table' x";
65     }
66     my $sth = $self->{'dbh'}->prepare($sql) || croak "can't prepare '$sql': ".$self->{'dbh'}->errstr;
67     $sth->execute() || croak "can't execute '$sql': ".$sth->errstr;
68     while(my $row = $sth->fetchrow_hashref()) {
69     push @tables,$row->{table};
70     }
71     }
72     #@{$self->{'tables'}} = @tables;
73     return @tables;
74     }
75    
76     sub get_table_oid {
77     my $self = shift;
78     my $table = shift;
79    
80     # find table oid
81     my $sql = "
82     SELECT c.oid, n.nspname, c.relname
83     FROM pg_catalog.pg_class c
84     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
85     WHERE pg_catalog.pg_table_is_visible(c.oid)
86     AND c.relname = '$table'
87     ORDER BY 2, 3
88     ";
89    
90     my $sth = $self->{'dbh'}->prepare($sql);
91     $sth->execute() || die;
92     my $row = $sth->fetchrow_hashref();
93     croak "Can't find OID of table '$table'\n" if (! $row);
94     $sth->finish();
95    
96     return $row->{oid};
97     }
98    
99 dpavlin 1.2 sub explain {
100 dpavlin 1.1 my $self = shift;
101     my $table = shift;
102    
103 dpavlin 1.2 # XXX if explained, return just results
104     # return $self->{'explained'}->{$table}->{'pg_attribute'} if ($self->{'explained'}->{$table}->{'pg_attribute'});
105     my @pg_attribute;
106 dpavlin 1.1
107     my $oid = $self->get_table_oid($table);
108    
109     my $sql="
110     SELECT a.attname,
111     pg_catalog.format_type(a.atttypid, a.atttypmod),
112     a.attnotnull, a.atthasdef, a.attnum
113     FROM pg_catalog.pg_attribute a
114     WHERE a.attrelid = ? AND a.attnum > 0 AND NOT a.attisdropped
115     ORDER BY a.attnum
116     ";
117    
118 dpavlin 1.2 my @cols; # all colums (for insert)
119     my @cols_null; # colums compared by a=b or a is null and b is null
120     my @cols_notnull;# colums compared by a=b
121    
122 dpavlin 1.1 my $sth = $self->{'dbh'}->prepare($sql);
123     $sth->execute($oid) || die;
124     while(my $row = $sth->fetchrow_hashref()) {
125     # attname | format_type | attnotnull | atthasdef | attnum
126 dpavlin 1.2 push @pg_attribute, $row;
127     push @cols,$row->{attname};
128    
129     if ($row->{attnotnull}) {
130     push @cols_notnull,$row->{attname};
131     } else {
132     push @cols_null,$row->{attname};
133     }
134    
135     }
136    
137     @{$self->{'explained'}->{$table}->{'pg_attribute'}} = @pg_attribute;
138     @{$self->{'explained'}->{$table}->{'cols'}} = @cols;
139     @{$self->{'explained'}->{$table}->{'cols_notnull'}} = @cols_notnull;
140     @{$self->{'explained'}->{$table}->{'cols_null'}} = @cols_null;
141    
142     # all, just for safe keeping
143     @{$self->{'explained'}->{$table}->{'cols_notpk'}} = @cols;
144    
145     # now, try to find primary key
146    
147     my @cols_pk; # columns which are primary key
148     my @cols_notpk;
149     my %in_pk;
150    
151     $sql="
152     SELECT
153     i.indexrelid as indexrelid, i.indrelid as indrelid,
154     count(a.attname) as cols_in_pk
155     FROM
156     pg_catalog.pg_class c,
157     pg_catalog.pg_index i,
158     pg_catalog.pg_attribute a
159     WHERE
160     c.oid = i.indrelid
161     and i.indisunique
162     and c.relname = '$table'
163     and a.attrelid = i.indexrelid
164     GROUP BY
165     i.indexrelid, i.indrelid, c.relname, i.indisprimary, i.indisunique
166     ORDER BY
167     cols_in_pk ASC, i.indisprimary DESC, i.indisunique DESC, c.relname DESC
168     ";
169     print STDERR "DEBUG: $sql\n" if ($debug);
170     $sth = $self->{'dbh'}->prepare($sql);
171     $sth->execute() || die;
172     my $row = $sth->fetchrow_hashref();
173     if ($row) {
174     $sql="
175     select a1.attname as attname from pg_attribute a1, pg_attribute a2 where a1.attrelid = ".$row->{indexrelid}." and a2.attrelid=".$row->{indrelid}." and a1.attname = a2.attname and a2.attnotnull";
176    
177     my $sth2 = $self->{'dbh'}->prepare($sql);
178     print STDERR "DEBUG: $sql\n" if ($debug);
179     $sth2->execute() || die;
180     while (my $row2 = $sth2->fetchrow_hashref()) {
181     push @cols_pk,$row2->{attname};
182     $in_pk{$row2->{attname}}++;
183     }
184    
185     }
186    
187     foreach my $col (@cols) {
188     push @cols_notpk,$col if (! $in_pk{$col});
189     }
190    
191     @{$self->{'explained'}->{$table}->{cols_pk}} = @cols_pk;
192     @{$self->{'explained'}->{$table}->{cols_notpk}} = @cols_notpk;
193    
194     return @pg_attribute;
195     }
196    
197     # return all rows in PostgreSQL format
198     # attname | format_type | attnotnull | atthasdef | attnum
199     #
200     # somewhat internal function, but still usefull if you want to
201     # do tweaking of columns your way
202     #
203     sub pg_attribute {
204     my $self = shift;
205     my $table = shift;
206    
207     if (! $self->{'explained'}->{$table}) {
208     $self->explain($table);
209     }
210    
211     return $self->{'explained'}->{$table}->{pg_attribute};
212     }
213    
214     # return columns in given table
215     sub cols {
216     my $self = shift;
217     my $table = shift;
218    
219     if (! $self->{'explained'}->{$table}) {
220     $self->explain($table);
221     }
222    
223     return $self->{'explained'}->{$table}->{cols};
224     }
225    
226     # return not null columns in given table
227     sub cols_notnull {
228     my $self = shift;
229     my $table = shift;
230    
231     if (! $self->{'explained'}->{$table}) {
232     $self->explain($table);
233     }
234    
235     return $self->{'explained'}->{$table}->{cols_notnull};
236     }
237    
238     # return columns which *can* be null in given table
239     sub cols_null {
240     my $self = shift;
241     my $table = shift;
242    
243     if (! $self->{'explained'}->{$table}) {
244     $self->explain($table);
245     }
246    
247     return $self->{'explained'}->{$table}->{cols_null};
248     }
249    
250     # return primary key columns
251     sub cols_pk {
252     my $self = shift;
253     my $table = shift;
254    
255     if (! $self->{'explained'}->{$table}) {
256     $self->explain($table);
257     }
258    
259     return $self->{'explained'}->{$table}->{cols_pk};
260     }
261    
262     # return columns not in primary key
263     sub cols_notpk {
264     my $self = shift;
265     my $table = shift;
266    
267     if (! $self->{'explained'}->{$table}) {
268     $self->explain($table);
269 dpavlin 1.1 }
270    
271 dpavlin 1.2 return $self->{'explained'}->{$table}->{cols_notpk};
272 dpavlin 1.1 }
273 dpavlin 1.3
274     # get active triggers
275     sub get_triggers {
276     my $self = shift;
277    
278     # find table oid
279     my $sql = "
280     SELECT tgname FROM pg_trigger
281     WHERE tgname not like 'pg_%' and tgenabled IS TRUE
282     ";
283    
284     my $sth = $self->{'dbh'}->prepare($sql);
285     $sth->execute() || die;
286    
287     my @triggers;
288    
289     while (my ($tr) = $sth->fetchrow_array()) {
290     push @triggers,$tr;
291     }
292     $sth->finish();
293    
294     return @triggers;
295     }
296    
297 dpavlin 1.1 1;

  ViewVC Help
Powered by ViewVC 1.1.26