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 });