DBIx-TempDB
view release on metacpan or search on metacpan
lib/DBIx/TempDB/Util.pm view on Meta::CPAN
sub parse_sql {
my ($type, $sql) = @_;
$type = $type->canonical_engine if blessed $type;
return _parse_mysql($sql) if $type eq 'mysql';
return $sql;
}
sub _dsn_for_mysql {
my ($url, $database_name) = @_;
my %opt = %{$url->query_form_hash};
my ($dsn, @userinfo);
$url = URI::db->new($url);
$url->dbname($database_name);
$url->query(undef);
$dsn = $url->dbi_dsn;
@userinfo = ($url->user, $url->password);
$opt{AutoCommit} //= 1;
$opt{AutoInactiveDestroy} //= 1;
$opt{PrintError} //= 0;
$opt{RaiseError} //= 1;
$opt{mysql_enable_utf8} //= 1;
return $dsn, @userinfo[0, 1], \%opt;
}
sub _dsn_for_pg {
my ($url, $database_name) = @_;
my %opt = %{$url->query_form_hash};
my ($dsn, @userinfo);
$url = URI::db->new($url);
$url->dbname($database_name);
$url->query(undef);
if (my $service = delete $opt{service}) { $url->query_param(service => $service) }
$dsn = $url->dbi_dsn;
@userinfo = ($url->user, $url->password);
$opt{AutoCommit} //= 1;
$opt{AutoInactiveDestroy} //= 1;
$opt{PrintError} //= 0;
$opt{RaiseError} //= 1;
return $dsn, @userinfo[0, 1], \%opt;
}
sub _dsn_for_sqlite {
my ($url, $database_name) = @_;
my %opt = %{$url->query_form_hash};
$url = URI::db->new($url);
$url->dbname($database_name);
$url->query(undef);
my $dsn = $url->dbi_dsn;
$opt{AutoCommit} //= 1;
$opt{AutoInactiveDestroy} //= 1;
$opt{PrintError} //= 0;
$opt{RaiseError} //= 1;
$opt{sqlite_unicode} //= 1;
return $dsn, "", "", \%opt;
}
sub _on_process_end_double_fork {
my $code = shift;
my $ppid = $$;
warn "[TempDB:$$] Watching process using double fork.\n" if DEBUG;
local $SIG{CHLD} = 'DEFAULT';
pipe(my ($READER), my ($WRITER)) or confess "Couldn't create pipe: $!";
# Parent
if (my $pid_1 = fork // confess "Couldn't fork: $!") {
my $pid_2;
# Wait around until the second fork is done so that when we return from
# here there are no new child processes that could mess things up if the
# calling process does any process handling.
close $WRITER;
$pid_2 = <$READER>;
$pid_2 = $pid_2 =~ m!(\d+)! ? $1 : undef;
waitpid $pid_1, 0;
confess "Couldn't get pid_2 from $pid_1." unless $pid_2;
warn "[TempDB:$$] Double forked from $$ to $pid_1 to $pid_2\n" if DEBUG;
return DBIx::TempDB::Guard->new(sub { kill TERM => $pid_2 }, $pid_2);
}
# Child #1
# Detach completely from parent by creating our own session and process
# group, closing all filehandles and forking a second time.
$0 = "dbix-on-process-end-$ppid";
close $READER;
$DB::CreateTTY = 0;
POSIX::setsid() != -1 or die "[TempDB:$$] Couldn't become session leader: $!\n";
if (my $pid_2 = fork // die "[TempDB:$$] Couldn't fork: $!") {
print $WRITER "$pid_2\n";
close $WRITER;
POSIX::_exit(0);
}
# Child #2
warn "[TempDB:$ppid/$$] Double fork waiting on signals or parent to go away.\n" if DEBUG;
_on_process_signals($code);
sleep KILL_SLEEP_INTERVAL while kill 0, $ppid;
local $ENV{DBIX_TEMP_DB_SIGNAL} = 'parent';
$code->();
exit;
}
sub _on_process_end_fork {
my $code = shift;
my $ppid = $$;
# Parent
warn "[TempDB:$$] Watching process using single fork.\n" if DEBUG;
pipe(my ($READER), my ($WRITER)) or confess "Couldn't create pipe: $!";
defined(my $pid = fork) or confess "Couldn't fork: $!";
return DBIx::TempDB::Guard->new(sub { close $WRITER }, $pid) if $pid;
( run in 1.961 second using v1.01-cache-2.11-cpan-39bf76dae61 )