@@ -21,8 +21,20 @@ PostgresNode - class representing PostgreSQL server instance
21
21
$node->restart('fast');
22
22
23
23
# 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;
26
38
27
39
# run query every second until it returns 't'
28
40
# or times out
@@ -69,6 +81,7 @@ use IPC::Run;
69
81
use RecursiveCopy;
70
82
use Test::More;
71
83
use TestLib ();
84
+ use Scalar::Util qw( blessed) ;
72
85
73
86
our @EXPORT = qw(
74
87
get_new_node
@@ -780,11 +793,16 @@ sub teardown_node
780
793
781
794
=item $node->psql(dbname, sql)
782
795
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 .
784
797
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.
788
806
789
807
=cut
790
808
@@ -793,24 +811,215 @@ sub psql
793
811
my ($self , $dbname , $sql ) = @_ ;
794
812
795
813
my ($stdout , $stderr );
814
+
796
815
my $name = $self -> name;
797
816
print (" ### Running SQL command on node \" $name \" : $sql \n " );
798
817
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.
802
838
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
803
853
if ($stderr ne " " )
804
854
{
805
855
print " #### Begin standard error\n " ;
806
856
print $stderr ;
807
- print " #### End standard error\n " ;
857
+ print " \n #### End standard error\n " ;
808
858
}
809
- chomp $stdout ;
810
- $stdout =~ s /\r // g if $Config {osname } eq ' msys' ;
859
+
811
860
return $stdout ;
812
861
}
813
862
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
+
814
1023
=pod
815
1024
816
1025
=item $node->poll_query_until(dbname, query)
0 commit comments