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

Diff of /pgdiff

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by dpavlin, Tue Aug 12 12:00:07 2003 UTC revision 1.6 by dpavlin, Wed Aug 13 13:27:32 2003 UTC
# Line 11  use strict; Line 11  use strict;
11  use Getopt::Long;  use Getopt::Long;
12  use DBI;  use DBI;
13  use Data::Dumper;  use Data::Dumper;
14    use Pg::Scheme;
15    
16  $| = 1;  $| = 1;
17    
# Line 105  sub debug { Line 106  sub debug {
106    
107  $verbose = 1 if ($debug);  $verbose = 1 if ($debug);
108    
109    # init object for scheme in master database
110    my $mscheme = new Pg::Scheme( 'dbh' => $mdbh, 'DEBUG' => 0 ) || die "can't query schema";
111    
112  # which tables to compare?  # which tables to compare?
113    
114  my @tables;  my @tables = $mscheme->list_tables($tables);
 if ($tables) {  
         @tables = split(/,/,$tables);  
 } else {  
         # take all tables  
         #$sql="select tablename from pg_tables where tablename not like 'pg_%' and tablename not like '_rserv_%'";  
         # show tables (based on psql \dt)  
         $sql = "  
         SELECT c.relname as table  
         FROM pg_catalog.pg_class c  
                 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace  
         WHERE c.relkind = 'r'  
                 AND n.nspname NOT IN ('pg_catalog', 'pg_toast')  
                 AND pg_catalog.pg_table_is_visible(c.oid)  
                 and c.relname not like '_rserv_%'  
         ";  
         foreach my $table (@tables) {  
                 $sql .= " and c.relname like '$table'";  
         }  
         my $sth = $mdbh->prepare($sql);  
         $sth->execute() || die;  
         while(my $row = $sth->fetchrow_hashref()) {  
                 push @tables,$row->{table};  
         }  
 }  
115    
116  debug "Comparing tables: ".join(", ",@tables)."\n";  debug "Comparing tables: ".join(", ",@tables)."\n";
117    
# Line 140  my $diff_total = 0; Line 120  my $diff_total = 0;
120    
121  foreach my $table (@tables) {  foreach my $table (@tables) {
122    
123          my ($sth);          my $sth;
124    
125          # find table oid          # diff schema
         $sql = "  
         SELECT c.oid, n.nspname, c.relname  
         FROM pg_catalog.pg_class c  
         LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace  
         WHERE pg_catalog.pg_table_is_visible(c.oid)  
         AND c.relname = '$table'  
         ORDER BY 2, 3  
         ";  
   
         $sth = $mdbh->prepare($sql);  
         $sth->execute() || die;  
         my $row = $sth->fetchrow_hashref();  
         if (! $row) {  
                 print STDERR "Can't find OID of table '$table'\n";  
                 exit 1;  
         }  
126    
127          my $oid = $row->{oid};          # all colums (for insert)
128            my @cols = @{$mscheme->cols($table)};
129    
130          # diff schema          # colums compared by a=b
131            my @cols_notnull = @{$mscheme->cols_notnull($table)};
132    
133            # colums compared by a=b or a is null and b is null
134            my @cols_null = @{$mscheme->cols_null($table)};
135    
136            # primary key columns
137            my @cols_pk = @{$mscheme->cols_pk($table)};
138    
139            # columns to compare (not in primary key)
140            my @cols_cmp = @{$mscheme->cols_notpk($table)};
141    
         my @cols_notnull;# colums compared by a=b  
         my @cols_null;  # colums compared by a=b or a is null and b is null  
142          my @cols_skip;  # skipped columns          my @cols_skip;  # skipped columns
143          my @cols_test;  # all colums to test (without skipped)          my @cols_test;  # all colums to test (without skipped)
         my @cols;       # all colums (for insert)  
   
         my $sql="  
 SELECT a.attname,  
 pg_catalog.format_type(a.atttypid, a.atttypmod),  
 a.attnotnull, a.atthasdef, a.attnum  
 FROM pg_catalog.pg_attribute a  
 WHERE a.attrelid = $oid AND a.attnum > 0 AND NOT a.attisdropped  
 ORDER BY a.attnum  
 ";  
144    
145          $sth = $mdbh->prepare($sql);          foreach my $row (@{$mscheme->pg_attribute($table)}) {
         $sth->execute() || die;  
         while(my $row = $sth->fetchrow_hashref()) {  
146                  # attname | format_type | attnotnull | atthasdef | attnum                  # attname | format_type | attnotnull | atthasdef | attnum
147    
                 push @cols,$row->{attname};  
   
148                  # FIXME: do something with attributes which shouldn't be compared                  # FIXME: do something with attributes which shouldn't be compared
149                  # (date, time, datetime, timestamp)                  # (date, time, datetime, timestamp)
150                  if ($row->{format_type} =~ /(date)|(time)/i) {                  if ($row->{format_type} =~ /(date)|(time)/i) {
151                          push @cols_skip,$row->{attname};                          push @cols_skip,$row->{attname};
                         next;  
                 }  
   
                 push @cols_test,$row->{attname};  
   
                 if ($row->{attnotnull}) {  
                         push @cols_notnull,$row->{attname};  
152                  } else {                  } else {
153                          push @cols_null,$row->{attname};                          push @cols_test,$row->{attname};
154                  }                  }
155    
156          }          }
         $sth->finish();  
157    
158          if ($debug) {          if ($debug) {
159                  print STDERR "DEBUG: table $table [$oid] not null: (",join(", ",@cols_notnull),")";                  print STDERR "DEBUG: table $table not null cols: (",join(", ",@cols_notnull),")";
160                  print STDERR " - null: (",join(", ",@cols_null),")" if (@cols_null);                  print STDERR " - null cols: (",join(", ",@cols_null),")" if (@cols_null);
161                  print STDERR " - skip: (",join(", ",@cols_skip),")" if (@cols_skip);                  print STDERR " - skip cols: (",join(", ",@cols_skip),")" if (@cols_skip);
162                  print STDERR "\n";                  print STDERR "\n";
163          }          }
164    
165          # diff data          # diff data
166    
         my @cols_pk;    # columns which are primary key  
         my %in_pk;  
   
         $sql="  
 SELECT  
         i.indexrelid as indexrelid, i.indrelid as indrelid,  
         count(a.attname) as cols_in_pk  
 FROM  
         pg_catalog.pg_class c,  
         pg_catalog.pg_index i,  
         pg_catalog.pg_attribute a  
 WHERE  
         c.oid = i.indrelid  
         and i.indisunique  
         and c.relname = '$table'  
         and a.attrelid = i.indexrelid  
 GROUP BY  
         i.indexrelid, i.indrelid, c.relname, i.indisprimary, i.indisunique  
 ORDER BY  
         cols_in_pk ASC, i.indisprimary DESC, i.indisunique DESC, c.relname DESC  
 ";  
         debug_sql($sql);  
         $sth = $mdbh->prepare($sql);  
         $sth->execute() || die;  
         $row = $sth->fetchrow_hashref();  
         if ($row) {  
                 $sql="  
                 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";  
                   
                 debug_sql($sql);  
                 my $sth2 = $mdbh->prepare($sql);  
                 $sth2->execute() || die;  
                 @cols_pk = ();  
                 while (my $row2 = $sth2->fetchrow_hashref()) {  
                         push @cols_pk,$row2->{attname};  
                         $in_pk{$row2->{attname}}++;  
                 }  
                   
         }  
167          if (! @cols_pk) {          if (! @cols_pk) {
168                  print STDERR "can't find PK rows for table '$table' using all\n";                  print STDERR "can't find PK rows for table '$table' using all\n";
169                  @cols_pk = @cols;                  @cols_pk = @cols;
170          }          }
171    
         my @cols_cmp;   # columns to compare  
   
         foreach my $col (@cols_test) {  
                 push @cols_cmp,$col if (! $in_pk{$col});  
         }  
172    
173          if ($verbose) {          if ($verbose) {
174                  print "table '$table' using for key: (",join(", ",@cols_pk),") to compare cols: (",join(", ",@cols_cmp),")\n";                  print "table '$table' using for key: (",join(", ",@cols_pk),") to compare cols: (",join(", ",@cols_cmp),")\n";
# Line 358  ORDER BY Line 266  ORDER BY
266    
267                  # insert into slave database                  # insert into slave database
268                  sub sql_insert {                  sub sql_insert {
269                            my $dbh = shift @_ || die "need dbh";
270                          my $table = shift @_ || die "need table as argument";                          my $table = shift @_ || die "need table as argument";
271                          my $row = shift @_ || die "need row data";                          my $row = shift @_ || die "need row data";
272                          my @cols = @_;                          my @cols = @_;
# Line 365  ORDER BY Line 274  ORDER BY
274                          my $sql = "insert into $table (".join(",",@cols).") values (";                          my $sql = "insert into $table (".join(",",@cols).") values (";
275                          my $comma = "";                          my $comma = "";
276                          foreach my $col (@cols) {                          foreach my $col (@cols) {
277                                  $sql .= $comma.$mdbh->quote($row->{$col});                                  $sql .= $comma.$dbh->quote($row->{$col});
278                                  $comma = ",";                                  $comma = ",";
279                          }                          }
280                          $sql.=")";                          $sql.=")";
# Line 375  ORDER BY Line 284  ORDER BY
284    
285                  # delete from slave database                  # delete from slave database
286                  sub sql_delete {                  sub sql_delete {
287                            my $dbh = shift @_ || die "need dbh";
288                          my $table = shift @_ || die "need table as argument";                          my $table = shift @_ || die "need table as argument";
289                          my $row = shift @_ || die "need row as argument";                          my $row = shift @_ || die "need row as argument";
290                          my @cols_pk = @_;                          my @cols_pk = @_;
291    
292                          my $where = sql_where(@cols_pk);                          my $where = sql_where(@cols_pk);
293    
294                          my $sql = "delete from $table ";                          my $sql = "delete from $table";
295                          foreach my $col (@cols_pk) {                          foreach my $col (@cols_pk) {
296                                  my $val = $sdbh->quote($row->{$col}) || die "can't find value in row for col $col";                                  my $val = $dbh->quote($row->{$col}) || die "can't find value in row for col $col";
297                                  $where =~ s/\?/$val/;                                  $where =~ s/\?/$val/;
298                          }                          }
299                          $sql .= $where;                          $sql .= $where;
# Line 393  ORDER BY Line 303  ORDER BY
303    
304                  # update row in slave database                  # update row in slave database
305                  sub sql_update {                  sub sql_update {
306                            my $dbh = shift @_ || die "need dbh";
307                          my $table = shift @_ || die "need table as argument";                          my $table = shift @_ || die "need table as argument";
308                          my $col = shift @_ || die "need col to update";                          my $col = shift @_ || die "need col to update";
309                          my $val = shift @_ || die "need new val";                          my $row = shift @_ || die "need row";
310                          my @cols_pk = @_ || die "need pk idenitifier";                          my @cols_pk = @_;
311    
312                          my $sql = "udate $table set $col=".$mdbh->quote($val);                          my $sql = "update $table set $col=".$dbh->quote($row->{$col});
313                            my $where = sql_where(@cols_pk);
314                            foreach my $col (@cols_pk) {
315                                    my $val = $dbh->quote($row->{$col}) || die "can't find value in row for col $col";
316                                    $where =~ s/\?/$val/;
317                            }
318                            $sql .= $where;
319                          debug_sql($sql);                          debug_sql($sql);
320                          return $sql;                          return $sql;
321                  }                  }
# Line 418  ORDER BY Line 335  ORDER BY
335                                  $diff_row++;                                  $diff_row++;
336                                  $pk_same = 0;                                  $pk_same = 0;
337                                  print STDERR "EXTRA row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($srow,@cols_pk)).")\n" if ($verbose);                                  print STDERR "EXTRA row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($srow,@cols_pk)).")\n" if ($verbose);
338                                  print sql_delete($table,$srow,@cols_pk),";\n";                                  print sql_delete($sdbh,$table,$srow,@cols_pk),";\n";
339                                  $have_srow = FETCH_ROW;                                  $have_srow = FETCH_ROW;
340                                  last;                                  last;
341                          } elsif ( ($have_mrow == HAVE_ROW && $have_srow == NO_ROW) ||                          } elsif ( ($have_mrow == HAVE_ROW && $have_srow == NO_ROW) ||
# Line 426  ORDER BY Line 343  ORDER BY
343                                  $diff_row++;                                  $diff_row++;
344                                  $pk_same = 0;                                  $pk_same = 0;
345                                  print STDERR "MISSING row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($mrow,@cols_pk)).")\n" if ($verbose);                                  print STDERR "MISSING row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($mrow,@cols_pk)).")\n" if ($verbose);
346                                  print sql_insert($table,$mrow,@cols),";\n";                                  print sql_insert($mdbh,$table,$mrow,@cols),";\n";
347                                  $have_mrow = FETCH_ROW;                                  $have_mrow = FETCH_ROW;
348                                  last;                                  last;
349                          }                          }
# Line 438  ORDER BY Line 355  ORDER BY
355                                  if ($mrow->{$col} ne $srow->{$col}) {                                  if ($mrow->{$col} ne $srow->{$col}) {
356                                          $diff_row++;                                          $diff_row++;
357                                          print STDERR "DIFF in table '$table' row ($col): [".join(",",@cols_pk)."] '$mrow->{$col}' != '$srow->{$col}'\n" if ($verbose);                                          print STDERR "DIFF in table '$table' row ($col): [".join(",",@cols_pk)."] '$mrow->{$col}' != '$srow->{$col}'\n" if ($verbose);
358                                          print sql_update($table,$col,$mrow->{$col},@cols_pk),";\n";                                          print sql_update($mdbh,$table,$col,$mrow,@cols_pk),";\n";
359                                  }                                  }
360                          }                          }
361                          $have_mrow = FETCH_ROW;                          $have_mrow = FETCH_ROW;
# Line 450  ORDER BY Line 367  ORDER BY
367          $diff_total += $diff_row;          $diff_total += $diff_row;
368  }  }
369    
370  print STDERR "$diff_total differences in all tables\n" if ($verbose && $diff_total > 0);  if ($verbose) {
371            if ($diff_total == 0) {
372                    print STDERR "databases are same";
373            } elsif ($diff_total > 0) {
374                    print STDERR "$diff_total differences in all tables\n";
375            } else {
376                    die "this shouldn't happend. please report a bug!";
377            }
378    }
379    
380  $mdbh->disconnect();  $mdbh->disconnect();
381  $sdbh->disconnect();  $sdbh->disconnect();

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.6

  ViewVC Help
Powered by ViewVC 1.1.26