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