Skip to content

Instantly share code, notes, and snippets.

@nikoma
Created February 11, 2013 10:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikoma/4753784 to your computer and use it in GitHub Desktop.
Save nikoma/4753784 to your computer and use it in GitHub Desktop.
Migrates data from MySQL to Postgresql
#!/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 = 'user';
my $srcPass = '';
my $srcDbName = 'database_name';
my $srcDbHost = 'localhost';
my $dstUser = 'user';
my $dstPass = '';
my $dstDbName = 'database_name';
my $dstDbHost = 'localhost';
### 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment