/[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.1 by dpavlin, Tue Aug 12 10:38:23 2003 UTC revision 1.4 by dpavlin, Tue Aug 12 18:45:04 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 74  sub debug_sql { Line 75  sub debug_sql {
75          my $sql = shift;          my $sql = shift;
76          $sql =~ s/[\n\r]/ /gs;          $sql =~ s/[\n\r]/ /gs;
77          $sql =~ s/\s\s+/ /g;          $sql =~ s/\s\s+/ /g;
78          print STDERR "SQL: $sql\n";          print STDERR "DEBUG: SQL: $sql\n";
79  }  }
80    
81  sub debug_row {  sub debug_row {
# Line 82  sub debug_row { Line 83  sub debug_row {
83          my $row = shift;          my $row = shift;
84          my @cols = @_;          my @cols = @_;
85          if (! $row) {          if (! $row) {
86                  print STDERR "ROW data is undef!\n";                  print STDERR "DEBUG: ROW data is undef!\n";
87                  return;                  return;
88          }          }
89          print STDERR "ROW: [",$#cols+1,"] ";          print STDERR "DEBUG: ROW: [",$#cols+1,"] ";
90          foreach my $col (@cols) {          foreach my $col (@cols) {
91                  print STDERR "$col:";                  print STDERR "$col:";
92                  if ($row->{$col}) {                  if ($row->{$col}) {
# Line 98  sub debug_row { Line 99  sub debug_row {
99          print STDERR "\n";          print STDERR "\n";
100  }  }
101    
102    sub debug {
103            return if (!$debug);
104            print STDERR "DEBUG: ",@_;
105    }
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 ) || 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_%'  
         ";  
         my $sth = $mdbh->prepare($sql);  
         $sth->execute() || die;  
         while(my $row = $sth->fetchrow_hashref()) {  
                 push @tables,$row->{table};  
         }  
 }  
115    
116  print "Comparing tables: ",join(", ",@tables),"\n" if ($debug);  debug "Comparing tables: ".join(", ",@tables)."\n";
117    
118  my $cols;  my $cols;
119  my $diff_total = 0;  my $diff_total = 0;
120    
121  foreach my $table (@tables) {  foreach my $table (@tables) {
122    
123          my ($sth);          my $sth;
   
         # find table oid  
         $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;  
         }  
   
         my $oid = $row->{oid};  
124    
125          # diff schema          # diff schema
126    
# Line 162  foreach my $table (@tables) { Line 130  foreach my $table (@tables) {
130          my @cols_test;  # all colums to test (without skipped)          my @cols_test;  # all colums to test (without skipped)
131          my @cols;       # all colums (for insert)          my @cols;       # all colums (for insert)
132    
         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  
 ";  
133    
134          $sth = $mdbh->prepare($sql);          foreach my $row ($mscheme->explain_table($table)) {
         $sth->execute() || die;  
         while(my $row = $sth->fetchrow_hashref()) {  
135                  # attname | format_type | attnotnull | atthasdef | attnum                  # attname | format_type | attnotnull | atthasdef | attnum
136    
137                  push @cols,$row->{attname};                  push @cols,$row->{attname};
# Line 193  ORDER BY a.attnum Line 151  ORDER BY a.attnum
151                          push @cols_null,$row->{attname};                          push @cols_null,$row->{attname};
152                  }                  }
153          }          }
         $sth->finish();  
154    
155          if ($debug) {          if ($debug) {
156                  print STDERR "table $table [$oid] not null: (",join(", ",@cols_notnull),")";                  print STDERR "DEBUG: table $table not null cols: (",join(", ",@cols_notnull),")";
157                  print STDERR " - null: (",join(", ",@cols_null),")" if (@cols_null);                  print STDERR " - null cols: (",join(", ",@cols_null),")" if (@cols_null);
158                  print STDERR " - skip: (",join(", ",@cols_skip),")" if (@cols_skip);                  print STDERR " - skip cols: (",join(", ",@cols_skip),")" if (@cols_skip);
159                  print STDERR "\n";                  print STDERR "\n";
160          }          }
161    
# Line 228  ORDER BY Line 185  ORDER BY
185          debug_sql($sql);          debug_sql($sql);
186          $sth = $mdbh->prepare($sql);          $sth = $mdbh->prepare($sql);
187          $sth->execute() || die;          $sth->execute() || die;
188          $row = $sth->fetchrow_hashref();          my $row = $sth->fetchrow_hashref();
189          if ($row) {          if ($row) {
190                  $sql="                  $sql="
191                  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";                  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";
# Line 287  ORDER BY Line 244  ORDER BY
244    
245          my $order = sql_order(@cols_pk);          my $order = sql_order(@cols_pk);
246          $msql .= $order;          $msql .= $order;
247          $ssql .= sql_where(@cols_pk) . $order;          $ssql .= $order;
248    
249          debug_sql($msql);          debug_sql($msql);
         debug_sql($ssql);  
250    
251          my $msth = $mdbh->prepare($msql) || die;          my $msth = $mdbh->prepare($msql) || die;
252          $msth->execute() || die;          $msth->execute() || die;
253    
254          my $ssth = $sdbh->prepare($ssql) || die;          my $ssth = $sdbh->prepare($ssql) || die;
255            $ssth->execute() || die;
256    
257          my $diff_row = 0;          my $diff_row = 0;
258    
259          my ($mrow,$srow);          my ($mrow,$srow);
260          my ($have_mrow,$have_srow) = (0,0);          # have_*
261          my @pk_val;          use constant NO_ROW => 0;
262            use constant FETCH_ROW => 1;
263            use constant HAVE_ROW => 2;
264            my ($have_mrow,$have_srow) = (FETCH_ROW,FETCH_ROW);
265    
266            while ($have_mrow != NO_ROW || $have_srow != NO_ROW) {
267    
268                    debug "have mrow: $have_mrow srow: $have_srow\n";
269    
270                    sub pk_val {
271                            my $row = shift || die "need row";
272                            my @cols = shift || die "need cols";
273                            my @val;
274                            foreach my $col (@cols) {
275                                    push @val,$row->{$col};
276                            }
277                            return @val;
278                    }
279    
         my $more_rows = 1;  
         while (!$have_mrow || !$have_srow) {  
280                  # fetch row from master                  # fetch row from master
281                  if (!$have_mrow) {                  if ($have_mrow == FETCH_ROW) {
282                          print "fetch row from master [$more_rows]: $msql\n" if ($debug);                          debug "fetch row from master: $msql\n";
283                          $mrow = $msth->fetchrow_hashref();                          $mrow = $msth->fetchrow_hashref();
284                          debug_row($mrow,@cols);                          debug_row($mrow,@cols);
285    
286                          if ($mrow) {                          if ($mrow) {
287                                  # fill-in primary key values                                  # fill-in primary key values
288                                  @pk_val = ();                                  $have_mrow = HAVE_ROW;
                                 foreach my $col (@cols_pk) {  
                                         push @pk_val,$mrow->{$col};  
                                 }  
                                 $have_mrow = 1;  
289                          } else {                          } else {
290                                  $have_mrow = 0;                                  $have_mrow = NO_ROW;
291                          }                          }
292                  }                  }
293    
294                  # fetch row from slave                  # fetch row from slave
295                  if (!$have_srow) {                  if ($have_srow == FETCH_ROW) {
296                          print "fetch row from slave [$more_rows]: $ssql\n" if ($debug);                          debug "fetch row from slave: $ssql\n";
                         $ssth->execute(@pk_val) || die;  
297                          $srow = $ssth->fetchrow_hashref();                          $srow = $ssth->fetchrow_hashref();
298                          debug_row($srow,@cols);                          debug_row($srow,@cols);
299                          if ($srow) {                          if ($srow) {
300                                  $have_srow = 1;                                  $have_srow = HAVE_ROW;
301                          } else {                          } else {
302                                  $have_srow = 0;                                  $have_srow = NO_ROW;
303                          }                          }
304                  }                  }
305    
306                  # end of this table?                  debug "have mrow: $have_mrow srow: $have_srow\n";
                 if (!$have_mrow && !$have_srow) {  
                         last;  
                 }  
307    
308                  # insert into slave database                  # insert into slave database
309                  sub sql_insert {                  sub sql_insert {
# Line 376  ORDER BY Line 340  ORDER BY
340                          return $sql;                          return $sql;
341                  }                  }
342    
343                    # update row in slave database
344                    sub sql_update {
345                            my $table = shift @_ || die "need table as argument";
346                            my $col = shift @_ || die "need col to update";
347                            my $val = shift @_ || die "need new val";
348                            my @cols_pk = @_ || die "need pk idenitifier";
349    
350                            my $sql = "udate $table set $col=".$mdbh->quote($val);
351                            debug_sql($sql);
352                            return $sql;
353                    }
354                  # master        slave                  # master        slave
355                  # 1     =       1       test                  # 1     =       1       test
356                  # 1     <       2       insert mrow                  # 1     <       2       insert mrow
# Line 387  ORDER BY Line 362  ORDER BY
362    
363                  # check key cols for row                  # check key cols for row
364                  foreach my $col (@cols_pk) {                  foreach my $col (@cols_pk) {
365                          if ( (!$mrow && $srow) || ($mrow && $srow && ($mrow->{$col} gt $srow->{$col})) ) {                          if ( ($have_mrow == NO_ROW && $have_srow == HAVE_ROW) ||
366                                    ($have_mrow == HAVE_ROW && $have_srow == HAVE_ROW && $mrow->{$col} gt $srow->{$col}) ) {
367                                  $diff_row++;                                  $diff_row++;
368                                  $pk_same = 0;                                  $pk_same = 0;
369                                  print sql_delete($table,$srow,@cols_pk),"\n";                                  print STDERR "EXTRA row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($srow,@cols_pk)).")\n" if ($verbose);
370                                  $have_srow = 0; # fetch new slave row                                  print sql_delete($table,$srow,@cols_pk),";\n";
371                                    $have_srow = FETCH_ROW;
372                                  last;                                  last;
373                          } elsif ( ($mrow && !$srow) || ($mrow && $srow && ($mrow->{$col} lt $srow->{$col})) ) {                          } elsif ( ($have_mrow == HAVE_ROW && $have_srow == NO_ROW) ||
374                                    ($have_mrow == HAVE_ROW && $have_srow == HAVE_ROW && $mrow->{$col} lt $srow->{$col}) ) {
375                                  $diff_row++;                                  $diff_row++;
376                                  $pk_same = 0;                                  $pk_same = 0;
377                                  print sql_insert($table,$mrow,@cols),"\n";                                  print STDERR "MISSING row in table '$table' pk: [".join(",",@cols_pk)."] value (".join(",",pk_val($mrow,@cols_pk)).")\n" if ($verbose);
378                                  $have_mrow = 0;                                  print sql_insert($table,$mrow,@cols),";\n";
379                                    $have_mrow = FETCH_ROW;
380                                  last;                                  last;
381                          }                          }
382                  }                  }
383    
384                  if ($pk_same) {                  if ($pk_same && $have_mrow == HAVE_ROW && $have_srow == HAVE_ROW) {
385                          # check non-key cols for row                          # check non-key cols for row
386                          foreach my $col (@cols_cmp) {                          foreach my $col (@cols_cmp) {
387                                  if ($mrow->{$col} ne $srow->{$col}) {                                  if ($mrow->{$col} ne $srow->{$col}) {
388                                          $diff_row++;                                          $diff_row++;
389                                          print STDERR "DIFF in table '$table' row ($col): [".join(",",@pk_val)."] '$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);
390                                          print sql_delete($table,$srow,@cols_pk),"\n";                                          print sql_update($table,$col,$mrow->{$col},@cols_pk),";\n";
                                         print sql_insert($table,$mrow,@cols),"\n";  
391                                  }                                  }
392                          }                          }
393                            $have_mrow = FETCH_ROW;
394                            $have_srow = FETCH_ROW;
395                  }                  }
396          }          }
397    
# Line 419  ORDER BY Line 399  ORDER BY
399          $diff_total += $diff_row;          $diff_total += $diff_row;
400  }  }
401    
402  print STDERR "$diff_total differences in all tables\n" if ($verbose && $diff_total > 0);  if ($verbose) {
403            if ($diff_total == 0) {
404                    print STDERR "databases are same";
405            } elsif ($diff_total > 0) {
406                    print STDERR "$diff_total differences in all tables\n";
407            } else {
408                    die "this shouldn't happend. please report a bug!";
409            }
410    }
411    
412  $mdbh->disconnect();  $mdbh->disconnect();
413  $sdbh->disconnect();  $sdbh->disconnect();

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.4

  ViewVC Help
Powered by ViewVC 1.1.26