This is a perl script I’ve used to move data from mysql 5.1 to postgres 9, this script doesn’t create a schema, it only grabs the data from mysql and try to put it on the same table in postgres.
The only requirement is DBI for mysql and postgres.
- #!/usr/bin/perl
- #
- # this script moves all the data from mysql to postgres
- # modules required are:
- #
- # http://search.cpan.org/~timb/DBI-1.616/DBI.pm
- #
- # please change the dsn, srcUser/srcPass and dstUser/Pass variables.
-
- use DBI;
- use strict;
-
- my $srcUser = 'ivan';
- my $srcPass = '123';
- my $srcDbName = 'datatocopy';
- my $srcDbHost = 'mini';
-
- my $dstUser = 'ivan';
- my $dstPass = '456';
- my $dstDbName = 'migrateddata';
- my $dstDbHost = '192.168.1.145';
-
- ### do not modify ##
-
- my $srcDb = DBI->connect("dbi:mysql:database=$srcDbName;host=$srcDbHost", $srcUser, $srcPass) or die;
- my $dstDb = DBI->connect("dbi:Pg:database=$dstDbName;host=$dstDbHost", $dstUser, $dstPass) or die;
-
- ####main########
- print "Starting to move data from $srcDbHost to $dstDbHost\n";
- $srcDb->do("SET NAMES \'UTF8\'");
- $dstDb->do("SET CLIENT_ENCODING=\'UTF8\'") or die;
-
-
- my $srcTables = $srcDb->selectall_arrayref("SHOW TABLES");
- my $dstTables = $dstDb->selectall_hashref("SELECT * FROM pg_tables WHERE NOT tablename ~\'^(pg_|sql_)\'","tablename");
-
- my $seqlist = $dstDb->selectall_arrayref("SELECT RELNAME FROM pg_class WHERE relkind=\'S\'");
- my $seqmap;
- foreach my $s(@$seqlist) {
- my $seqname = $s->[0];
- if ($seqname=~/^(.*)_([a-z]+)_([a-z]+$)/) {
- my $item;
- $item->{seq}=$seqname;
- $item->{field}=$2;
- my $table = $1;
- if (exists $dstTables->{$table}) {
- push @{$seqmap->{$table}},$item;
- } else {
- print STDERR "WARN: cannot find table for sequence $seqname\n";
- }
- }
- }
- $dstDb->{AutoCommit}=0;
- my $totalRowCount = 0;
- foreach my $t(@$srcTables) {
- my $table = $t->[0];
- unless (exists $dstTables->{$table}) {
- print STDERR "WARN: table $table does not exists in dest db Pg:$dstDbName\n";
- next;
- }
- print "Clearing data from table $table in $dstDbHost\n";
- clear_table($dstDb,$table);
- next if $table=~/^cache/;
- next if $table=~/^locales/;
- print "Copying data from mysql table $table in $srcDbHost to postgres table $table in $dstDbHost\n";
- my $cnt = copy_table($srcDb,$dstDb,$table) unless $table=~/^cache/;
- $totalRowCount = $totalRowCount + $cnt;
- print "$cnt rows copied ($table)\n";
- init_seq($dstDb,$table,$seqmap->{$table}); # if (exists $seqmap->{$table});
- }
- print "Commiting changes \n";
- $dstDb->commit;
- print "$totalRowCount rows were copied.\n";
- exit 0;
-
-
- sub init_seq {
- my ($db,$table,$list)=@_;
- return unless $list;
- for my $item (@{$list}) {
- my $ref = $db->selectall_arrayref("SELECT MAX($item->{field}) FROM $table") or die;
- my $val = $ref->[0]->[0];
- if ($val) {
- $db->do("SELECT SETVAL(\'$item->{seq}\',$val)") or die;
- }
- }
- }
-
- sub clear_table {
- my ($dbh,$table)=@_;
- return unless $table;
- $dbh->do("DELETE FROM $table") or die;
- }
-
- sub copy_table {
- my ($srcDb,$dstDb,$table)=@_;
- die unless $table;
- my $slf = $srcDb->prepare("select * from $table limit 1");
- my $rows = $slf->execute() or die;
- return 0 if $rows < 1;
- my $rec1 = $slf->fetchrow_hashref;
- $slf->finish;
- my @fieldnames = sort keys %$rec1;
- my @qm = map { '?'} @fieldnames;
- my $ins = $dstDb->prepare("INSERT INTO $table (".join(",",@fieldnames).") VALUES(".join(",",@qm).")");
- my $sel = $srcDb->prepare("SELECT * FROM $table");
- $sel->execute or die;
- my $cnt = 0;
- while (my $data = $sel->fetchrow_hashref) {
- $ins->execute(map {$data->{$_}} @fieldnames) or die;
- $cnt++;
- }
- $ins->finish;
- $sel->finish;
- return $cnt;
- }