DBD-PgLite
view release on metacpan or search on metacpan
lib/DBD/PgLite/MirrorPgToSQLite.pm view on Meta::CPAN
&& $opt{where} !~ /^\s*(?:natural\s+)?join\s/i) {
$opt{where} = 'where '.$opt{where};
}
die "Incompatible options: 'append' and 'snapshot'" if $opt{append} && $opt{snapshot};
die "Need either database handle (pg_dbh) or DSN (pg_dsn)" unless $opt{pg_dbh} || $opt{pg_dsn};
my $disconnect = 0;
unless ($opt{pg_dbh}) {
$disconnect++;
$opt{pg_dbh} = DBI->connect(@opt{ qw(pg_dsn pg_user pg_pass) },{RaiseError=>1})
or die "Could not connect to PostgreSQL: $DBI::errstr";
}
my $fn = $opt{sqlite_file};
die "Need both list of source tables and a SQLite file" unless @{$opt{tables}} && $fn;
$|++ if $opt{verbose};
my $lockfile = "$fn.lock";
lockfile('create',$lockfile);
if (-f "$fn.tmp") {
warn "WARNING: Removing temp file $fn.tmp - apparently left over from a previous run\n";
unlink "$fn.tmp" or die "ERROR: Could not remove file.tmp: $!\n";
}
if ($opt{append}) {
unless (copy $fn, "$fn.tmp") {
warn "WARNING: Could not copy $fn to $fn.tmp for appending: $! - turning --append off\n";
$opt{append} = 0;
}
}
$opt{sl_dbh} = DBI->connect("dbi:SQLite:dbname=$fn.tmp",undef,undef,{RaiseError=>1});
my @tables = tablelist($opt{pg_dbh}, $opt{schema}, @{ $opt{tables} }); # handle regexp
print "MIRRORING ".scalar(@tables)." table(s):\n" if $opt{verbose};
my @views = viewlist($opt{pg_dbh}, $opt{schema}, @{ $opt{views} })
if grep { /^\/.+\/$/ } @{ $opt{views} };
eval {
if ($opt{snapshot}) {
$opt{pg_dbh}->do("set session characteristics as transaction isolation level serializable");
$opt{pg_dbh}->begin_work;
mirror_table($_,%opt) for @tables;
mirror_functions(%opt) if $opt{functions};
$opt{pg_dbh}->commit;
} else {
mirror_table($_,%opt) for @tables;
mirror_functions(%opt) if $opt{functions};
}
if (@views) {
print "CREATING ".scalar(@views)." view(s):\n" if $opt{verbose};
create_view($_,%opt) for @views;
}
print "done!\n" if $opt{verbose};
};
if ($@) {
lockfile('clear',$lockfile);
die $@;
}
$opt{pg_dbh}->disconnect if $disconnect;
$opt{sl_dbh}->disconnect;
if (-f $fn) {
copy $fn, "$fn.bak" or warn "WARNING: Could not make backup copy of $fn: $!\n";
}
move "$fn.tmp", $fn or die "ERROR: Could not move temporary SQLite file $fn.tmp to $fn";
lockfile('clear',$lockfile);
}
########## OTHER SUBROUTINES ###########
sub _commasplit {
my $list = shift;
return [] unless $list;
$list = [$list] unless ref $list;
my @new = split(/\s*,\s*/,join(',',@$list));
return \@new;
}
sub defaults {
my %defaults = (
verbose => 0,
pg_dsn => ($ENV{PGDATABASE} ? "dbi:Pg:dbname=$ENV{PGDATABASE}" : undef),
pg_user => ($ENV{PGUSER} || $ENV{USER}),
pg_pass => $ENV{PGPASSWORD},
schema => 'public',
tables => [],
sqlite_file => '',
where => '',
cachedir => '/tmp/sqlite_mirror_cache',
append => 0,
snapshot => 0,
indexes => 0,
views => [],
functions => 0,
page_limit => 5000, # each page is 8K
pg_dbh => undef,
);
$defaults{pg_dsn} ||= "dbi:Pg:dbname=$defaults{pg_user}" if $defaults{pg_user};
return %defaults;
}
sub mirror_table {
my ($tn,%opt) = @_;
my $sn = $opt{schema};
print " - $sn.$tn\n" if $opt{verbose};
my ($create,$colcnt) = get_schema($sn,$tn,%opt);
my $drop = '';
if ($opt{append}) {
$drop = $opt{sl_dbh}->selectrow_array("select name from sqlite_master where type = 'table' and name = ?",{},$tn);
$opt{sl_dbh}->do("drop table $tn") if $drop;
}
$opt{sl_dbh}->do($create);
my $pages = $opt{pg_dbh}->selectrow_array("select relpages from pg_class where relnamespace = (select oid from pg_namespace where nspname = ?) and relname = ?",{},$sn,$tn);
my $ins = $opt{sl_dbh}->prepare("insert into $tn values (". join(',', ("?") x $colcnt) . ")");
if ($pages > $opt{page_limit}) {
warn " pagelimit ($opt{page_limit}) kicks in for $sn.$tn ($pages)\n" if $opt{verbose};
my @pkey = $opt{pg_dbh}->primary_key(undef,$sn,$tn);
warn " (pkey is )".join(":",@pkey)."\n" if $opt{verbose};
if (@pkey) {
my $pkey_vals = $opt{pg_dbh}->selectall_arrayref("select ".join(', ', @pkey)." from $sn.$tn");
my $sql = "select * from $sn.$tn where ".join(" and ", map {"$_ = ?"} @pkey);
( run in 0.765 second using v1.01-cache-2.11-cpan-39bf76dae61 )