Lors d’une migration oracle 8.0.6 vers 9i, nous avions besoin de vérifier que les objets présents dans une base étaient bien présent dans une autre.
Le script génère un csv pour être transforme en feuille Excel. Le tout avec une joli barre de progression.
#!/usr/bin/env perl use strict; #use warnings; use Term::ProgressBar; use DBI; my $h = { nine => { env => '/produits/oracleb/920/products', host =>'host1', dbname =>'dbname1', user =>'user1', pass =>'pass1', port => '1522', }, height => { env => '/produits/oraclea/806/products', host =>'host2', dbname =>'dbname2', user =>'user2', pass =>'pass2', port => '1521', }, }; my $sql = { count_all_table => 'select COUNT(table_name) from user_tables', get_all_table => 'select table_name from user_tables', get_all_objs => 'select OBJECT_TYPE,OBJECT_NAME ' . 'from dba_objects ORDER BY OBJECT_NAME,OBJECT_TYPE', get_table_col => 'select ' . 'COLUMN_ID, COLUMN_NAME, NULLABLE, ' . 'DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE ' . 'from user_tab_columns ' . 'where TABLE_NAME=? ORDER BY COLUMN_ID', get_dba_table_col => 'select ' . 'COLUMN_ID, COLUMN_NAME, NULLABLE, ' . 'DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE ' . 'from dba_tab_columns ' . 'where TABLE_NAME=? ORDER BY COLUMN_ID', }; #DBI->trace(15, '/tmp/dbi_trace'); sub dbconnect { my $ver = shift; # $ENV{ORACLE_HOME} = $h->{$ver}->{env}; my $dbh = DBI->connect(join('', "dbi:Oracle:", "host=$h->{$ver}->{host}", ";sid=$h->{$ver}->{dbname}", defined $h->{$ver}->{port} ? ";port=$h->{$ver}->{port}" : ""), "$h->{$ver}->{user}/$h->{$ver}->{pass}", '') or die "Unable to connect to $h->{$ver}->{dbname}: $DBI::errstr\n"; # print STDERR "Connected $ver\n"; $h->{$ver}->{dbh} = $dbh; foreach my $k (keys %{$sql}) { $h->{$ver}->{sql}->{$k} = $dbh->prepare($sql->{$k}); } return ($dbh); } sub dbexecute { my $ver = shift; my $sql_name = shift; # print STDERR "execute $sql_name version $ver\n"; my $sth = $h->{$ver}->{sql}->{$sql_name}; my $rv = $sth->execute(@_); $sth->fetchall_arrayref(); } sub describe_table { my $ver = shift; my $t = shift; # print STDERR "execute describe $t version $ver\n"; my $sth = $h->{$ver}->{dbh}->column_info(undef, undef, $t, undef, { TABLE_NAME => $t, }); my $res = $sth->fetchall_arrayref(); die unless defined $res; return ($res); } sub array_comp { my ($a, $b) = @_; print "a: $a\n"; print "b: $b\n"; my $i = 0; while (defined $a->[$i] or defined $b->[$i]) { # unless ((defined $a->[$i] and defined $b->[$i]) or # ($a->[$i] eq $b->[$i])){ # print "$i =>", join(':', # map { defined $_ ? $_ : "NULL"} # ($a->[$i], $b->[$i])), "\n" ; # } return ([$i, $a->[$i], $b->[$i]]) unless defined $a->[$i] and defined $b->[$i]; return ([$i, $a->[$i], $b->[$i]]) unless $a->[$i] eq $b->[$i]; return undef if ($b->[$i] eq ""); $i++ } return undef; } sub compare_table_old { my ($p, $table, @vers) = @_; my $table_info = []; foreach my $ver (@vers) { $p->update($p->next_call); push @$table_info, describe_table($ver, $table); } my $i = []; $p->update($p->next_call); while ( @{$table_info->[0]} and @{$table_info->[1]} ) { #print scalar @{$table_info->[0]}, " " , scalar @{$table_info->[1]}, "\n"; $i->[0] = shift @{$table_info->[0]}; $i->[1] = shift @{$table_info->[1]}; my $res = array_comp(@$i); $p->update($p->next_call) and return $res if defined $res; } $p->update($p->next_call); return undef; } sub compare_table { my ($p, $type, $table, @vers) = @_; my $table_info = []; foreach my $ver (@vers) { $p->update($p->next_call); my $ret = dbexecute($ver, $type, $table); # push @$table_info, describe_table($ver, $table); # print "ret: $ret\n"; my $info; foreach my $line (@$ret) { push @$info, join(' ', $line->[0], $line->[1], $line->[2] eq 'Y' ? "NULLABLE": " ", "$line->[3]($line->[4])[$line->[5]/$line->[6]]") ; } push @$table_info, $info; } my $i = []; my $res = undef; $p->update($p->next_call); $p->update($p->next_call) and return undef if not defined $table_info->[0] or not defined $table_info->[1]; while ( @{$table_info->[0]} and @{$table_info->[1]} ) { #print scalar @{$table_info->[0]}, " " , scalar @{$table_info->[1]}, "\n"; $i->[0] = shift @{$table_info->[0]}; $i->[1] = shift @{$table_info->[1]}; $res = $i->[0] eq $i->[1] ? undef : "$i->[0] => $i->[1]"; $p->update($p->next_call) and return $res if defined $res; } $p->update($p->next_call); return undef; } sub compare_table_list { my @vers = @_; my $r = {}; my $progress = Term::ProgressBar->new({name => 'Getting Tables', count => 2, ETA => 'linear', fh => \*STDERR, }); my $i = 0; foreach my $ver (@vers) { $progress->update(++$i); $r->{$ver}->{res} = dbexecute($ver, 'get_all_table'); } my $count = 0; map {$count += scalar @{$r->{$_}->{res}}} @vers; $progress = Term::ProgressBar->new({name => 'Sorting Tables', count => $count, ETA => 'linear', fh => \*STDERR, }); $i = 0; foreach my $ver (@vers) { # print "ref: $r->{$ver}->{res}\n"; foreach my $row (@{$r->{$ver}->{res}}) { my ($table) = @$row; $r->{table}->{$table}++; $r->{$ver}->{table}->{$table}++; $progress->update(++$i); } } print FILE_OUT "table;"; map { print FILE_OUT "$h->{$_}->{dbname};" } @vers; print FILE_OUT "\n"; $count = scalar keys %{$r->{table}}; $progress = Term::ProgressBar->new({name => 'Analysing Tables', count => $count * 4, ETA => 'linear', fh => \*STDERR, }); foreach my $table (sort keys %{$r->{table}}) { print FILE_OUT "$table;"; foreach my $ver (@vers) { my $line = defined $r->{$ver}->{table}->{$table} ? "presente;": "absente;"; print FILE_OUT $line; } if ($r->{table}->{$table} == 2) { my $res; $res = compare_table($progress, 'get_table_col', $table, @vers); if (defined $res) { print FILE_OUT "$res;"; } } else { my $nexti = $progress->next_call(4); # print "Count ", $count*4, " Next call => $i\n"; $progress->update($nexti); } print FILE_OUT "\n"; } print FILE_OUT "\nTotal des tables;"; foreach my $ver (@vers) { print FILE_OUT scalar keys %{$r->{$ver}->{table}}, ";"; } print FILE_OUT scalar keys %{$r->{table}}, ";\n"; } sub compare_objs_list { my @vers = @_; my $r = {}; my $progress = Term::ProgressBar->new({name => 'Getting Objects', count => 2, ETA => 'linear', fh => \*STDERR, }); my $i = 0; foreach my $ver (@vers) { $progress->update(++$i); $r->{$ver}->{res} = dbexecute($ver, 'get_all_objs'); } my $count = 0; map {$count += scalar @{$r->{$_}->{res}}} @vers; $progress = Term::ProgressBar->new({name => 'Sorting Objects', count => $count, ETA => 'linear', fh => \*STDERR, }); $i = 0; foreach my $ver (@vers) { # print "ref: $r->{$ver}->{res}\n"; foreach my $objs (@{$r->{$ver}->{res}}) { $r->{objs_name}->{$objs->[1]} = $objs; $r->{objs}->{$objs->[1]}++; $r->{$ver}->{objs}->{$objs->[1]}++; $progress->update(++$i); } } print FILE_OUT "object type; object type;"; map { print FILE_OUT "$h->{$_}->{dbname};" } @vers; print FILE_OUT "\n"; $count = scalar keys %{$r->{objs}}; $progress = Term::ProgressBar->new({name => 'Analysing Objects', count => $count * 4, ETA => 'linear', fh => \*STDERR, }); foreach my $objs (sort keys %{$r->{objs}}) { $objs = $r->{objs_name}->{$objs}; print FILE_OUT $objs->[0], ';', $objs->[1], ';'; foreach my $ver (@vers) { my $line = defined $r->{$ver}->{objs}->{$objs->[1]} ? "presente;": "absente;"; print FILE_OUT $line; } if ($r->{objs}->{$objs->[1]} == 2 and $objs->[1] eq 'TABLE') { my $res; $res = compare_table($progress, 'get_dba_table_col',$objs->[1], @vers); if (defined $res) { print FILE_OUT "$res;"; } } else { my $nexti = $progress->next_call(4); # print "Count ", $count*4, " Next call => $i\n"; $progress->update($nexti); } print FILE_OUT "\n"; } print FILE_OUT "\nTotal des objects;"; foreach my $ver (@vers) { print FILE_OUT scalar keys %{$r->{$ver}->{objs}}, ";"; } print FILE_OUT scalar keys %{$r->{objs}}, ";\n"; } sub dbconneting { my @vers = @_; my $progress = Term::ProgressBar->new({name => 'Connecting', count => scalar @vers, ETA => 'linear', fh => \*STDERR, }); my $i = 0; foreach my $ver (@vers) { dbconnect($ver); $progress->update(++$i); } } open FILE_OUT, ">list_objs.csv" or die; dbconneting(keys %$h); #compare_table_list(keys %$h); #user fashion compare_objs_list(keys %$h); #dba way