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