From f069af5d60587c93efd7c190706f08b81d6fad1f Mon Sep 17 00:00:00 2001 From: Christoph Berg Date: Mon, 23 Mar 2015 15:52:49 +0100 Subject: [PATCH] Query all sequences per DB in parallel for action=sequence action=sequence used to open a new session for every sequence checked, which could be very slow. Fix by creating a single SQL statement using UNION ALL to query all sequences at once. --- check_postgres.pl | 19 ++++++++++++------- t/02_sequence.t | 15 ++++++++++++++- t/CP_Testing.pm | 3 ++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/check_postgres.pl b/check_postgres.pl index 5f78bbb8c..fbffae2c3 100755 --- a/check_postgres.pl +++ b/check_postgres.pl @@ -7274,12 +7274,15 @@ ORDER BY nspname, seqname, typname my %seqinfo; my %seqperf; my $multidb = @{$info->{db}} > 1 ? "$db->{dbname}." : ''; - for my $r (@{$db->{slurp}}) { + my @seq_sql; + for my $r (@{$db->{slurp}}) { # for each sequence, create SQL command to inspect it my ($schema, $seq, $seqname, $typename) = @$r{qw/ nspname seqname safename typname /}; next if skip_item($seq); my $maxValue = $typename eq 'int2' ? $MAXINT2 : $typename eq 'int4' ? $MAXINT4 : $MAXINT8; - $SQL = qq{ -SELECT last_value, slots, used, ROUND(used/slots*100) AS percent, + my $seqname_l = $seqname; + $seqname_l =~ s/'/''/g; # SQL literal quoting (name is already identifier-quoted) + push @seq_sql, qq{ +SELECT '$seqname_l' AS seqname, last_value, slots, used, ROUND(used/slots*100) AS percent, CASE WHEN slots < used THEN 0 ELSE slots - used END AS numleft FROM ( SELECT last_value, @@ -7287,10 +7290,10 @@ FROM ( CEIL((last_value-min_value::numeric+1)/increment_by::NUMERIC) AS used FROM $seqname) foo }; - - my $seqinfo = run_command($SQL, { target => $db }); - my $r2 = $seqinfo->{db}[0]{slurp}[0]; - my ($last, $slots, $used, $percent, $left) = @$r2{qw/ last_value slots used percent numleft / }; + } + my $seqinfo = run_command(join("\nUNION ALL\n", @seq_sql), { target => $db }); # execute all SQL commands at once + for my $r2 (@{$seqinfo->{db}[0]{slurp}}) { # now look at all results + my ($seqname, $last, $slots, $used, $percent, $left) = @$r2{qw/ seqname last_value slots used percent numleft / }; if (! defined $last) { ndie msg('seq-die', $seqname); } @@ -9825,6 +9828,8 @@ Items not specifically attributed are by GSM (Greg Sabino Mullane). Declare POD encoding to be utf8. (Christoph Berg) + Query all sequences per DB in parallel for action=sequence. (Christoph Berg) + =item B September 24, 2013 Fix issue with SQL steps in check_pgagent_jobs for sql steps which perform deletes diff --git a/t/02_sequence.t b/t/02_sequence.t index d42187f61..b1fa3ea31 100644 --- a/t/02_sequence.t +++ b/t/02_sequence.t @@ -6,7 +6,7 @@ use 5.006; use strict; use warnings; use Data::Dumper; -use Test::More tests => 10; +use Test::More tests => 12; use lib 't','.'; use CP_Testing; @@ -45,6 +45,7 @@ if ($ver < 80100) { my $seqname = 'cp_test_sequence'; $cp->drop_sequence_if_exists($seqname); $cp->drop_sequence_if_exists("${seqname}2"); +$cp->drop_sequence_if_exists("${seqname}'\"evil"); $t=qq{$S works when no sequences exist}; like ($cp->run(''), qr{OK:.+No sequences found}, $t); @@ -83,4 +84,16 @@ like ($cp->run('--critical=22%'), qr{CRITICAL:.+public.cp_test_sequence=33% \(ca $t=qq{$S returns correct information with MRTG output}; is ($cp->run('--critical=22% --output=mrtg'), "33\n0\n\npublic.cp_test_sequence\n", $t); +# create second sequence +$dbh->do("CREATE SEQUENCE ${seqname}2"); +$dbh->commit(); +$t=qq{$S returns correct information for two sequences}; +like ($cp->run(''), qr{OK:.+public.cp_test_sequence=33% .* \| .*${seqname}=33%.*${seqname}2=0%}, $t); + +# test SQL quoting +$dbh->do(qq{CREATE SEQUENCE "${seqname}'""evil"}); +$dbh->commit(); +$t=qq{$S handles SQL quoting}; +like ($cp->run(''), qr{OK:.+'public."${seqname}''""evil"'}, $t); # extra " and ' because name is both identifier+literal quoted + exit; diff --git a/t/CP_Testing.pm b/t/CP_Testing.pm index 28ff60b3f..c473c9f75 100644 --- a/t/CP_Testing.pm +++ b/t/CP_Testing.pm @@ -700,7 +700,8 @@ sub drop_sequence_if_exists { $SQL = q{SELECT count(*) FROM pg_class WHERE relkind = 'S' AND relname = } . $dbh->quote($name); my $count = $dbh->selectall_arrayref($SQL)->[0][0]; if ($count) { - $dbh->do("DROP SEQUENCE $name"); + $name =~ s/"/""/g; + $dbh->do("DROP SEQUENCE \"$name\""); $dbh->commit(); } return; -- 2.30.2