@@ -21,8 +21,20 @@ PostgresNode - class representing PostgreSQL server instance
2121 $node->restart('fast');
2222
2323 # run a query with psql
24- # like: psql -qAXt postgres -c 'SELECT 1;'
25- $psql_stdout = $node->psql('postgres', 'SELECT 1');
24+ # like:
25+ # echo 'SELECT 1' | psql -qAXt postgres -v ON_ERROR_STOP=1
26+ $psql_stdout = $node->psql_check('postgres', 'SELECT 1');
27+
28+ # Run psql with a timeout, capturing stdout and stderr
29+ # as well as the psql exit code. Pass some extra psql
30+ # options. If there's an error from psql raise an exception.
31+ my ($stdout, $stderr, $timed_out);
32+ my $cmdret = $psql_expert('postgres', 'SELECT pg_sleep(60)',
33+ stdout => \$stdout, stderr => \$stderr,
34+ timeout => 30, timed_out => \$timed_out,
35+ extra_params => ['--single-transaction'],
36+ on_error_die => 1)
37+ print "Sleep timed out" if $timed_out;
2638
2739 # run query every second until it returns 't'
2840 # or times out
@@ -69,6 +81,7 @@ use IPC::Run;
6981use RecursiveCopy;
7082use Test::More;
7183use TestLib ();
84+ use Scalar::Util qw( blessed) ;
7285
7386our @EXPORT = qw(
7487 get_new_node
@@ -780,11 +793,16 @@ sub teardown_node
780793
781794=item $node->psql(dbname, sql)
782795
783- Run a query with psql and return stdout, or on error print stderr .
796+ Run a query with psql and return stdout if psql returns with no error .
784797
785- Executes a query/script with psql and returns psql's standard output. psql is
786- run in unaligned tuples-only quiet mode with psqlrc disabled so simple queries
787- will just return the result row(s) with fields separated by commas.
798+ psql is run in unaligned tuples-only quiet mode with psqlrc disabled so simple
799+ queries will just return the result row(s) with fields separated by commas.
800+
801+ If any stderr output is generated it is printed and discarded.
802+
803+ Nonzero return codes from psql are ignored and discarded.
804+
805+ Use psql_expert for more control.
788806
789807=cut
790808
@@ -793,24 +811,215 @@ sub psql
793811 my ($self , $dbname , $sql ) = @_ ;
794812
795813 my ($stdout , $stderr );
814+
796815 my $name = $self -> name;
797816 print (" ### Running SQL command on node \" $name \" : $sql \n " );
798817
799- IPC::Run::run [ ' psql' , ' -XAtq' , ' -d' , $self -> connstr($dbname ), ' -f' ,
800- ' -' ], ' <' , \$sql , ' >' , \$stdout , ' 2>' , \$stderr
801- or die ;
818+ # Run the command, ignoring errors
819+ $self -> psql_expert($dbname , $sql , stdout => \$stdout , stderr => \$stderr ,
820+ on_error_die => 0, on_error_stop => 0);
821+
822+ if ($stderr ne " " )
823+ {
824+ print " #### Begin standard error\n " ;
825+ print $stderr ;
826+ print " \n #### End standard error\n " ;
827+ }
828+ return $stdout ;
829+ }
830+
831+ =pod $node->psql_check($dbname, $sql) => stdout
832+
833+ Invoke 'psql' to run 'sql' on 'dbname' and return its stdout on success.
834+ Die if the SQL produces an error. Runs with ON_ERROR_STOP set.
835+
836+ Takes optional extra params like timeout and timed_out parameters with the same
837+ options as psql_expert.
802838
839+ =cut
840+
841+ sub psql_check
842+ {
843+ my ($self , $dbname , $sql , %params ) = @_ ;
844+
845+ my ($stdout , $stderr );
846+
847+ my $ret = $self -> psql_expert($dbname , $sql ,
848+ %params ,
849+ stdout => \$stdout , stderr => \$stderr ,
850+ on_error_die => 1, on_error_stop => 1);
851+
852+ # psql can emit stderr from NOTICEs etc
803853 if ($stderr ne " " )
804854 {
805855 print " #### Begin standard error\n " ;
806856 print $stderr ;
807- print " #### End standard error\n " ;
857+ print " \n #### End standard error\n " ;
808858 }
809- chomp $stdout ;
810- $stdout =~ s /\r // g if $Config {osname } eq ' msys' ;
859+
811860 return $stdout ;
812861}
813862
863+ =pod $node->psql_expert($dbname, $sql, %params) => psql_retval
864+
865+ Invoke 'psql' to run 'sql' on 'dbname' and return the return value from
866+ psql, which is run with on_error_stop by default so that it will stop running
867+ sql and return 3 if the passed SQL results in an error.
868+
869+ psql is invoked in tuples-only unaligned mode with reading of psqlrc disabled. That
870+ may be overridden by passing extra psql parameters.
871+
872+ stdout and stderr are transformed to unix line endings if on Windows and any
873+ trailing newline is removed.
874+
875+ Dies on failure to invoke psql but not if psql exits with a nonzero return code
876+ (unless on_error_die specified). Dies if psql exits with a signal.
877+
878+ =over
879+
880+ =item stdout => \$stdout
881+
882+ If a scalar to write stdout to is passed as the keyword parameter 'stdout' it
883+ will be set to psql's stdout.
884+
885+ =item stderr => \$stderr
886+
887+ Same as 'stdout' but gets stderr. If the same scalar is passed for both stdout
888+ and stderr the results may be interleaved unpredictably.
889+
890+ =item on_error_stop => 1
891+
892+ By default psql_expert invokes psql with ON_ERROR_STOP=1 set so it will
893+ stop executing SQL at the first error and return exit code 2. If you want
894+ to ignore errors, pass 0 to on_error_stop.
895+
896+ =item on_error_die => 0
897+
898+ By default psql_expert returns psql's result code. Pass on_error_die to instead
899+ die with an informative message.
900+
901+ =item timeout => 'interval'
902+
903+ Set a timeout for the psql call as an interval accepted by IPC::Run::timer.
904+ Integer seconds is fine. psql_expert dies with an exception on timeout unless
905+ the timed_out parameter is passed.
906+
907+ =item timed_out => \$timed_out
908+
909+ Keyword parameter. Pass a scalar reference and it'll be set to true if the psql
910+ call timed out instead of dying. Has no effect unless 'timeout' is set.
911+
912+ =item extra_params => ['--single-transaction']
913+
914+ Pass additional parameters to psql. Must be an arrayref.
915+
916+ =back
917+
918+ e.g.
919+
920+ my ($stdout, $stderr, $timed_out);
921+ my $cmdret = $psql_expert('postgres', 'SELECT pg_sleep(60)',
922+ stdout => \$stdout, stderr => \$stderr,
923+ timeout => 30, timed_out => \$timed_out,
924+ extra_params => ['--single-transaction'])
925+
926+ will set $cmdret to undef and $timed_out to a true value.
927+
928+ $psql_expert('postgres', $sql, on_error_die => 1);
929+
930+ dies with an informative message if $sql fails.
931+
932+ =cut
933+
934+ sub psql_expert
935+ {
936+ my ($self , $dbname , $sql , %params ) = @_ ;
937+
938+ my $stdout = $params {stdout };
939+ my $stderr = $params {stderr };
940+ my $timeout = undef ;
941+ my $timeout_exception = ' psql timed out' ;
942+ my @psql_params = (' psql' , ' -XAtq' , ' -d' , $self -> connstr($dbname ), ' -f' , ' -' );
943+
944+ $params {on_error_stop } = 1 unless defined $params {on_error_stop };
945+ $params {on_error_die } = 0 unless defined $params {on_error_die };
946+
947+ push @psql_params , ' -v' , ' ON_ERROR_STOP=1' if $params {on_error_stop };
948+ push @psql_params , @{$params {extra_params }} if defined $params {extra_params };
949+
950+ $timeout = IPC::Run::timeout( $params {timeout }, exception => $timeout_exception )
951+ if (defined ($params {timeout }));
952+
953+ # IPC::Run would otherwise append to existing contents:
954+ $$stdout = " " if ref ($stdout );
955+ $$stderr = " " if ref ($stderr );
956+
957+ my $ret ;
958+
959+ # Perl's exception handling is ... interesting. Especially since we have to
960+ # support 5.8.8. So we hide that from the caller, returning true/false for
961+ # timeout instead. See
962+ # http://search.cpan.org/~ether/Try-Tiny-0.24/lib/Try/Tiny.pm for
963+ # background.
964+ my $error = do {
965+ local $@ ;
966+ eval {
967+ IPC::Run::run \@psql_params , ' <' , \$sql , ' >' , $stdout , ' 2>' , $stderr , $timeout ;
968+ $ret = $? ;
969+ };
970+ my $exc_save = $@ ;
971+ if ($exc_save ) {
972+ # IPC::Run::run threw an exception. re-throw unless it's a
973+ # timeout, which we'll handle by testing is_expired
974+ if (blessed($exc_save ) || $exc_save ne $timeout_exception ) {
975+ print " Exception from IPC::Run::run when invoking psql: '$exc_save '\n " ;
976+ die $exc_save ;
977+ } else {
978+ $ret = undef ;
979+
980+ die " Got timeout exception '$exc_save ' but timer not expired?!"
981+ unless $timeout -> is_expired;
982+
983+ if (defined ($params {timed_out }))
984+ {
985+ ${$params {timed_out }} = 1;
986+ } else {
987+ die " psql timed out while running '@psql_params ', stderr '$$stderr '" ;
988+ }
989+ }
990+ }
991+ };
992+
993+ chomp $$stdout ;
994+ $$stdout =~ s /\r // g if $Config {osname } eq ' msys' ;
995+
996+ chomp $$stderr ;
997+ $$stderr =~ s /\r // g if $Config {osname } eq ' msys' ;
998+
999+ # See http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR
1000+ # We don't use IPC::Run::Simple to limit dependencies.
1001+ #
1002+ # We always die on signal. If someone wants to capture signals
1003+ # to psql we can return it with another reference out parameter.
1004+ die " psql exited with signal " . ($ret & 127) . " : '$$stderr ' while running '@psql_params '"
1005+ if $ret & 127;
1006+ die " psql exited with core dump: '$$stderr ' while running '@psql_params '"
1007+ if $ret & 128;
1008+ $ret = $ret >> 8;
1009+
1010+ if ($ret && $params {on_error_die }) {
1011+ die " psql command line syntax error or internal error: '$$stderr ' while running '@psql_params '"
1012+ if $ret == 1;
1013+ die " psql connection error: '$$stderr ' while running '@psql_params '"
1014+ if $ret == 2;
1015+ die " error when running passed SQL: '$$stderr ' while running '@psql_params '"
1016+ if $ret == 3;
1017+ die " unexpected error code $ret from psql: '$$stderr ' while running '@psql_params '" ;
1018+ }
1019+
1020+ return $ret ;
1021+ }
1022+
8141023=pod
8151024
8161025=item $node->poll_query_until(dbname, query)
0 commit comments