(D:/Yada.SQLite - database on a "spinner"):    the code took:789 wallclock secs ( 6.38 usr + 17.17 sys = 23.55 CPU) (C:/Yada.SQLite - database on a 'SSD'):    the code took:101 wallclock secs ( 3.70 usr + 16.78 sys = 20.49 CPU) (RAM drive - database on a 10 gig RAM drive)    the code took: 14 wallclock secs ( 2.89 usr +  9.47 sys = 12.36 CPU) #### (D:/Yada.SQLite)    the code took: 2 wallclock secs ( 1.41 usr +  0.00 sys =  1.41 CPU) (C:/Yada.SQLite)    the code took: 1 wallclock secs ( 1.31 usr +  0.00 sys =  1.31 CPU) (R:/Yada.SQlite - RAM drive)     the code took: 2 wallclock secs ( 1.36 usr +  0.00 sys =  1.36 CPU) #### package Log::Log4perl::Appender::DBI_eeks v0.00.01; # Purpose : Just to see how subclassing Log::Log4perl::Appender::DBI is done # Keywords : SQLite in-memory, # NB : # Notes : Note use of supplemental DBI::db:: # : Note the above superceded by inlining the code for _setup, _teardown ## no critic (EmptyQuotes,ProhibitParensWithBuiltins,ProhibitPostfixControls,ProhibitUnlessBlocks,PostfixControls,RequireCarping) ## no critic (RequireDotMatchAnything,RequireExtendedFormatting,RequireLineBoundaryMatching,RequirePodSections) use 5.032001; use warnings; use parent 'Log::Log4perl::Appender::DBI'; use Benchmark; use Carp; use Data::Alias; use Data::Dumper; use DBI; use English qw(-no_match_vars); use Readonly; Readonly my $FALSE => !!0; Readonly my $THREE => 3; Readonly my $TRUE => !!1; use Syntax::Keyword::Try qw( try :experimental(typed) );; use Time::HiRes; my ($MASTER); my ($error,$sql,@tablename_a); sub _init { ;my $subname=(caller 0)[$THREE]; ;warn "$subname called."; #;warn Data::Dumper->new([\@_],[qw(*_)])->Deepcopy(1)->Indent(1)->Maxdepth(3)->Sortkeys(1)->Dump(),q{ }; my $self=shift; my %params = @_; if ($params{dbh}) { $self->{dbh}=$params{dbh}; } elsif ($params{datasource} !~ m{\Qdbi:SQLite:dbname=\E(?.*)$}i) { # Not OUR speciality $self->SUPER::_init(@_); } else { # OUR speciality my $t0=Benchmark->new; #;warn Data::Dumper->new([\%LAST_PAREN_MATCH],[qw(*+)])->Deepcopy(1)->Indent(1)->Maxdepth(3)->Sortkeys(1)->Dump(),q{ }; $MASTER=$LAST_PAREN_MATCH{dbfile}; substr($params{datasource},$LAST_MATCH_START[1])=q{:memory:}; $self->{connect}=sub { DBI->connect(@params{qw(datasource username password)}, {PrintError => 0, $params{attrs} ? %{$params{attrs}} : ()}) or croak "Log4perl: $DBI::errstr"; }; $self->{dbh}=$self->{connect}->(); ########################################################################## #$self->{dbh}->_setup(); try { # Replicating the schema of $MASTER # Attach master database $self->{dbh}->do($sql=<<"_ATTACH_"); ATTACH DATABASE '$MASTER' as master; _ATTACH_ # replicate tables (my $sth=$self->{dbh}->prepare($sql=<<"_SELECT_"))->execute(); SELECT * FROM master.sqlite_schema; -- WHERE type = 'table'; _SELECT_ my $field_aref=$sth->{NAME}; my %_h; while (my $value_aref=$sth->fetchrow_arrayref()) { @_h{@{$field_aref}}=@{$value_aref}; $self->{dbh}->do($sql=$_h{sql}); push @tablename_a,$_h{tbl_name} if ($_h{type} =~ m{table$}); }; $sth->finish(); } catch ($error) { confess $error; }; ########################################################################## $self->{_RAM}=1; warn "$subname took: ",timestr(timediff(Benchmark->new,$t0)),"\n"; }; return; }; # sub _init: ok. sub DESTROY { ;my $subname=(caller 0)[$THREE]; ;warn "$subname called."; my $self=shift; no warnings ('experimental::lexical_subs'); my sub _verify_integrity { ;my $subname=(caller 0)[$THREE]; use warnings; ;warn "$subname called."; Data::Alias::alias my $dbh=$self->{dbh}; (my $sth=$dbh->prepare('PRAGMA integrity_check'))->execute(); my $row; while (my $_aref=$sth->fetchrow_arrayref()) { #=# TRACE [ IntegrityOK=>\$_aref ]; return $TRUE if (++$row == 1 && $_aref->[0] eq 'ok'); }; warn 'Database integrity could NOT be validated --- backup will not be updated!'; return $FALSE; }; # sub _verify_integrity: unless ($self->{_RAM} && $self->{dbh}) { # Not our speciality $self->SUPER::DESTROY(@_); } else { # Our speciality my $t0=Benchmark->new; ########################################################################## #$self->{dbh}->_teardown(); try { _verify_integrity(); # Attach $sql=<<"_ATTACH_"; -- NB: since \$MASTER might have a [.] \$MASTER must be quoted! -- ATTACH DATABASE '$MASTER' AS master; BEGIN TRANSACTION; _ATTACH_ # insert then delete $sql.=<<"_INSERT_" INSERT INTO master.$_ SELECT * FROM main.$_; _INSERT_ for (@tablename_a); $sql.=<<"_DELETE_" DELETE FROM main.$_; _DELETE_ for (@tablename_a); $sql.=<<"_DETACH_"; END TRANSACTION; DETACH DATABASE master; _DETACH_ $self->{dbh}->{sqlite_allow_multiple_statements}=1; $self->{dbh}->do($sql); $self->{dbh}->{sqlite_allow_multiple_statements}=0; } catch ($error) { confess $error; }; ########################################################################## $self->{dbh}->disconnect; delete $self->{_RAM}; warn "$subname took: ",timestr(timediff(Benchmark->new,$t0)),"\n"; }; return; }; # sub DESTROY: ok. unless (caller) { ...; } else { 0**0; }; =scratch =cut __DATA__