107 lines
3.2 KiB
Perl
Executable File
107 lines
3.2 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
use charnames ':full'; # only necessary before v5.16
|
|
use strict;
|
|
use v5.10;
|
|
use warnings;
|
|
|
|
use DBIx::SimpleConnect;
|
|
use Encode qw(:fallbacks encode);
|
|
|
|
my $db = shift // "default";
|
|
|
|
my $dbh = DBIx::SimpleConnect->connect($db, {RaiseError => 1});
|
|
|
|
my $sth
|
|
= $dbh->prepare("
|
|
select locks_blocking.pid as blocking_pid,
|
|
query_blocking.query as blocking_query,
|
|
query_blocking.usename as blocking_username,
|
|
locks_blocked.pid as blocked_pid,
|
|
query_blocked.query as blocked_query,
|
|
query_blocked.usename as blocked_username
|
|
from pg_locks locks_blocked join pg_locks locks_blocking
|
|
on (locks_blocked.locktype='relation' and locks_blocking.locktype='relation' and locks_blocked.database=locks_blocking.database and locks_blocked.relation=locks_blocking.relation
|
|
or locks_blocked.locktype='transactionid' and locks_blocking.locktype='transactionid' and locks_blocked.transactionid=locks_blocking.transactionid
|
|
-- don't know how to handle virtualxid
|
|
)
|
|
join pg_stat_activity query_blocked on (locks_blocked.pid=query_blocked.pid)
|
|
join pg_stat_activity query_blocking on (locks_blocking.pid = query_blocking.pid)
|
|
where locks_blocking.granted and not locks_blocked.granted
|
|
"
|
|
);
|
|
$sth->execute();
|
|
my $locks = $sth->fetchall_arrayref();
|
|
|
|
|
|
binmode STDOUT, ":encoding(UTF-8)";
|
|
say "<!DOCTYPE html>";
|
|
say "<html>";
|
|
say "<head>";
|
|
say "<meta charset='UTF-8'/>";
|
|
say "<style type='text/css'>";
|
|
say "table { border-collapse: collapse; border-style: solid; border-width: 1px; }";
|
|
say "th { vertical-align: baseline; border-style: solid; border-color: #888; border-width: 1px; }";
|
|
say "td {";
|
|
say " vertical-align: baseline;";
|
|
say " border-style: solid;";
|
|
say " border-color: #888;";
|
|
say " border-width: 1px;";
|
|
say " white-space: pre-wrap }";
|
|
say "}";
|
|
say "</style>";
|
|
say "</head>";
|
|
say "<body>";
|
|
|
|
if (@$locks) {
|
|
say "<table>";
|
|
say "<tr>";
|
|
say map {
|
|
"<th>" . xmlencode($_) . "</th>"
|
|
} @{$sth->{NAME}};
|
|
say "</tr>";
|
|
for my $lk (@$locks) {
|
|
say "<tr>";
|
|
say map {
|
|
"<td>"
|
|
. (defined($_) ? xmlencode($_) : '<em>NULL</em>')
|
|
. "</td>"
|
|
} @$lk;
|
|
say "</tr>";
|
|
}
|
|
|
|
say "</table>";
|
|
} else {
|
|
say "<p>No locks \N{WHITE SMILING FACE}</p>";
|
|
}
|
|
say "</body>";
|
|
say "</html>";
|
|
exit(0);
|
|
|
|
sub xmlencode {
|
|
my ($s) = @_;
|
|
return encode("us-ascii", $s, FB_XMLCREF);
|
|
}
|
|
|
|
sub format_pretty {
|
|
my ($s) = @_;
|
|
|
|
if (!defined $s) { return '<em>NULL</em>' }
|
|
$s = xmlencode($s);
|
|
|
|
my @s = split(/\n/, $s);
|
|
while (@s && $s[0] eq "") { shift @s }
|
|
while (@s && $s[-1] eq "") { pop @s }
|
|
my $leading_space = "+Inf";
|
|
for (@s) {
|
|
my $sp = /^(\s+)/;
|
|
if (length($sp) < $leading_space) {
|
|
$leading_space = length($sp);
|
|
}
|
|
}
|
|
for (@s) {
|
|
$_ = substr($_, $leading_space);
|
|
}
|
|
$s = join("\n", @s);
|
|
return $s;
|
|
}
|