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