diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 8c464c9d421..b5e3a62a339 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -804,6 +804,18 @@ pgbench options d + + Exit Status + + + A successful run will exit with status 0. Exit status 1 indicates static + problems such as invalid command-line options. Errors during the run such + as database errors or problems in the script will result in exit status 2. + In the latter case, pgbench will print partial + results. + + + Notes diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 436764b9c91..81bc6d8a6e3 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -4931,6 +4931,8 @@ main(int argc, char **argv) PGresult *res; char *env; + int exit_code = 0; + progname = get_progname(argv[0]); if (argc > 1) @@ -5675,6 +5677,10 @@ main(int argc, char **argv) (void) threadRun(thread); #endif /* ENABLE_THREAD_SAFETY */ + for (int j = 0; j < thread->nstate; j++) + if (thread->state[j].state == CSTATE_ABORTED) + exit_code = 2; + /* aggregate thread level stats */ mergeSimpleStats(&stats.latency, &thread->stats.latency); mergeSimpleStats(&stats.lag, &thread->stats.lag); @@ -5699,7 +5705,10 @@ main(int argc, char **argv) INSTR_TIME_SUBTRACT(total_time, start_time); printResults(threads, &stats, total_time, conn_total_time, latency_late); - return 0; + if (exit_code != 0) + fprintf(stderr, "Run was aborted; the above results are incomplete.\n"); + + return exit_code; } static void * diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index d972903f2ad..00819890261 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -537,7 +537,7 @@ my @errors = ( # SQL [ 'sql syntax error', - 0, + 2, [ qr{ERROR: syntax error}, qr{prepared statement .* does not exist} @@ -556,11 +556,11 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); # SHELL [ - 'shell bad command', 0, + 'shell bad command', 2, [qr{\(shell\) .* meta-command failed}], q{\shell no-such-command} ], [ - 'shell undefined variable', 0, + 'shell undefined variable', 2, [qr{undefined variable ":nosuchvariable"}], q{-- undefined variable in shell \shell echo ::foo :nosuchvariable @@ -600,75 +600,75 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); [qr{unexpected function name}], q{\set i noSuchFunction()} ], [ - 'set invalid variable name', 0, + 'set invalid variable name', 2, [qr{invalid variable name}], q{\set . 1} ], [ - 'set division by zero', 0, + 'set division by zero', 2, [qr{division by zero}], q{\set i 1/0} ], [ 'set undefined variable', - 0, + 2, [qr{undefined variable "nosuchvariable"}], q{\set i :nosuchvariable} ], [ 'set unexpected char', 1, [qr{unexpected character .;.}], q{\set i ;} ], [ 'set too many args', - 0, + 2, [qr{too many function arguments}], q{\set i least(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)} ], [ - 'set empty random range', 0, + 'set empty random range', 2, [qr{empty range given to random}], q{\set i random(5,3)} ], [ 'set random range too large', - 0, + 2, [qr{random range is too large}], q{\set i random(:minint, :maxint)} ], [ 'set gaussian param too small', - 0, + 2, [qr{gaussian param.* at least 2}], q{\set i random_gaussian(0, 10, 1.0)} ], [ 'set exponential param greater 0', - 0, + 2, [qr{exponential parameter must be greater }], q{\set i random_exponential(0, 10, 0.0)} ], [ 'set zipfian param to 1', - 0, + 2, [qr{zipfian parameter must be in range \(0, 1\) U \(1, \d+\]}], q{\set i random_zipfian(0, 10, 1)} ], [ 'set zipfian param too large', - 0, + 2, [qr{zipfian parameter must be in range \(0, 1\) U \(1, \d+\]}], q{\set i random_zipfian(0, 10, 1000000)} ], [ - 'set non numeric value', 0, + 'set non numeric value', 2, [qr{malformed variable "foo" value: "bla"}], q{\set i :foo + 1} ], [ 'set no expression', 1, [qr{syntax error}], q{\set i} ], [ 'set missing argument', 1, [qr{missing argument}i], q{\set} ], [ - 'set not a bool', 0, + 'set not a bool', 2, [qr{cannot coerce double to boolean}], q{\set b NOT 0.0} ], [ - 'set not an int', 0, + 'set not an int', 2, [qr{cannot coerce boolean to int}], q{\set i TRUE + 2} ], [ - 'set not a double', 0, + 'set not a double', 2, [qr{cannot coerce boolean to double}], q{\set d ln(TRUE)} ], [ @@ -678,7 +678,7 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); q{\set i CASE TRUE THEN 1 ELSE 0 END} ], [ - 'set random error', 0, + 'set random error', 2, [qr{cannot coerce boolean to int}], q{\set b random(FALSE, TRUE)} ], [ @@ -691,31 +691,31 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); ], # SET: ARITHMETIC OVERFLOW DETECTION - [ 'set double to int overflow', 0, + [ 'set double to int overflow', 2, [ qr{double to int overflow for 100} ], q{\set i int(1E32)} ], - [ 'set bigint add overflow', 0, + [ 'set bigint add overflow', 2, [ qr{int add out} ], q{\set i (1<<62) + (1<<62)} ], - [ 'set bigint sub overflow', 0, + [ 'set bigint sub overflow', 2, [ qr{int sub out} ], q{\set i 0 - (1<<62) - (1<<62) - (1<<62)} ], - [ 'set bigint mul overflow', 0, + [ 'set bigint mul overflow', 2, [ qr{int mul out} ], q{\set i 2 * (1<<62)} ], - [ 'set bigint div out of range', 0, + [ 'set bigint div out of range', 2, [ qr{bigint div out of range} ], q{\set i :minint / -1} ], # SETSHELL [ - 'setshell not an int', 0, + 'setshell not an int', 2, [qr{command must return an integer}], q{\setshell i echo -n one} ], [ 'setshell missing arg', 1, [qr{missing argument }], q{\setshell var} ], [ - 'setshell no such command', 0, + 'setshell no such command', 2, [qr{could not read result }], q{\setshell var no-such-command} ], # SLEEP [ - 'sleep undefined variable', 0, + 'sleep undefined variable', 2, [qr{sleep: undefined variable}], q{\sleep :nosuchvariable} ], [ @@ -738,7 +738,7 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); ], [ 'misc empty script', 1, [qr{empty command list for script}], q{} ], [ - 'bad boolean', 0, + 'bad boolean', 2, [qr{malformed variable.*trueXXX}], q{\set b :badtrue or true} ],); @@ -746,13 +746,14 @@ SELECT LEAST(:i, :i, :i, :i, :i, :i, :i, :i, :i, :i, :i); for my $e (@errors) { my ($name, $status, $re, $script) = @$e; + $status != 0 or die "invalid expected status for test \"$name\""; my $n = '001_pgbench_error_' . $name; $n =~ s/ /_/g; pgbench( '-n -t 1 -M prepared -Dfoo=bla -Dnull=null -Dtrue=true -Done=1 -Dzero=0.0 ' . '-Dbadtrue=trueXXX -Dmaxint=9223372036854775807 -Dminint=-9223372036854775808', $status, - [ $status ? qr{^$} : qr{processed: 0/1} ], + [ $status == 1 ? qr{^$} : qr{processed: 0/1} ], $re, 'pgbench script error: ' . $name, { $n => $script });