PostgreSQL Source Code  git master
isolationtester.c
Go to the documentation of this file.
1 /*
2  * src/test/isolation/isolationtester.c
3  *
4  * isolationtester.c
5  * Runs an isolation test specified by a spec file.
6  */
7 
8 #include "postgres_fe.h"
9 
10 #include <sys/time.h>
11 #ifdef HAVE_SYS_SELECT_H
12 #include <sys/select.h>
13 #endif
14 
15 #include "datatype/timestamp.h"
16 #include "libpq-fe.h"
17 #include "pqexpbuffer.h"
18 #include "pg_getopt.h"
19 
20 #include "isolationtester.h"
21 
22 #define PREP_WAITING "isolationtester_waiting"
23 
24 /*
25  * conns[0] is the global setup, teardown, and watchdog connection. Additional
26  * connections represent spec-defined sessions.
27  */
28 static PGconn **conns = NULL;
29 static const char **backend_pids = NULL;
30 static int nconns = 0;
31 
32 /* In dry run only output permutations to be run by the tester. */
33 static int dry_run = false;
34 
35 static void exit_nicely(void) pg_attribute_noreturn();
36 static void run_testspec(TestSpec *testspec);
37 static void run_all_permutations(TestSpec *testspec);
38 static void run_all_permutations_recurse(TestSpec *testspec, int nsteps,
39  Step **steps);
40 static void run_named_permutations(TestSpec *testspec);
41 static void run_permutation(TestSpec *testspec, int nsteps, Step **steps);
42 
43 #define STEP_NONBLOCK 0x1 /* return 0 as soon as cmd waits for a lock */
44 #define STEP_RETRY 0x2 /* this is a retry of a previously-waiting cmd */
45 static bool try_complete_step(Step *step, int flags);
46 
47 static int step_qsort_cmp(const void *a, const void *b);
48 static int step_bsearch_cmp(const void *a, const void *b);
49 
50 static void printResultSet(PGresult *res);
51 
52 /* close all connections and exit */
53 static void
54 exit_nicely(void)
55 {
56  int i;
57 
58  for (i = 0; i < nconns; i++)
59  PQfinish(conns[i]);
60  exit(1);
61 }
62 
63 int
64 main(int argc, char **argv)
65 {
66  const char *conninfo;
67  TestSpec *testspec;
68  int i,
69  j;
70  int n;
71  PGresult *res;
72  PQExpBufferData wait_query;
73  int opt;
74  int nallsteps;
75  Step **allsteps;
76 
77  while ((opt = getopt(argc, argv, "nV")) != -1)
78  {
79  switch (opt)
80  {
81  case 'n':
82  dry_run = true;
83  break;
84  case 'V':
85  puts("isolationtester (PostgreSQL) " PG_VERSION);
86  exit(0);
87  default:
88  fprintf(stderr, "Usage: isolationtester [-n] [CONNINFO]\n");
89  return EXIT_FAILURE;
90  }
91  }
92 
93  /*
94  * Make stdout unbuffered to match stderr; and ensure stderr is unbuffered
95  * too, which it should already be everywhere except sometimes in Windows.
96  */
97  setbuf(stdout, NULL);
98  setbuf(stderr, NULL);
99 
100  /*
101  * If the user supplies a non-option parameter on the command line, use it
102  * as the conninfo string; otherwise default to setting dbname=postgres
103  * and using environment variables or defaults for all other connection
104  * parameters.
105  */
106  if (argc > optind)
107  conninfo = argv[optind];
108  else
109  conninfo = "dbname = postgres";
110 
111  /* Read the test spec from stdin */
112  spec_yyparse();
113  testspec = &parseresult;
114 
115  /* Create a lookup table of all steps. */
116  nallsteps = 0;
117  for (i = 0; i < testspec->nsessions; i++)
118  nallsteps += testspec->sessions[i]->nsteps;
119 
120  allsteps = pg_malloc(nallsteps * sizeof(Step *));
121 
122  n = 0;
123  for (i = 0; i < testspec->nsessions; i++)
124  {
125  for (j = 0; j < testspec->sessions[i]->nsteps; j++)
126  allsteps[n++] = testspec->sessions[i]->steps[j];
127  }
128 
129  qsort(allsteps, nallsteps, sizeof(Step *), &step_qsort_cmp);
130  testspec->nallsteps = nallsteps;
131  testspec->allsteps = allsteps;
132 
133  /* Verify that all step names are unique */
134  for (i = 1; i < testspec->nallsteps; i++)
135  {
136  if (strcmp(testspec->allsteps[i - 1]->name,
137  testspec->allsteps[i]->name) == 0)
138  {
139  fprintf(stderr, "duplicate step name: %s\n",
140  testspec->allsteps[i]->name);
141  exit_nicely();
142  }
143  }
144 
145  /*
146  * In dry-run mode, just print the permutations that would be run, and
147  * exit.
148  */
149  if (dry_run)
150  {
151  run_testspec(testspec);
152  return 0;
153  }
154 
155  printf("Parsed test spec with %d sessions\n", testspec->nsessions);
156 
157  /*
158  * Establish connections to the database, one for each session and an
159  * extra for lock wait detection and global work.
160  */
161  nconns = 1 + testspec->nsessions;
162  conns = calloc(nconns, sizeof(PGconn *));
163  backend_pids = calloc(nconns, sizeof(*backend_pids));
164  for (i = 0; i < nconns; i++)
165  {
166  conns[i] = PQconnectdb(conninfo);
167  if (PQstatus(conns[i]) != CONNECTION_OK)
168  {
169  fprintf(stderr, "Connection %d to database failed: %s",
170  i, PQerrorMessage(conns[i]));
171  exit_nicely();
172  }
173 
174  /*
175  * Suppress NOTIFY messages, which otherwise pop into results at odd
176  * places.
177  */
178  res = PQexec(conns[i], "SET client_min_messages = warning;");
179  if (PQresultStatus(res) != PGRES_COMMAND_OK)
180  {
181  fprintf(stderr, "message level setup failed: %s", PQerrorMessage(conns[i]));
182  exit_nicely();
183  }
184  PQclear(res);
185 
186  /* Get the backend pid for lock wait checking. */
187  res = PQexec(conns[i], "SELECT pg_backend_pid()");
188  if (PQresultStatus(res) == PGRES_TUPLES_OK)
189  {
190  if (PQntuples(res) == 1 && PQnfields(res) == 1)
191  backend_pids[i] = pg_strdup(PQgetvalue(res, 0, 0));
192  else
193  {
194  fprintf(stderr, "backend pid query returned %d rows and %d columns, expected 1 row and 1 column",
195  PQntuples(res), PQnfields(res));
196  exit_nicely();
197  }
198  }
199  else
200  {
201  fprintf(stderr, "backend pid query failed: %s",
202  PQerrorMessage(conns[i]));
203  exit_nicely();
204  }
205  PQclear(res);
206  }
207 
208  /* Set the session index fields in steps. */
209  for (i = 0; i < testspec->nsessions; i++)
210  {
211  Session *session = testspec->sessions[i];
212  int stepindex;
213 
214  for (stepindex = 0; stepindex < session->nsteps; stepindex++)
215  session->steps[stepindex]->session = i;
216  }
217 
218  /*
219  * Build the query we'll use to detect lock contention among sessions in
220  * the test specification. Most of the time, we could get away with
221  * simply checking whether a session is waiting for *any* lock: we don't
222  * exactly expect concurrent use of test tables. However, autovacuum will
223  * occasionally take AccessExclusiveLock to truncate a table, and we must
224  * ignore that transient wait.
225  */
226  initPQExpBuffer(&wait_query);
227  appendPQExpBufferStr(&wait_query,
228  "SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{");
229  /* The spec syntax requires at least one session; assume that here. */
230  appendPQExpBufferStr(&wait_query, backend_pids[1]);
231  for (i = 2; i < nconns; i++)
232  appendPQExpBuffer(&wait_query, ",%s", backend_pids[i]);
233  appendPQExpBufferStr(&wait_query, "}')");
234 
235  res = PQprepare(conns[0], PREP_WAITING, wait_query.data, 0, NULL);
236  if (PQresultStatus(res) != PGRES_COMMAND_OK)
237  {
238  fprintf(stderr, "prepare of lock wait query failed: %s",
239  PQerrorMessage(conns[0]));
240  exit_nicely();
241  }
242  PQclear(res);
243  termPQExpBuffer(&wait_query);
244 
245  /*
246  * Run the permutations specified in the spec, or all if none were
247  * explicitly specified.
248  */
249  run_testspec(testspec);
250 
251  /* Clean up and exit */
252  for (i = 0; i < nconns; i++)
253  PQfinish(conns[i]);
254  return 0;
255 }
256 
257 static int *piles;
258 
259 /*
260  * Run the permutations specified in the spec, or all if none were
261  * explicitly specified.
262  */
263 static void
265 {
266  if (testspec->permutations)
267  run_named_permutations(testspec);
268  else
269  run_all_permutations(testspec);
270 }
271 
272 /*
273  * Run all permutations of the steps and sessions.
274  */
275 static void
277 {
278  int nsteps;
279  int i;
280  Step **steps;
281 
282  /* Count the total number of steps in all sessions */
283  nsteps = 0;
284  for (i = 0; i < testspec->nsessions; i++)
285  nsteps += testspec->sessions[i]->nsteps;
286 
287  steps = pg_malloc(sizeof(Step *) * nsteps);
288 
289  /*
290  * To generate the permutations, we conceptually put the steps of each
291  * session on a pile. To generate a permutation, we pick steps from the
292  * piles until all piles are empty. By picking steps from piles in
293  * different order, we get different permutations.
294  *
295  * A pile is actually just an integer which tells how many steps we've
296  * already picked from this pile.
297  */
298  piles = pg_malloc(sizeof(int) * testspec->nsessions);
299  for (i = 0; i < testspec->nsessions; i++)
300  piles[i] = 0;
301 
302  run_all_permutations_recurse(testspec, 0, steps);
303 }
304 
305 static void
306 run_all_permutations_recurse(TestSpec *testspec, int nsteps, Step **steps)
307 {
308  int i;
309  int found = 0;
310 
311  for (i = 0; i < testspec->nsessions; i++)
312  {
313  /* If there's any more steps in this pile, pick it and recurse */
314  if (piles[i] < testspec->sessions[i]->nsteps)
315  {
316  steps[nsteps] = testspec->sessions[i]->steps[piles[i]];
317  piles[i]++;
318 
319  run_all_permutations_recurse(testspec, nsteps + 1, steps);
320 
321  piles[i]--;
322 
323  found = 1;
324  }
325  }
326 
327  /* If all the piles were empty, this permutation is completed. Run it */
328  if (!found)
329  run_permutation(testspec, nsteps, steps);
330 }
331 
332 /*
333  * Run permutations given in the test spec
334  */
335 static void
337 {
338  int i,
339  j;
340 
341  for (i = 0; i < testspec->npermutations; i++)
342  {
343  Permutation *p = testspec->permutations[i];
344  Step **steps;
345 
346  steps = pg_malloc(p->nsteps * sizeof(Step *));
347 
348  /* Find all the named steps using the lookup table */
349  for (j = 0; j < p->nsteps; j++)
350  {
351  Step **this = (Step **) bsearch(p->stepnames[j],
352  testspec->allsteps,
353  testspec->nallsteps,
354  sizeof(Step *),
356 
357  if (this == NULL)
358  {
359  fprintf(stderr, "undefined step \"%s\" specified in permutation\n",
360  p->stepnames[j]);
361  exit_nicely();
362  }
363  steps[j] = *this;
364  }
365 
366  /* And run them */
367  run_permutation(testspec, p->nsteps, steps);
368 
369  free(steps);
370  }
371 }
372 
373 static int
374 step_qsort_cmp(const void *a, const void *b)
375 {
376  Step *stepa = *((Step **) a);
377  Step *stepb = *((Step **) b);
378 
379  return strcmp(stepa->name, stepb->name);
380 }
381 
382 static int
383 step_bsearch_cmp(const void *a, const void *b)
384 {
385  char *stepname = (char *) a;
386  Step *step = *((Step **) b);
387 
388  return strcmp(stepname, step->name);
389 }
390 
391 /*
392  * If a step caused an error to be reported, print it out and clear it.
393  */
394 static void
396 {
397  if (step->errormsg)
398  {
399  fprintf(stdout, "%s\n", step->errormsg);
400  free(step->errormsg);
401  step->errormsg = NULL;
402  }
403 }
404 
405 /*
406  * As above, but reports messages possibly emitted by multiple steps. This is
407  * useful when we have a blocked command awakened by another one; we want to
408  * report all messages identically, for the case where we don't care which
409  * one fails due to a timeout such as deadlock timeout.
410  */
411 static void
412 report_multiple_error_messages(Step *step, int nextra, Step **extrastep)
413 {
415  int n;
416 
417  if (nextra == 0)
418  {
419  report_error_message(step);
420  return;
421  }
422 
423  initPQExpBuffer(&buffer);
424  appendPQExpBufferStr(&buffer, step->name);
425 
426  for (n = 0; n < nextra; ++n)
427  appendPQExpBuffer(&buffer, " %s", extrastep[n]->name);
428 
429  if (step->errormsg)
430  {
431  fprintf(stdout, "error in steps %s: %s\n", buffer.data,
432  step->errormsg);
433  free(step->errormsg);
434  step->errormsg = NULL;
435  }
436 
437  for (n = 0; n < nextra; ++n)
438  {
439  if (extrastep[n]->errormsg == NULL)
440  continue;
441  fprintf(stdout, "error in steps %s: %s\n",
442  buffer.data, extrastep[n]->errormsg);
443  free(extrastep[n]->errormsg);
444  extrastep[n]->errormsg = NULL;
445  }
446 
447  termPQExpBuffer(&buffer);
448 }
449 
450 /*
451  * Run one permutation
452  */
453 static void
454 run_permutation(TestSpec *testspec, int nsteps, Step **steps)
455 {
456  PGresult *res;
457  int i;
458  int w;
459  int nwaiting = 0;
460  int nerrorstep = 0;
461  Step **waiting;
462  Step **errorstep;
463 
464  /*
465  * In dry run mode, just display the permutation in the same format used
466  * by spec files, and return.
467  */
468  if (dry_run)
469  {
470  printf("permutation");
471  for (i = 0; i < nsteps; i++)
472  printf(" \"%s\"", steps[i]->name);
473  printf("\n");
474  return;
475  }
476 
477  waiting = pg_malloc(sizeof(Step *) * testspec->nsessions);
478  errorstep = pg_malloc(sizeof(Step *) * testspec->nsessions);
479 
480  printf("\nstarting permutation:");
481  for (i = 0; i < nsteps; i++)
482  printf(" %s", steps[i]->name);
483  printf("\n");
484 
485  /* Perform setup */
486  for (i = 0; i < testspec->nsetupsqls; i++)
487  {
488  res = PQexec(conns[0], testspec->setupsqls[i]);
489  if (PQresultStatus(res) == PGRES_TUPLES_OK)
490  {
491  printResultSet(res);
492  }
493  else if (PQresultStatus(res) != PGRES_COMMAND_OK)
494  {
495  fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0]));
496  exit_nicely();
497  }
498  PQclear(res);
499  }
500 
501  /* Perform per-session setup */
502  for (i = 0; i < testspec->nsessions; i++)
503  {
504  if (testspec->sessions[i]->setupsql)
505  {
506  res = PQexec(conns[i + 1], testspec->sessions[i]->setupsql);
507  if (PQresultStatus(res) == PGRES_TUPLES_OK)
508  {
509  printResultSet(res);
510  }
511  else if (PQresultStatus(res) != PGRES_COMMAND_OK)
512  {
513  fprintf(stderr, "setup of session %s failed: %s",
514  testspec->sessions[i]->name,
515  PQerrorMessage(conns[i + 1]));
516  exit_nicely();
517  }
518  PQclear(res);
519  }
520  }
521 
522  /* Perform steps */
523  for (i = 0; i < nsteps; i++)
524  {
525  Step *step = steps[i];
526  PGconn *conn = conns[1 + step->session];
527  Step *oldstep = NULL;
528  bool mustwait;
529 
530  /*
531  * Check whether the session that needs to perform the next step is
532  * still blocked on an earlier step. If so, wait for it to finish.
533  *
534  * (In older versions of this tool, we allowed precisely one session
535  * to be waiting at a time. If we reached a step that required that
536  * session to execute the next command, we would declare the whole
537  * permutation invalid, cancel everything, and move on to the next
538  * one. Unfortunately, that made it impossible to test the deadlock
539  * detector using this framework, unless the number of processes
540  * involved in the deadlock was precisely two. We now assume that if
541  * we reach a step that is still blocked, we need to wait for it to
542  * unblock itself.)
543  */
544  for (w = 0; w < nwaiting; ++w)
545  {
546  if (step->session == waiting[w]->session)
547  {
548  oldstep = waiting[w];
549 
550  /* Wait for previous step on this connection. */
551  try_complete_step(oldstep, STEP_RETRY);
552 
553  /* Remove that step from the waiting[] array. */
554  if (w + 1 < nwaiting)
555  memmove(&waiting[w], &waiting[w + 1],
556  (nwaiting - (w + 1)) * sizeof(Step *));
557  nwaiting--;
558 
559  break;
560  }
561  }
562  if (oldstep != NULL)
563  {
564  /*
565  * Check for completion of any steps that were previously waiting.
566  * Remove any that have completed from waiting[], and include them
567  * in the list for report_multiple_error_messages().
568  */
569  w = 0;
570  nerrorstep = 0;
571  while (w < nwaiting)
572  {
573  if (try_complete_step(waiting[w], STEP_NONBLOCK | STEP_RETRY))
574  {
575  /* Still blocked on a lock, leave it alone. */
576  w++;
577  }
578  else
579  {
580  /* This one finished, too! */
581  errorstep[nerrorstep++] = waiting[w];
582  if (w + 1 < nwaiting)
583  memmove(&waiting[w], &waiting[w + 1],
584  (nwaiting - (w + 1)) * sizeof(Step *));
585  nwaiting--;
586  }
587  }
588 
589  /* Report all errors together. */
590  report_multiple_error_messages(oldstep, nerrorstep, errorstep);
591  }
592 
593  /* Send the query for this step. */
594  if (!PQsendQuery(conn, step->sql))
595  {
596  fprintf(stdout, "failed to send query for step %s: %s\n",
597  step->name, PQerrorMessage(conns[1 + step->session]));
598  exit_nicely();
599  }
600 
601  /* Try to complete this step without blocking. */
602  mustwait = try_complete_step(step, STEP_NONBLOCK);
603 
604  /* Check for completion of any steps that were previously waiting. */
605  w = 0;
606  nerrorstep = 0;
607  while (w < nwaiting)
608  {
609  if (try_complete_step(waiting[w], STEP_NONBLOCK | STEP_RETRY))
610  w++;
611  else
612  {
613  errorstep[nerrorstep++] = waiting[w];
614  if (w + 1 < nwaiting)
615  memmove(&waiting[w], &waiting[w + 1],
616  (nwaiting - (w + 1)) * sizeof(Step *));
617  nwaiting--;
618  }
619  }
620 
621  /* Report any error from this step, and any steps that it unblocked. */
622  report_multiple_error_messages(step, nerrorstep, errorstep);
623 
624  /* If this step is waiting, add it to the array of waiters. */
625  if (mustwait)
626  waiting[nwaiting++] = step;
627  }
628 
629  /* Wait for any remaining queries. */
630  for (w = 0; w < nwaiting; ++w)
631  {
632  try_complete_step(waiting[w], STEP_RETRY);
633  report_error_message(waiting[w]);
634  }
635 
636  /* Perform per-session teardown */
637  for (i = 0; i < testspec->nsessions; i++)
638  {
639  if (testspec->sessions[i]->teardownsql)
640  {
641  res = PQexec(conns[i + 1], testspec->sessions[i]->teardownsql);
642  if (PQresultStatus(res) == PGRES_TUPLES_OK)
643  {
644  printResultSet(res);
645  }
646  else if (PQresultStatus(res) != PGRES_COMMAND_OK)
647  {
648  fprintf(stderr, "teardown of session %s failed: %s",
649  testspec->sessions[i]->name,
650  PQerrorMessage(conns[i + 1]));
651  /* don't exit on teardown failure */
652  }
653  PQclear(res);
654  }
655  }
656 
657  /* Perform teardown */
658  if (testspec->teardownsql)
659  {
660  res = PQexec(conns[0], testspec->teardownsql);
661  if (PQresultStatus(res) == PGRES_TUPLES_OK)
662  {
663  printResultSet(res);
664  }
665  else if (PQresultStatus(res) != PGRES_COMMAND_OK)
666  {
667  fprintf(stderr, "teardown failed: %s",
668  PQerrorMessage(conns[0]));
669  /* don't exit on teardown failure */
670  }
671  PQclear(res);
672  }
673 
674  free(waiting);
675  free(errorstep);
676 }
677 
678 /*
679  * Our caller already sent the query associated with this step. Wait for it
680  * to either complete or (if given the STEP_NONBLOCK flag) to block while
681  * waiting for a lock. We assume that any lock wait will persist until we
682  * have executed additional steps in the permutation.
683  *
684  * When calling this function on behalf of a given step for a second or later
685  * time, pass the STEP_RETRY flag. This only affects the messages printed.
686  *
687  * If the query returns an error, the message is saved in step->errormsg.
688  * Caller should call report_error_message shortly after this, to have it
689  * printed and cleared.
690  *
691  * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire
692  * a lock, returns true. Otherwise, returns false.
693  */
694 static bool
695 try_complete_step(Step *step, int flags)
696 {
697  PGconn *conn = conns[1 + step->session];
698  fd_set read_set;
699  struct timeval start_time;
700  struct timeval timeout;
701  int sock = PQsocket(conn);
702  int ret;
703  PGresult *res;
704  bool canceled = false;
705 
706  if (sock < 0)
707  {
708  fprintf(stderr, "invalid socket: %s", PQerrorMessage(conn));
709  exit_nicely();
710  }
711 
712  gettimeofday(&start_time, NULL);
713  FD_ZERO(&read_set);
714 
715  while (PQisBusy(conn))
716  {
717  FD_SET(sock, &read_set);
718  timeout.tv_sec = 0;
719  timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */
720 
721  ret = select(sock + 1, &read_set, NULL, NULL, &timeout);
722  if (ret < 0) /* error in select() */
723  {
724  if (errno == EINTR)
725  continue;
726  fprintf(stderr, "select failed: %s\n", strerror(errno));
727  exit_nicely();
728  }
729  else if (ret == 0) /* select() timeout: check for lock wait */
730  {
731  struct timeval current_time;
732  int64 td;
733 
734  /* If it's OK for the step to block, check whether it has. */
735  if (flags & STEP_NONBLOCK)
736  {
737  bool waiting;
738 
739  res = PQexecPrepared(conns[0], PREP_WAITING, 1,
740  &backend_pids[step->session + 1],
741  NULL, NULL, 0);
742  if (PQresultStatus(res) != PGRES_TUPLES_OK ||
743  PQntuples(res) != 1)
744  {
745  fprintf(stderr, "lock wait query failed: %s",
746  PQerrorMessage(conn));
747  exit_nicely();
748  }
749  waiting = ((PQgetvalue(res, 0, 0))[0] == 't');
750  PQclear(res);
751 
752  if (waiting) /* waiting to acquire a lock */
753  {
754  if (!(flags & STEP_RETRY))
755  printf("step %s: %s <waiting ...>\n",
756  step->name, step->sql);
757  return true;
758  }
759  /* else, not waiting */
760  }
761 
762  /* Figure out how long we've been waiting for this step. */
763  gettimeofday(&current_time, NULL);
764  td = (int64) current_time.tv_sec - (int64) start_time.tv_sec;
765  td *= USECS_PER_SEC;
766  td += (int64) current_time.tv_usec - (int64) start_time.tv_usec;
767 
768  /*
769  * After 60 seconds, try to cancel the query.
770  *
771  * If the user tries to test an invalid permutation, we don't want
772  * to hang forever, especially when this is running in the
773  * buildfarm. So try to cancel it after a minute. This will
774  * presumably lead to this permutation failing, but remaining
775  * permutations and tests should still be OK.
776  */
777  if (td > 60 * USECS_PER_SEC && !canceled)
778  {
779  PGcancel *cancel = PQgetCancel(conn);
780 
781  if (cancel != NULL)
782  {
783  char buf[256];
784 
785  if (PQcancel(cancel, buf, sizeof(buf)))
786  canceled = true;
787  else
788  fprintf(stderr, "PQcancel failed: %s\n", buf);
789  PQfreeCancel(cancel);
790  }
791  }
792 
793  /*
794  * After 75 seconds, just give up and die.
795  *
796  * Since cleanup steps won't be run in this case, this may cause
797  * later tests to fail. That stinks, but it's better than waiting
798  * forever for the server to respond to the cancel.
799  */
800  if (td > 75 * USECS_PER_SEC)
801  {
802  fprintf(stderr, "step %s timed out after 75 seconds\n",
803  step->name);
804  exit_nicely();
805  }
806  }
807  else if (!PQconsumeInput(conn)) /* select(): data available */
808  {
809  fprintf(stderr, "PQconsumeInput failed: %s\n",
810  PQerrorMessage(conn));
811  exit_nicely();
812  }
813  }
814 
815  if (flags & STEP_RETRY)
816  printf("step %s: <... completed>\n", step->name);
817  else
818  printf("step %s: %s\n", step->name, step->sql);
819 
820  while ((res = PQgetResult(conn)))
821  {
822  switch (PQresultStatus(res))
823  {
824  case PGRES_COMMAND_OK:
825  break;
826  case PGRES_TUPLES_OK:
827  printResultSet(res);
828  break;
829  case PGRES_FATAL_ERROR:
830  if (step->errormsg != NULL)
831  {
832  printf("WARNING: this step had a leftover error message\n");
833  printf("%s\n", step->errormsg);
834  }
835 
836  /*
837  * Detail may contain XID values, so we want to just show
838  * primary. Beware however that libpq-generated error results
839  * may not contain subfields, only an old-style message.
840  */
841  {
842  const char *sev = PQresultErrorField(res,
844  const char *msg = PQresultErrorField(res,
846 
847  if (sev && msg)
848  step->errormsg = psprintf("%s: %s", sev, msg);
849  else
851  }
852  break;
853  default:
854  printf("unexpected result status: %s\n",
856  }
857  PQclear(res);
858  }
859 
860  return false;
861 }
862 
863 static void
865 {
866  int nFields;
867  int i,
868  j;
869 
870  /* first, print out the attribute names */
871  nFields = PQnfields(res);
872  for (i = 0; i < nFields; i++)
873  printf("%-15s", PQfname(res, i));
874  printf("\n\n");
875 
876  /* next, print out the rows */
877  for (i = 0; i < PQntuples(res); i++)
878  {
879  for (j = 0; j < nFields; j++)
880  printf("%-15s", PQgetvalue(res, i, j));
881  printf("\n");
882  }
883 }
#define calloc(a, b)
Definition: header.h:55
PGresult * PQexecPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1958
int PQnfields(const PGresult *res)
Definition: fe-exec.c:2732
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:1941
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
#define PG_DIAG_MESSAGE_PRIMARY
Definition: postgres_ext.h:58
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3118
char * PQfname(const PGresult *res, int field_num)
Definition: fe-exec.c:2810
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define USECS_PER_SEC
Definition: timestamp.h:94
static void run_named_permutations(TestSpec *testspec)
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
Session ** sessions
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:385
char ** setupsqls
void PQfreeCancel(PGcancel *cancel)
Definition: fe-connect.c:3773
int main(int argc, char **argv)
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static void run_all_permutations(TestSpec *testspec)
char * teardownsql
static int dry_run
static bool try_complete_step(Step *step, int flags)
static void report_multiple_error_messages(Step *step, int nextra, Step **extrastep)
char * PQresStatus(ExecStatusType status)
Definition: fe-exec.c:2655
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3629
Permutation ** permutations
char * setupsql
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2724
static const char ** backend_pids
static int step_qsort_cmp(const void *a, const void *b)
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:72
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
char * name
int npermutations
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1183
int optind
Definition: getopt.c:51
static PGconn ** conns
char * name
char * teardownsql
PGconn * conn
Definition: streamutil.c:46
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:262
static int step_bsearch_cmp(const void *a, const void *b)
static char * buf
Definition: pg_test_fsync.c:67
#define memmove(d, s, c)
Definition: c.h:1055
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-connect.c:3750
#define PG_DIAG_SEVERITY
Definition: postgres_ext.h:55
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define select(n, r, w, e, timeout)
Definition: win32_port.h:447
#define STEP_RETRY
char ** stepnames
static int * piles
char * errormsg
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1682
static void exit_nicely(void)
void PQclear(PGresult *res)
Definition: fe-exec.c:671
#define STEP_NONBLOCK
#define free(a)
Definition: header.h:65
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2709
static void run_permutation(TestSpec *testspec, int nsteps, Step **steps)
static void run_all_permutations_recurse(TestSpec *testspec, int nsteps, Step **steps)
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1732
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define PREP_WAITING
Step ** steps
char * sql
const char * name
Definition: encode.c:521
#define pg_attribute_noreturn()
Definition: c.h:146
static void report_error_message(Step *step)
static void run_testspec(TestSpec *testspec)
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-connect.c:3905
char * PQresultErrorMessage(const PGresult *res)
Definition: fe-exec.c:2663
int i
const char * strerror(int errnum)
Definition: strerror.c:19
Step ** allsteps
#define EXIT_FAILURE
Definition: settings.h:152
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897
int session
TestSpec parseresult
#define EINTR
Definition: win32_port.h:334
#define qsort(a, b, c, d)
Definition: port.h:408
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6053
static int nconns
int spec_yyparse(void)
static volatile sig_atomic_t waiting
Definition: latch.c:115
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:6124
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
static void printResultSet(PGresult *res)
PGconn * PQconnectdb(const char *conninfo)
Definition: fe-connect.c:585