PostgreSQL Source Code  git master
pg_regress.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_regress --- regression test driver
4  *
5  * This is a C implementation of the previous shell script for running
6  * the regression tests, and should be mostly compatible with it.
7  * Initial author of C translation: Magnus Hagander
8  *
9  * This code is released under the terms of the PostgreSQL License.
10  *
11  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  * src/test/regress/pg_regress.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 
19 #include "postgres_fe.h"
20 
21 #include <ctype.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25 #include <unistd.h>
26 
27 #ifdef HAVE_SYS_RESOURCE_H
28 #include <sys/time.h>
29 #include <sys/resource.h>
30 #endif
31 
32 #include "common/logging.h"
34 #include "common/string.h"
35 #include "common/username.h"
36 #include "getopt_long.h"
37 #include "lib/stringinfo.h"
38 #include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
39 #include "pg_config_paths.h"
40 #include "pg_regress.h"
41 #include "portability/instr_time.h"
42 
43 /* for resultmap we need a list of pairs of strings */
44 typedef struct _resultmap
45 {
46  char *test;
47  char *type;
48  char *resultfile;
49  struct _resultmap *next;
50 } _resultmap;
51 
52 /*
53  * Values obtained from Makefile.
54  */
55 char *host_platform = HOST_TUPLE;
56 
57 #ifndef WIN32 /* not used in WIN32 case */
58 static char *shellprog = SHELLPROG;
59 #endif
60 
61 /*
62  * On Windows we use -w in diff switches to avoid problems with inconsistent
63  * newline representation. The actual result files will generally have
64  * Windows-style newlines, but the comparison files might or might not.
65  */
66 #ifndef WIN32
67 const char *basic_diff_opts = "";
68 const char *pretty_diff_opts = "-U3";
69 #else
70 const char *basic_diff_opts = "-w";
71 const char *pretty_diff_opts = "-w -U3";
72 #endif
73 
74 /* options settable from command line */
76 bool debug = false;
77 char *inputdir = ".";
78 char *outputdir = ".";
79 char *bindir = PGBINDIR;
80 char *launcher = NULL;
81 static _stringlist *loadextension = NULL;
82 static int max_connections = 0;
83 static int max_concurrent_tests = 0;
84 static char *encoding = NULL;
85 static _stringlist *schedulelist = NULL;
86 static _stringlist *extra_tests = NULL;
87 static char *temp_instance = NULL;
88 static _stringlist *temp_configs = NULL;
89 static bool nolocale = false;
90 static bool use_existing = false;
91 static char *hostname = NULL;
92 static int port = -1;
93 static bool port_specified_by_user = false;
94 static char *dlpath = PKGLIBDIR;
95 static char *user = NULL;
96 static _stringlist *extraroles = NULL;
97 static char *config_auth_datadir = NULL;
98 
99 /* internal variables */
100 static const char *progname;
101 static char *logfilename;
102 static FILE *logfile;
103 static char *difffilename;
104 static const char *sockdir;
105 #ifdef HAVE_UNIX_SOCKETS
106 static const char *temp_sockdir;
107 static char sockself[MAXPGPATH];
108 static char socklock[MAXPGPATH];
109 #endif
110 
111 static _resultmap *resultmap = NULL;
112 
114 static bool postmaster_running = false;
115 
116 static int success_count = 0;
117 static int fail_count = 0;
118 static int fail_ignore_count = 0;
119 
120 static bool directory_exists(const char *dir);
121 static void make_directory(const char *dir);
122 
123 static void header(const char *fmt,...) pg_attribute_printf(1, 2);
124 static void status(const char *fmt,...) pg_attribute_printf(1, 2);
125 static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2, 3);
126 
127 /*
128  * allow core files if possible.
129  */
130 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
131 static void
132 unlimit_core_size(void)
133 {
134  struct rlimit lim;
135 
136  getrlimit(RLIMIT_CORE, &lim);
137  if (lim.rlim_max == 0)
138  {
139  fprintf(stderr,
140  _("%s: could not set core size: disallowed by hard limit\n"),
141  progname);
142  return;
143  }
144  else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
145  {
146  lim.rlim_cur = lim.rlim_max;
147  setrlimit(RLIMIT_CORE, &lim);
148  }
149 }
150 #endif
151 
152 
153 /*
154  * Add an item at the end of a stringlist.
155  */
156 void
157 add_stringlist_item(_stringlist **listhead, const char *str)
158 {
159  _stringlist *newentry = pg_malloc(sizeof(_stringlist));
160  _stringlist *oldentry;
161 
162  newentry->str = pg_strdup(str);
163  newentry->next = NULL;
164  if (*listhead == NULL)
165  *listhead = newentry;
166  else
167  {
168  for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
169  /* skip */ ;
170  oldentry->next = newentry;
171  }
172 }
173 
174 /*
175  * Free a stringlist.
176  */
177 static void
179 {
180  if (listhead == NULL || *listhead == NULL)
181  return;
182  if ((*listhead)->next != NULL)
183  free_stringlist(&((*listhead)->next));
184  free((*listhead)->str);
185  free(*listhead);
186  *listhead = NULL;
187 }
188 
189 /*
190  * Split a delimited string into a stringlist
191  */
192 static void
193 split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
194 {
195  char *sc = pg_strdup(s);
196  char *token = strtok(sc, delim);
197 
198  while (token)
199  {
200  add_stringlist_item(listhead, token);
201  token = strtok(NULL, delim);
202  }
203  free(sc);
204 }
205 
206 /*
207  * Print a progress banner on stdout.
208  */
209 static void
210 header(const char *fmt,...)
211 {
212  char tmp[64];
213  va_list ap;
214 
215  va_start(ap, fmt);
216  vsnprintf(tmp, sizeof(tmp), fmt, ap);
217  va_end(ap);
218 
219  fprintf(stdout, "============== %-38s ==============\n", tmp);
220  fflush(stdout);
221 }
222 
223 /*
224  * Print "doing something ..." --- supplied text should not end with newline
225  */
226 static void
227 status(const char *fmt,...)
228 {
229  va_list ap;
230 
231  va_start(ap, fmt);
232  vfprintf(stdout, fmt, ap);
233  fflush(stdout);
234  va_end(ap);
235 
236  if (logfile)
237  {
238  va_start(ap, fmt);
239  vfprintf(logfile, fmt, ap);
240  va_end(ap);
241  }
242 }
243 
244 /*
245  * Done "doing something ..."
246  */
247 static void
249 {
250  fprintf(stdout, "\n");
251  fflush(stdout);
252  if (logfile)
253  fprintf(logfile, "\n");
254 }
255 
256 /*
257  * shut down temp postmaster
258  */
259 static void
261 {
262  if (postmaster_running)
263  {
264  /* We use pg_ctl to issue the kill and wait for stop */
265  char buf[MAXPGPATH * 2];
266  int r;
267 
268  /* On Windows, system() seems not to force fflush, so... */
269  fflush(stdout);
270  fflush(stderr);
271 
272  snprintf(buf, sizeof(buf),
273  "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
274  bindir ? bindir : "",
275  bindir ? "/" : "",
276  temp_instance);
277  r = system(buf);
278  if (r != 0)
279  {
280  fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
281  progname, r);
282  _exit(2); /* not exit(), that could be recursive */
283  }
284 
285  postmaster_running = false;
286  }
287 }
288 
289 #ifdef HAVE_UNIX_SOCKETS
290 /*
291  * Remove the socket temporary directory. pg_regress never waits for a
292  * postmaster exit, so it is indeterminate whether the postmaster has yet to
293  * unlink the socket and lock file. Unlink them here so we can proceed to
294  * remove the directory. Ignore errors; leaking a temporary directory is
295  * unimportant. This can run from a signal handler. The code is not
296  * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
297  * on Windows, pg_regress does not use Unix sockets by default.
298  */
299 static void
300 remove_temp(void)
301 {
302  Assert(temp_sockdir);
303  unlink(sockself);
304  unlink(socklock);
305  rmdir(temp_sockdir);
306 }
307 
308 /*
309  * Signal handler that calls remove_temp() and reraises the signal.
310  */
311 static void
312 signal_remove_temp(int signum)
313 {
314  remove_temp();
315 
316  pqsignal(signum, SIG_DFL);
317  raise(signum);
318 }
319 
320 /*
321  * Create a temporary directory suitable for the server's Unix-domain socket.
322  * The directory will have mode 0700 or stricter, so no other OS user can open
323  * our socket to exploit our use of trust authentication. Most systems
324  * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
325  * place the directory under /tmp rather than relative to the possibly-deep
326  * current working directory.
327  *
328  * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
329  * testing to work in builds that relocate it to a directory not writable to
330  * the build/test user.
331  */
332 static const char *
333 make_temp_sockdir(void)
334 {
335  char *template = psprintf("%s/pg_regress-XXXXXX",
336  getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
337 
338  temp_sockdir = mkdtemp(template);
339  if (temp_sockdir == NULL)
340  {
341  fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
342  progname, template, strerror(errno));
343  exit(2);
344  }
345 
346  /* Stage file names for remove_temp(). Unsafe in a signal handler. */
347  UNIXSOCK_PATH(sockself, port, temp_sockdir);
348  snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
349 
350  /* Remove the directory during clean exit. */
351  atexit(remove_temp);
352 
353  /*
354  * Remove the directory before dying to the usual signals. Omit SIGQUIT,
355  * preserving it as a quick, untidy exit.
356  */
357  pqsignal(SIGHUP, signal_remove_temp);
358  pqsignal(SIGINT, signal_remove_temp);
359  pqsignal(SIGPIPE, signal_remove_temp);
360  pqsignal(SIGTERM, signal_remove_temp);
361 
362  return temp_sockdir;
363 }
364 #endif /* HAVE_UNIX_SOCKETS */
365 
366 /*
367  * Check whether string matches pattern
368  *
369  * In the original shell script, this function was implemented using expr(1),
370  * which provides basic regular expressions restricted to match starting at
371  * the string start (in conventional regex terms, there's an implicit "^"
372  * at the start of the pattern --- but no implicit "$" at the end).
373  *
374  * For now, we only support "." and ".*" as non-literal metacharacters,
375  * because that's all that anyone has found use for in resultmap. This
376  * code could be extended if more functionality is needed.
377  */
378 static bool
379 string_matches_pattern(const char *str, const char *pattern)
380 {
381  while (*str && *pattern)
382  {
383  if (*pattern == '.' && pattern[1] == '*')
384  {
385  pattern += 2;
386  /* Trailing .* matches everything. */
387  if (*pattern == '\0')
388  return true;
389 
390  /*
391  * Otherwise, scan for a text position at which we can match the
392  * rest of the pattern.
393  */
394  while (*str)
395  {
396  /*
397  * Optimization to prevent most recursion: don't recurse
398  * unless first pattern char might match this text char.
399  */
400  if (*str == *pattern || *pattern == '.')
401  {
402  if (string_matches_pattern(str, pattern))
403  return true;
404  }
405 
406  str++;
407  }
408 
409  /*
410  * End of text with no match.
411  */
412  return false;
413  }
414  else if (*pattern != '.' && *str != *pattern)
415  {
416  /*
417  * Not the single-character wildcard and no explicit match? Then
418  * time to quit...
419  */
420  return false;
421  }
422 
423  str++;
424  pattern++;
425  }
426 
427  if (*pattern == '\0')
428  return true; /* end of pattern, so declare match */
429 
430  /* End of input string. Do we have matching pattern remaining? */
431  while (*pattern == '.' && pattern[1] == '*')
432  pattern += 2;
433  if (*pattern == '\0')
434  return true; /* end of pattern, so declare match */
435 
436  return false;
437 }
438 
439 /*
440  * Replace all occurrences of "replace" in "string" with "replacement".
441  * The StringInfo will be suitably enlarged if necessary.
442  *
443  * Note: this is optimized on the assumption that most calls will find
444  * no more than one occurrence of "replace", and quite likely none.
445  */
446 void
447 replace_string(StringInfo string, const char *replace, const char *replacement)
448 {
449  int pos = 0;
450  char *ptr;
451 
452  while ((ptr = strstr(string->data + pos, replace)) != NULL)
453  {
454  /* Must copy the remainder of the string out of the StringInfo */
455  char *suffix = pg_strdup(ptr + strlen(replace));
456 
457  /* Truncate StringInfo at start of found string ... */
458  string->len = ptr - string->data;
459  /* ... and append the replacement (this restores the trailing '\0') */
460  appendStringInfoString(string, replacement);
461  /* Next search should start after the replacement */
462  pos = string->len;
463  /* Put back the remainder of the string */
464  appendStringInfoString(string, suffix);
465  free(suffix);
466  }
467 }
468 
469 /*
470  * Convert *.source found in the "source" directory, replacing certain tokens
471  * in the file contents with their intended values, and put the resulting files
472  * in the "dest" directory, replacing the ".source" prefix in their names with
473  * the given suffix.
474  */
475 static void
476 convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
477 {
478  char testtablespace[MAXPGPATH];
479  char indir[MAXPGPATH];
480  char outdir_sub[MAXPGPATH];
481  char **name;
482  char **names;
483  int count = 0;
484 
485  snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
486 
487  /* Check that indir actually exists and is a directory */
488  if (!directory_exists(indir))
489  {
490  /*
491  * No warning, to avoid noise in tests that do not have these
492  * directories; for example, ecpg, contrib and src/pl.
493  */
494  return;
495  }
496 
497  names = pgfnames(indir);
498  if (!names)
499  /* Error logged in pgfnames */
500  exit(2);
501 
502  /* Create the "dest" subdirectory if not present */
503  snprintf(outdir_sub, MAXPGPATH, "%s/%s", dest_dir, dest_subdir);
504  if (!directory_exists(outdir_sub))
505  make_directory(outdir_sub);
506 
507  snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
508 
509  /*
510  * Clean out the test tablespace dir, or create it if it doesn't exist. On
511  * Windows, doing this cleanup here makes possible to run the regression
512  * tests as a Windows administrative user account with the restricted
513  * token obtained when starting pg_regress.
514  */
515  if (directory_exists(testtablespace))
516  {
517  if (!rmtree(testtablespace, true))
518  {
519  fprintf(stderr, _("\n%s: could not remove test tablespace \"%s\"\n"),
520  progname, testtablespace);
521  exit(2);
522  }
523  }
524  make_directory(testtablespace);
525 
526  /* finally loop on each file and do the replacement */
527  for (name = names; *name; name++)
528  {
529  char srcfile[MAXPGPATH];
530  char destfile[MAXPGPATH];
531  char prefix[MAXPGPATH];
532  FILE *infile,
533  *outfile;
534  StringInfoData line;
535 
536  /* reject filenames not finishing in ".source" */
537  if (strlen(*name) < 8)
538  continue;
539  if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
540  continue;
541 
542  count++;
543 
544  /* build the full actual paths to open */
545  snprintf(prefix, strlen(*name) - 6, "%s", *name);
546  snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
547  snprintf(destfile, MAXPGPATH, "%s/%s/%s.%s", dest_dir, dest_subdir,
548  prefix, suffix);
549 
550  infile = fopen(srcfile, "r");
551  if (!infile)
552  {
553  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
554  progname, srcfile, strerror(errno));
555  exit(2);
556  }
557  outfile = fopen(destfile, "w");
558  if (!outfile)
559  {
560  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
561  progname, destfile, strerror(errno));
562  exit(2);
563  }
564 
565  initStringInfo(&line);
566 
567  while (pg_get_line_buf(infile, &line))
568  {
569  replace_string(&line, "@abs_srcdir@", inputdir);
570  replace_string(&line, "@abs_builddir@", outputdir);
571  replace_string(&line, "@testtablespace@", testtablespace);
572  replace_string(&line, "@libdir@", dlpath);
573  replace_string(&line, "@DLSUFFIX@", DLSUFFIX);
574  fputs(line.data, outfile);
575  }
576 
577  pfree(line.data);
578  fclose(infile);
579  fclose(outfile);
580  }
581 
582  /*
583  * If we didn't process any files, complain because it probably means
584  * somebody neglected to pass the needed --inputdir argument.
585  */
586  if (count <= 0)
587  {
588  fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
589  progname, indir);
590  exit(2);
591  }
592 
593  pgfnames_cleanup(names);
594 }
595 
596 /* Create the .sql and .out files from the .source files, if any */
597 static void
599 {
600  convert_sourcefiles_in("input", outputdir, "sql", "sql");
601  convert_sourcefiles_in("output", outputdir, "expected", "out");
602 }
603 
604 /*
605  * Scan resultmap file to find which platform-specific expected files to use.
606  *
607  * The format of each line of the file is
608  * testname/hostplatformpattern=substitutefile
609  * where the hostplatformpattern is evaluated per the rules of expr(1),
610  * namely, it is a standard regular expression with an implicit ^ at the start.
611  * (We currently support only a very limited subset of regular expressions,
612  * see string_matches_pattern() above.) What hostplatformpattern will be
613  * matched against is the config.guess output. (In the shell-script version,
614  * we also provided an indication of whether gcc or another compiler was in
615  * use, but that facility isn't used anymore.)
616  */
617 static void
619 {
620  char buf[MAXPGPATH];
621  FILE *f;
622 
623  /* scan the file ... */
624  snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
625  f = fopen(buf, "r");
626  if (!f)
627  {
628  /* OK if it doesn't exist, else complain */
629  if (errno == ENOENT)
630  return;
631  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
632  progname, buf, strerror(errno));
633  exit(2);
634  }
635 
636  while (fgets(buf, sizeof(buf), f))
637  {
638  char *platform;
639  char *file_type;
640  char *expected;
641  int i;
642 
643  /* strip trailing whitespace, especially the newline */
644  i = strlen(buf);
645  while (i > 0 && isspace((unsigned char) buf[i - 1]))
646  buf[--i] = '\0';
647 
648  /* parse out the line fields */
649  file_type = strchr(buf, ':');
650  if (!file_type)
651  {
652  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
653  buf);
654  exit(2);
655  }
656  *file_type++ = '\0';
657 
658  platform = strchr(file_type, ':');
659  if (!platform)
660  {
661  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
662  buf);
663  exit(2);
664  }
665  *platform++ = '\0';
666  expected = strchr(platform, '=');
667  if (!expected)
668  {
669  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
670  buf);
671  exit(2);
672  }
673  *expected++ = '\0';
674 
675  /*
676  * if it's for current platform, save it in resultmap list. Note: by
677  * adding at the front of the list, we ensure that in ambiguous cases,
678  * the last match in the resultmap file is used. This mimics the
679  * behavior of the old shell script.
680  */
681  if (string_matches_pattern(host_platform, platform))
682  {
683  _resultmap *entry = pg_malloc(sizeof(_resultmap));
684 
685  entry->test = pg_strdup(buf);
686  entry->type = pg_strdup(file_type);
687  entry->resultfile = pg_strdup(expected);
688  entry->next = resultmap;
689  resultmap = entry;
690  }
691  }
692  fclose(f);
693 }
694 
695 /*
696  * Check in resultmap if we should be looking at a different file
697  */
698 static
699 const char *
700 get_expectfile(const char *testname, const char *file)
701 {
702  char *file_type;
703  _resultmap *rm;
704 
705  /*
706  * Determine the file type from the file name. This is just what is
707  * following the last dot in the file name.
708  */
709  if (!file || !(file_type = strrchr(file, '.')))
710  return NULL;
711 
712  file_type++;
713 
714  for (rm = resultmap; rm != NULL; rm = rm->next)
715  {
716  if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
717  {
718  return rm->resultfile;
719  }
720  }
721 
722  return NULL;
723 }
724 
725 /*
726  * Prepare environment variables for running regression tests
727  */
728 static void
730 {
731  /*
732  * Set default application_name. (The test_start_function may choose to
733  * override this, but if it doesn't, we have something useful in place.)
734  */
735  setenv("PGAPPNAME", "pg_regress", 1);
736 
737  if (nolocale)
738  {
739  /*
740  * Clear out any non-C locale settings
741  */
742  unsetenv("LC_COLLATE");
743  unsetenv("LC_CTYPE");
744  unsetenv("LC_MONETARY");
745  unsetenv("LC_NUMERIC");
746  unsetenv("LC_TIME");
747  unsetenv("LANG");
748 
749  /*
750  * Most platforms have adopted the POSIX locale as their
751  * implementation-defined default locale. Exceptions include native
752  * Windows, macOS with --enable-nls, and Cygwin with --enable-nls.
753  * (Use of --enable-nls matters because libintl replaces setlocale().)
754  * Also, PostgreSQL does not support macOS with locale environment
755  * variables unset; see PostmasterMain().
756  */
757 #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
758  setenv("LANG", "C", 1);
759 #endif
760  }
761 
762  /*
763  * Set translation-related settings to English; otherwise psql will
764  * produce translated messages and produce diffs. (XXX If we ever support
765  * translation of pg_regress, this needs to be moved elsewhere, where psql
766  * is actually called.)
767  */
768  unsetenv("LANGUAGE");
769  unsetenv("LC_ALL");
770  setenv("LC_MESSAGES", "C", 1);
771 
772  /*
773  * Set encoding as requested
774  */
775  if (encoding)
776  setenv("PGCLIENTENCODING", encoding, 1);
777  else
778  unsetenv("PGCLIENTENCODING");
779 
780  /*
781  * Set timezone and datestyle for datetime-related tests
782  */
783  setenv("PGTZ", "PST8PDT", 1);
784  setenv("PGDATESTYLE", "Postgres, MDY", 1);
785 
786  /*
787  * Likewise set intervalstyle to ensure consistent results. This is a bit
788  * more painful because we must use PGOPTIONS, and we want to preserve the
789  * user's ability to set other variables through that.
790  */
791  {
792  const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
793  const char *old_pgoptions = getenv("PGOPTIONS");
794  char *new_pgoptions;
795 
796  if (!old_pgoptions)
797  old_pgoptions = "";
798  new_pgoptions = psprintf("%s %s",
799  old_pgoptions, my_pgoptions);
800  setenv("PGOPTIONS", new_pgoptions, 1);
801  free(new_pgoptions);
802  }
803 
804  if (temp_instance)
805  {
806  /*
807  * Clear out any environment vars that might cause psql to connect to
808  * the wrong postmaster, or otherwise behave in nondefault ways. (Note
809  * we also use psql's -X switch consistently, so that ~/.psqlrc files
810  * won't mess things up.) Also, set PGPORT to the temp port, and set
811  * PGHOST depending on whether we are using TCP or Unix sockets.
812  */
813  unsetenv("PGDATABASE");
814  unsetenv("PGUSER");
815  unsetenv("PGSERVICE");
816  unsetenv("PGSSLMODE");
817  unsetenv("PGREQUIRESSL");
818  unsetenv("PGCONNECT_TIMEOUT");
819  unsetenv("PGDATA");
820 #ifdef HAVE_UNIX_SOCKETS
821  if (hostname != NULL)
822  setenv("PGHOST", hostname, 1);
823  else
824  {
825  sockdir = getenv("PG_REGRESS_SOCK_DIR");
826  if (!sockdir)
827  sockdir = make_temp_sockdir();
828  setenv("PGHOST", sockdir, 1);
829  }
830 #else
831  Assert(hostname != NULL);
832  setenv("PGHOST", hostname, 1);
833 #endif
834  unsetenv("PGHOSTADDR");
835  if (port != -1)
836  {
837  char s[16];
838 
839  sprintf(s, "%d", port);
840  setenv("PGPORT", s, 1);
841  }
842  }
843  else
844  {
845  const char *pghost;
846  const char *pgport;
847 
848  /*
849  * When testing an existing install, we honor existing environment
850  * variables, except if they're overridden by command line options.
851  */
852  if (hostname != NULL)
853  {
854  setenv("PGHOST", hostname, 1);
855  unsetenv("PGHOSTADDR");
856  }
857  if (port != -1)
858  {
859  char s[16];
860 
861  sprintf(s, "%d", port);
862  setenv("PGPORT", s, 1);
863  }
864  if (user != NULL)
865  setenv("PGUSER", user, 1);
866 
867  /*
868  * However, we *don't* honor PGDATABASE, since we certainly don't wish
869  * to connect to whatever database the user might like as default.
870  * (Most tests override PGDATABASE anyway, but there are some ECPG
871  * test cases that don't.)
872  */
873  unsetenv("PGDATABASE");
874 
875  /*
876  * Report what we're connecting to
877  */
878  pghost = getenv("PGHOST");
879  pgport = getenv("PGPORT");
880 #ifndef HAVE_UNIX_SOCKETS
881  if (!pghost)
882  pghost = "localhost";
883 #endif
884 
885  if (pghost && pgport)
886  printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
887  if (pghost && !pgport)
888  printf(_("(using postmaster on %s, default port)\n"), pghost);
889  if (!pghost && pgport)
890  printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
891  if (!pghost && !pgport)
892  printf(_("(using postmaster on Unix socket, default port)\n"));
893  }
894 
896  load_resultmap();
897 }
898 
899 #ifdef ENABLE_SSPI
900 
901 /* support for config_sspi_auth() */
902 static const char *
903 fmtHba(const char *raw)
904 {
905  static char *ret;
906  const char *rp;
907  char *wp;
908 
909  wp = ret = realloc(ret, 3 + strlen(raw) * 2);
910 
911  *wp++ = '"';
912  for (rp = raw; *rp; rp++)
913  {
914  if (*rp == '"')
915  *wp++ = '"';
916  *wp++ = *rp;
917  }
918  *wp++ = '"';
919  *wp++ = '\0';
920 
921  return ret;
922 }
923 
924 /*
925  * Get account and domain/realm names for the current user. This is based on
926  * pg_SSPI_recvauth(). The returned strings use static storage.
927  */
928 static void
929 current_windows_user(const char **acct, const char **dom)
930 {
931  static char accountname[MAXPGPATH];
932  static char domainname[MAXPGPATH];
933  HANDLE token;
934  TOKEN_USER *tokenuser;
935  DWORD retlen;
936  DWORD accountnamesize = sizeof(accountname);
937  DWORD domainnamesize = sizeof(domainname);
938  SID_NAME_USE accountnameuse;
939 
940  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token))
941  {
942  fprintf(stderr,
943  _("%s: could not open process token: error code %lu\n"),
944  progname, GetLastError());
945  exit(2);
946  }
947 
948  if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
949  {
950  fprintf(stderr,
951  _("%s: could not get token information buffer size: error code %lu\n"),
952  progname, GetLastError());
953  exit(2);
954  }
955  tokenuser = pg_malloc(retlen);
956  if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
957  {
958  fprintf(stderr,
959  _("%s: could not get token information: error code %lu\n"),
960  progname, GetLastError());
961  exit(2);
962  }
963 
964  if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
965  domainname, &domainnamesize, &accountnameuse))
966  {
967  fprintf(stderr,
968  _("%s: could not look up account SID: error code %lu\n"),
969  progname, GetLastError());
970  exit(2);
971  }
972 
973  free(tokenuser);
974 
975  *acct = accountname;
976  *dom = domainname;
977 }
978 
979 /*
980  * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication. Permit
981  * the current OS user to authenticate as the bootstrap superuser and as any
982  * user named in a --create-role option.
983  *
984  * In --config-auth mode, the --user switch can be used to specify the
985  * bootstrap superuser's name, otherwise we assume it is the default.
986  */
987 static void
988 config_sspi_auth(const char *pgdata, const char *superuser_name)
989 {
990  const char *accountname,
991  *domainname;
992  char *errstr;
993  bool have_ipv6;
994  char fname[MAXPGPATH];
995  int res;
996  FILE *hba,
997  *ident;
998  _stringlist *sl;
999 
1000  /* Find out the name of the current OS user */
1001  current_windows_user(&accountname, &domainname);
1002 
1003  /* Determine the bootstrap superuser's name */
1004  if (superuser_name == NULL)
1005  {
1006  /*
1007  * Compute the default superuser name the same way initdb does.
1008  *
1009  * It's possible that this result always matches "accountname", the
1010  * value SSPI authentication discovers. But the underlying system
1011  * functions do not clearly guarantee that.
1012  */
1013  superuser_name = get_user_name(&errstr);
1014  if (superuser_name == NULL)
1015  {
1016  fprintf(stderr, "%s: %s\n", progname, errstr);
1017  exit(2);
1018  }
1019  }
1020 
1021  /*
1022  * Like initdb.c:setup_config(), determine whether the platform recognizes
1023  * ::1 (IPv6 loopback) as a numeric host address string.
1024  */
1025  {
1026  struct addrinfo *gai_result;
1027  struct addrinfo hints;
1028  WSADATA wsaData;
1029 
1030  hints.ai_flags = AI_NUMERICHOST;
1031  hints.ai_family = AF_UNSPEC;
1032  hints.ai_socktype = 0;
1033  hints.ai_protocol = 0;
1034  hints.ai_addrlen = 0;
1035  hints.ai_canonname = NULL;
1036  hints.ai_addr = NULL;
1037  hints.ai_next = NULL;
1038 
1039  have_ipv6 = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0 &&
1040  getaddrinfo("::1", NULL, &hints, &gai_result) == 0);
1041  }
1042 
1043  /* Check a Write outcome and report any error. */
1044 #define CW(cond) \
1045  do { \
1046  if (!(cond)) \
1047  { \
1048  fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), \
1049  progname, fname, strerror(errno)); \
1050  exit(2); \
1051  } \
1052  } while (0)
1053 
1054  res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
1055  if (res < 0 || res >= sizeof(fname))
1056  {
1057  /*
1058  * Truncating this name is a fatal error, because we must not fail to
1059  * overwrite an original trust-authentication pg_hba.conf.
1060  */
1061  fprintf(stderr, _("%s: directory name too long\n"), progname);
1062  exit(2);
1063  }
1064  hba = fopen(fname, "w");
1065  if (hba == NULL)
1066  {
1067  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1068  progname, fname, strerror(errno));
1069  exit(2);
1070  }
1071  CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
1072  CW(fputs("host all all 127.0.0.1/32 sspi include_realm=1 map=regress\n",
1073  hba) >= 0);
1074  if (have_ipv6)
1075  CW(fputs("host all all ::1/128 sspi include_realm=1 map=regress\n",
1076  hba) >= 0);
1077  CW(fclose(hba) == 0);
1078 
1079  snprintf(fname, sizeof(fname), "%s/pg_ident.conf", pgdata);
1080  ident = fopen(fname, "w");
1081  if (ident == NULL)
1082  {
1083  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1084  progname, fname, strerror(errno));
1085  exit(2);
1086  }
1087  CW(fputs("# Configuration written by config_sspi_auth()\n", ident) >= 0);
1088 
1089  /*
1090  * Double-quote for the benefit of account names containing whitespace or
1091  * '#'. Windows forbids the double-quote character itself, so don't
1092  * bother escaping embedded double-quote characters.
1093  */
1094  CW(fprintf(ident, "regress \"%s@%s\" %s\n",
1095  accountname, domainname, fmtHba(superuser_name)) >= 0);
1096  for (sl = extraroles; sl; sl = sl->next)
1097  CW(fprintf(ident, "regress \"%s@%s\" %s\n",
1098  accountname, domainname, fmtHba(sl->str)) >= 0);
1099  CW(fclose(ident) == 0);
1100 }
1101 
1102 #endif /* ENABLE_SSPI */
1103 
1104 /*
1105  * Issue a command via psql, connecting to the specified database
1106  *
1107  * Since we use system(), this doesn't return until the operation finishes
1108  */
1109 static void
1110 psql_command(const char *database, const char *query,...)
1111 {
1112  char query_formatted[1024];
1113  char query_escaped[2048];
1114  char psql_cmd[MAXPGPATH + 2048];
1115  va_list args;
1116  char *s;
1117  char *d;
1118 
1119  /* Generate the query with insertion of sprintf arguments */
1120  va_start(args, query);
1121  vsnprintf(query_formatted, sizeof(query_formatted), query, args);
1122  va_end(args);
1123 
1124  /* Now escape any shell double-quote metacharacters */
1125  d = query_escaped;
1126  for (s = query_formatted; *s; s++)
1127  {
1128  if (strchr("\\\"$`", *s))
1129  *d++ = '\\';
1130  *d++ = *s;
1131  }
1132  *d = '\0';
1133 
1134  /* And now we can build and execute the shell command */
1135  snprintf(psql_cmd, sizeof(psql_cmd),
1136  "\"%s%spsql\" -X -c \"%s\" \"%s\"",
1137  bindir ? bindir : "",
1138  bindir ? "/" : "",
1139  query_escaped,
1140  database);
1141 
1142  if (system(psql_cmd) != 0)
1143  {
1144  /* psql probably already reported the error */
1145  fprintf(stderr, _("command failed: %s\n"), psql_cmd);
1146  exit(2);
1147  }
1148 }
1149 
1150 /*
1151  * Spawn a process to execute the given shell command; don't wait for it
1152  *
1153  * Returns the process ID (or HANDLE) so we can wait for it later
1154  */
1155 PID_TYPE
1156 spawn_process(const char *cmdline)
1157 {
1158 #ifndef WIN32
1159  pid_t pid;
1160 
1161  /*
1162  * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
1163  * ... does anyone still care about systems where that doesn't work?
1164  */
1165  fflush(stdout);
1166  fflush(stderr);
1167  if (logfile)
1168  fflush(logfile);
1169 
1170  pid = fork();
1171  if (pid == -1)
1172  {
1173  fprintf(stderr, _("%s: could not fork: %s\n"),
1174  progname, strerror(errno));
1175  exit(2);
1176  }
1177  if (pid == 0)
1178  {
1179  /*
1180  * In child
1181  *
1182  * Instead of using system(), exec the shell directly, and tell it to
1183  * "exec" the command too. This saves two useless processes per
1184  * parallel test case.
1185  */
1186  char *cmdline2;
1187 
1188  cmdline2 = psprintf("exec %s", cmdline);
1189  execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
1190  fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
1191  progname, shellprog, strerror(errno));
1192  _exit(1); /* not exit() here... */
1193  }
1194  /* in parent */
1195  return pid;
1196 #else
1197  PROCESS_INFORMATION pi;
1198  char *cmdline2;
1199  HANDLE restrictedToken;
1200  const char *comspec;
1201 
1202  /* Find CMD.EXE location using COMSPEC, if it's set */
1203  comspec = getenv("COMSPEC");
1204  if (comspec == NULL)
1205  comspec = "CMD";
1206 
1207  memset(&pi, 0, sizeof(pi));
1208  cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
1209 
1210  if ((restrictedToken =
1211  CreateRestrictedProcess(cmdline2, &pi)) == 0)
1212  exit(2);
1213 
1214  CloseHandle(pi.hThread);
1215  return pi.hProcess;
1216 #endif
1217 }
1218 
1219 /*
1220  * Count bytes in file
1221  */
1222 static long
1223 file_size(const char *file)
1224 {
1225  long r;
1226  FILE *f = fopen(file, "r");
1227 
1228  if (!f)
1229  {
1230  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1231  progname, file, strerror(errno));
1232  return -1;
1233  }
1234  fseek(f, 0, SEEK_END);
1235  r = ftell(f);
1236  fclose(f);
1237  return r;
1238 }
1239 
1240 /*
1241  * Count lines in file
1242  */
1243 static int
1244 file_line_count(const char *file)
1245 {
1246  int c;
1247  int l = 0;
1248  FILE *f = fopen(file, "r");
1249 
1250  if (!f)
1251  {
1252  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1253  progname, file, strerror(errno));
1254  return -1;
1255  }
1256  while ((c = fgetc(f)) != EOF)
1257  {
1258  if (c == '\n')
1259  l++;
1260  }
1261  fclose(f);
1262  return l;
1263 }
1264 
1265 bool
1266 file_exists(const char *file)
1267 {
1268  FILE *f = fopen(file, "r");
1269 
1270  if (!f)
1271  return false;
1272  fclose(f);
1273  return true;
1274 }
1275 
1276 static bool
1277 directory_exists(const char *dir)
1278 {
1279  struct stat st;
1280 
1281  if (stat(dir, &st) != 0)
1282  return false;
1283  if (S_ISDIR(st.st_mode))
1284  return true;
1285  return false;
1286 }
1287 
1288 /* Create a directory */
1289 static void
1290 make_directory(const char *dir)
1291 {
1292  if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1293  {
1294  fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1295  progname, dir, strerror(errno));
1296  exit(2);
1297  }
1298 }
1299 
1300 /*
1301  * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1302  */
1303 static char *
1304 get_alternative_expectfile(const char *expectfile, int i)
1305 {
1306  char *last_dot;
1307  int ssize = strlen(expectfile) + 2 + 1;
1308  char *tmp;
1309  char *s;
1310 
1311  if (!(tmp = (char *) malloc(ssize)))
1312  return NULL;
1313 
1314  if (!(s = (char *) malloc(ssize)))
1315  {
1316  free(tmp);
1317  return NULL;
1318  }
1319 
1320  strcpy(tmp, expectfile);
1321  last_dot = strrchr(tmp, '.');
1322  if (!last_dot)
1323  {
1324  free(tmp);
1325  free(s);
1326  return NULL;
1327  }
1328  *last_dot = '\0';
1329  snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1330  free(tmp);
1331  return s;
1332 }
1333 
1334 /*
1335  * Run a "diff" command and also check that it didn't crash
1336  */
1337 static int
1338 run_diff(const char *cmd, const char *filename)
1339 {
1340  int r;
1341 
1342  r = system(cmd);
1343  if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1344  {
1345  fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1346  exit(2);
1347  }
1348 #ifdef WIN32
1349 
1350  /*
1351  * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1352  * but produces nothing to stdout, so we check for that here.
1353  */
1354  if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1355  {
1356  fprintf(stderr, _("diff command not found: %s\n"), cmd);
1357  exit(2);
1358  }
1359 #endif
1360 
1361  return WEXITSTATUS(r);
1362 }
1363 
1364 /*
1365  * Check the actual result file for the given test against expected results
1366  *
1367  * Returns true if different (failure), false if correct match found.
1368  * In the true case, the diff is appended to the diffs file.
1369  */
1370 static bool
1371 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1372 {
1373  char expectfile[MAXPGPATH];
1374  char diff[MAXPGPATH];
1375  char cmd[MAXPGPATH * 3];
1376  char best_expect_file[MAXPGPATH];
1377  FILE *difffile;
1378  int best_line_count;
1379  int i;
1380  int l;
1381  const char *platform_expectfile;
1382 
1383  /*
1384  * We can pass either the resultsfile or the expectfile, they should have
1385  * the same type (filename.type) anyway.
1386  */
1387  platform_expectfile = get_expectfile(testname, resultsfile);
1388 
1389  strlcpy(expectfile, default_expectfile, sizeof(expectfile));
1390  if (platform_expectfile)
1391  {
1392  /*
1393  * Replace everything after the last slash in expectfile with what the
1394  * platform_expectfile contains.
1395  */
1396  char *p = strrchr(expectfile, '/');
1397 
1398  if (p)
1399  strcpy(++p, platform_expectfile);
1400  }
1401 
1402  /* Name to use for temporary diff file */
1403  snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1404 
1405  /* OK, run the diff */
1406  snprintf(cmd, sizeof(cmd),
1407  "diff %s \"%s\" \"%s\" > \"%s\"",
1408  basic_diff_opts, expectfile, resultsfile, diff);
1409 
1410  /* Is the diff file empty? */
1411  if (run_diff(cmd, diff) == 0)
1412  {
1413  unlink(diff);
1414  return false;
1415  }
1416 
1417  /* There may be secondary comparison files that match better */
1418  best_line_count = file_line_count(diff);
1419  strcpy(best_expect_file, expectfile);
1420 
1421  for (i = 0; i <= 9; i++)
1422  {
1423  char *alt_expectfile;
1424 
1425  alt_expectfile = get_alternative_expectfile(expectfile, i);
1426  if (!alt_expectfile)
1427  {
1428  fprintf(stderr, _("Unable to check secondary comparison files: %s\n"),
1429  strerror(errno));
1430  exit(2);
1431  }
1432 
1433  if (!file_exists(alt_expectfile))
1434  {
1435  free(alt_expectfile);
1436  continue;
1437  }
1438 
1439  snprintf(cmd, sizeof(cmd),
1440  "diff %s \"%s\" \"%s\" > \"%s\"",
1441  basic_diff_opts, alt_expectfile, resultsfile, diff);
1442 
1443  if (run_diff(cmd, diff) == 0)
1444  {
1445  unlink(diff);
1446  free(alt_expectfile);
1447  return false;
1448  }
1449 
1450  l = file_line_count(diff);
1451  if (l < best_line_count)
1452  {
1453  /* This diff was a better match than the last one */
1454  best_line_count = l;
1455  strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
1456  }
1457  free(alt_expectfile);
1458  }
1459 
1460  /*
1461  * fall back on the canonical results file if we haven't tried it yet and
1462  * haven't found a complete match yet.
1463  */
1464 
1465  if (platform_expectfile)
1466  {
1467  snprintf(cmd, sizeof(cmd),
1468  "diff %s \"%s\" \"%s\" > \"%s\"",
1469  basic_diff_opts, default_expectfile, resultsfile, diff);
1470 
1471  if (run_diff(cmd, diff) == 0)
1472  {
1473  /* No diff = no changes = good */
1474  unlink(diff);
1475  return false;
1476  }
1477 
1478  l = file_line_count(diff);
1479  if (l < best_line_count)
1480  {
1481  /* This diff was a better match than the last one */
1482  best_line_count = l;
1483  strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
1484  }
1485  }
1486 
1487  /*
1488  * Use the best comparison file to generate the "pretty" diff, which we
1489  * append to the diffs summary file.
1490  */
1491 
1492  /* Write diff header */
1493  difffile = fopen(difffilename, "a");
1494  if (difffile)
1495  {
1496  fprintf(difffile,
1497  "diff %s %s %s\n",
1498  pretty_diff_opts, best_expect_file, resultsfile);
1499  fclose(difffile);
1500  }
1501 
1502  /* Run diff */
1503  snprintf(cmd, sizeof(cmd),
1504  "diff %s \"%s\" \"%s\" >> \"%s\"",
1505  pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1506  run_diff(cmd, difffilename);
1507 
1508  unlink(diff);
1509  return true;
1510 }
1511 
1512 /*
1513  * Wait for specified subprocesses to finish, and return their exit
1514  * statuses into statuses[] and stop times into stoptimes[]
1515  *
1516  * If names isn't NULL, print each subprocess's name as it finishes
1517  *
1518  * Note: it's OK to scribble on the pids array, but not on the names array
1519  */
1520 static void
1521 wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
1522  char **names, int num_tests)
1523 {
1524  int tests_left;
1525  int i;
1526 
1527 #ifdef WIN32
1528  PID_TYPE *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
1529 
1530  memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1531 #endif
1532 
1533  tests_left = num_tests;
1534  while (tests_left > 0)
1535  {
1536  PID_TYPE p;
1537 
1538 #ifndef WIN32
1539  int exit_status;
1540 
1541  p = wait(&exit_status);
1542 
1543  if (p == INVALID_PID)
1544  {
1545  fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1546  strerror(errno));
1547  exit(2);
1548  }
1549 #else
1550  DWORD exit_status;
1551  int r;
1552 
1553  r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1554  if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1555  {
1556  fprintf(stderr, _("failed to wait for subprocesses: error code %lu\n"),
1557  GetLastError());
1558  exit(2);
1559  }
1560  p = active_pids[r - WAIT_OBJECT_0];
1561  /* compact the active_pids array */
1562  active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1563 #endif /* WIN32 */
1564 
1565  for (i = 0; i < num_tests; i++)
1566  {
1567  if (p == pids[i])
1568  {
1569 #ifdef WIN32
1570  GetExitCodeProcess(pids[i], &exit_status);
1571  CloseHandle(pids[i]);
1572 #endif
1573  pids[i] = INVALID_PID;
1574  statuses[i] = (int) exit_status;
1575  INSTR_TIME_SET_CURRENT(stoptimes[i]);
1576  if (names)
1577  status(" %s", names[i]);
1578  tests_left--;
1579  break;
1580  }
1581  }
1582  }
1583 
1584 #ifdef WIN32
1585  free(active_pids);
1586 #endif
1587 }
1588 
1589 /*
1590  * report nonzero exit code from a test process
1591  */
1592 static void
1593 log_child_failure(int exitstatus)
1594 {
1595  if (WIFEXITED(exitstatus))
1596  status(_(" (test process exited with exit code %d)"),
1597  WEXITSTATUS(exitstatus));
1598  else if (WIFSIGNALED(exitstatus))
1599  {
1600 #if defined(WIN32)
1601  status(_(" (test process was terminated by exception 0x%X)"),
1602  WTERMSIG(exitstatus));
1603 #else
1604  status(_(" (test process was terminated by signal %d: %s)"),
1605  WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
1606 #endif
1607  }
1608  else
1609  status(_(" (test process exited with unrecognized status %d)"),
1610  exitstatus);
1611 }
1612 
1613 /*
1614  * Run all the tests specified in one schedule file
1615  */
1616 static void
1617 run_schedule(const char *schedule, test_start_function startfunc,
1618  postprocess_result_function postfunc)
1619 {
1620 #define MAX_PARALLEL_TESTS 100
1621  char *tests[MAX_PARALLEL_TESTS];
1622  _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1623  _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1626  instr_time starttimes[MAX_PARALLEL_TESTS];
1627  instr_time stoptimes[MAX_PARALLEL_TESTS];
1628  int statuses[MAX_PARALLEL_TESTS];
1629  _stringlist *ignorelist = NULL;
1630  char scbuf[1024];
1631  FILE *scf;
1632  int line_num = 0;
1633 
1634  memset(tests, 0, sizeof(tests));
1635  memset(resultfiles, 0, sizeof(resultfiles));
1636  memset(expectfiles, 0, sizeof(expectfiles));
1637  memset(tags, 0, sizeof(tags));
1638 
1639  scf = fopen(schedule, "r");
1640  if (!scf)
1641  {
1642  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1643  progname, schedule, strerror(errno));
1644  exit(2);
1645  }
1646 
1647  while (fgets(scbuf, sizeof(scbuf), scf))
1648  {
1649  char *test = NULL;
1650  char *c;
1651  int num_tests;
1652  bool inword;
1653  int i;
1654 
1655  line_num++;
1656 
1657  /* strip trailing whitespace, especially the newline */
1658  i = strlen(scbuf);
1659  while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1660  scbuf[--i] = '\0';
1661 
1662  if (scbuf[0] == '\0' || scbuf[0] == '#')
1663  continue;
1664  if (strncmp(scbuf, "test: ", 6) == 0)
1665  test = scbuf + 6;
1666  else if (strncmp(scbuf, "ignore: ", 8) == 0)
1667  {
1668  c = scbuf + 8;
1669  while (*c && isspace((unsigned char) *c))
1670  c++;
1671  add_stringlist_item(&ignorelist, c);
1672 
1673  /*
1674  * Note: ignore: lines do not run the test, they just say that
1675  * failure of this test when run later on is to be ignored. A bit
1676  * odd but that's how the shell-script version did it.
1677  */
1678  continue;
1679  }
1680  else
1681  {
1682  fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1683  schedule, line_num, scbuf);
1684  exit(2);
1685  }
1686 
1687  num_tests = 0;
1688  inword = false;
1689  for (c = test;; c++)
1690  {
1691  if (*c == '\0' || isspace((unsigned char) *c))
1692  {
1693  if (inword)
1694  {
1695  /* Reached end of a test name */
1696  char sav;
1697 
1698  if (num_tests >= MAX_PARALLEL_TESTS)
1699  {
1700  fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
1701  MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
1702  exit(2);
1703  }
1704  sav = *c;
1705  *c = '\0';
1706  tests[num_tests] = pg_strdup(test);
1707  num_tests++;
1708  *c = sav;
1709  inword = false;
1710  }
1711  if (*c == '\0')
1712  break; /* loop exit is here */
1713  }
1714  else if (!inword)
1715  {
1716  /* Start of a test name */
1717  test = c;
1718  inword = true;
1719  }
1720  }
1721 
1722  if (num_tests == 0)
1723  {
1724  fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1725  schedule, line_num, scbuf);
1726  exit(2);
1727  }
1728 
1729  if (num_tests == 1)
1730  {
1731  status(_("test %-28s ... "), tests[0]);
1732  pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1733  INSTR_TIME_SET_CURRENT(starttimes[0]);
1734  wait_for_tests(pids, statuses, stoptimes, NULL, 1);
1735  /* status line is finished below */
1736  }
1737  else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
1738  {
1739  fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
1740  max_concurrent_tests, schedule, line_num, scbuf);
1741  exit(2);
1742  }
1743  else if (max_connections > 0 && max_connections < num_tests)
1744  {
1745  int oldest = 0;
1746 
1747  status(_("parallel group (%d tests, in groups of %d): "),
1748  num_tests, max_connections);
1749  for (i = 0; i < num_tests; i++)
1750  {
1751  if (i - oldest >= max_connections)
1752  {
1753  wait_for_tests(pids + oldest, statuses + oldest,
1754  stoptimes + oldest,
1755  tests + oldest, i - oldest);
1756  oldest = i;
1757  }
1758  pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1759  INSTR_TIME_SET_CURRENT(starttimes[i]);
1760  }
1761  wait_for_tests(pids + oldest, statuses + oldest,
1762  stoptimes + oldest,
1763  tests + oldest, i - oldest);
1764  status_end();
1765  }
1766  else
1767  {
1768  status(_("parallel group (%d tests): "), num_tests);
1769  for (i = 0; i < num_tests; i++)
1770  {
1771  pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1772  INSTR_TIME_SET_CURRENT(starttimes[i]);
1773  }
1774  wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
1775  status_end();
1776  }
1777 
1778  /* Check results for all tests */
1779  for (i = 0; i < num_tests; i++)
1780  {
1781  _stringlist *rl,
1782  *el,
1783  *tl;
1784  bool differ = false;
1785 
1786  if (num_tests > 1)
1787  status(_(" %-28s ... "), tests[i]);
1788 
1789  /*
1790  * Advance over all three lists simultaneously.
1791  *
1792  * Compare resultfiles[j] with expectfiles[j] always. Tags are
1793  * optional but if there are tags, the tag list has the same
1794  * length as the other two lists.
1795  */
1796  for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1797  rl != NULL; /* rl and el have the same length */
1798  rl = rl->next, el = el->next,
1799  tl = tl ? tl->next : NULL)
1800  {
1801  bool newdiff;
1802 
1803  if (postfunc)
1804  (*postfunc) (rl->str);
1805  newdiff = results_differ(tests[i], rl->str, el->str);
1806  if (newdiff && tl)
1807  {
1808  printf("%s ", tl->str);
1809  }
1810  differ |= newdiff;
1811  }
1812 
1813  if (differ)
1814  {
1815  bool ignore = false;
1816  _stringlist *sl;
1817 
1818  for (sl = ignorelist; sl != NULL; sl = sl->next)
1819  {
1820  if (strcmp(tests[i], sl->str) == 0)
1821  {
1822  ignore = true;
1823  break;
1824  }
1825  }
1826  if (ignore)
1827  {
1828  status(_("failed (ignored)"));
1830  }
1831  else
1832  {
1833  status(_("FAILED"));
1834  fail_count++;
1835  }
1836  }
1837  else
1838  {
1839  status(_("ok ")); /* align with FAILED */
1840  success_count++;
1841  }
1842 
1843  if (statuses[i] != 0)
1844  log_child_failure(statuses[i]);
1845 
1846  INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
1847  status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptimes[i]));
1848 
1849  status_end();
1850  }
1851 
1852  for (i = 0; i < num_tests; i++)
1853  {
1854  pg_free(tests[i]);
1855  tests[i] = NULL;
1856  free_stringlist(&resultfiles[i]);
1857  free_stringlist(&expectfiles[i]);
1858  free_stringlist(&tags[i]);
1859  }
1860  }
1861 
1862  free_stringlist(&ignorelist);
1863 
1864  fclose(scf);
1865 }
1866 
1867 /*
1868  * Run a single test
1869  */
1870 static void
1872  postprocess_result_function postfunc)
1873 {
1874  PID_TYPE pid;
1875  instr_time starttime;
1876  instr_time stoptime;
1877  int exit_status;
1878  _stringlist *resultfiles = NULL;
1879  _stringlist *expectfiles = NULL;
1880  _stringlist *tags = NULL;
1881  _stringlist *rl,
1882  *el,
1883  *tl;
1884  bool differ = false;
1885 
1886  status(_("test %-28s ... "), test);
1887  pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
1888  INSTR_TIME_SET_CURRENT(starttime);
1889  wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
1890 
1891  /*
1892  * Advance over all three lists simultaneously.
1893  *
1894  * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1895  * but if there are tags, the tag list has the same length as the other
1896  * two lists.
1897  */
1898  for (rl = resultfiles, el = expectfiles, tl = tags;
1899  rl != NULL; /* rl and el have the same length */
1900  rl = rl->next, el = el->next,
1901  tl = tl ? tl->next : NULL)
1902  {
1903  bool newdiff;
1904 
1905  if (postfunc)
1906  (*postfunc) (rl->str);
1907  newdiff = results_differ(test, rl->str, el->str);
1908  if (newdiff && tl)
1909  {
1910  printf("%s ", tl->str);
1911  }
1912  differ |= newdiff;
1913  }
1914 
1915  if (differ)
1916  {
1917  status(_("FAILED"));
1918  fail_count++;
1919  }
1920  else
1921  {
1922  status(_("ok ")); /* align with FAILED */
1923  success_count++;
1924  }
1925 
1926  if (exit_status != 0)
1927  log_child_failure(exit_status);
1928 
1929  INSTR_TIME_SUBTRACT(stoptime, starttime);
1930  status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptime));
1931 
1932  status_end();
1933 }
1934 
1935 /*
1936  * Create the summary-output files (making them empty if already existing)
1937  */
1938 static void
1940 {
1941  char file[MAXPGPATH];
1942  FILE *difffile;
1943 
1944  /* create outputdir directory if not present */
1947 
1948  /* create the log file (copy of running status output) */
1949  snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1950  logfilename = pg_strdup(file);
1951  logfile = fopen(logfilename, "w");
1952  if (!logfile)
1953  {
1954  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1955  progname, logfilename, strerror(errno));
1956  exit(2);
1957  }
1958 
1959  /* create the diffs file as empty */
1960  snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1961  difffilename = pg_strdup(file);
1962  difffile = fopen(difffilename, "w");
1963  if (!difffile)
1964  {
1965  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1966  progname, difffilename, strerror(errno));
1967  exit(2);
1968  }
1969  /* we don't keep the diffs file open continuously */
1970  fclose(difffile);
1971 
1972  /* also create the results directory if not present */
1973  snprintf(file, sizeof(file), "%s/results", outputdir);
1974  if (!directory_exists(file))
1975  make_directory(file);
1976 }
1977 
1978 static void
1980 {
1981  header(_("dropping database \"%s\""), dbname);
1982  psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1983 }
1984 
1985 static void
1987 {
1988  _stringlist *sl;
1989 
1990  /*
1991  * We use template0 so that any installation-local cruft in template1 will
1992  * not mess up the tests.
1993  */
1994  header(_("creating database \"%s\""), dbname);
1995  if (encoding)
1996  psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
1997  (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1998  else
1999  psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
2000  (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
2001  psql_command(dbname,
2002  "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
2003  "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
2004  "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
2005  "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
2006  "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
2007  "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
2008  dbname, dbname, dbname, dbname, dbname, dbname);
2009 
2010  /*
2011  * Install any requested extensions. We use CREATE IF NOT EXISTS so that
2012  * this will work whether or not the extension is preinstalled.
2013  */
2014  for (sl = loadextension; sl != NULL; sl = sl->next)
2015  {
2016  header(_("installing %s"), sl->str);
2017  psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
2018  }
2019 }
2020 
2021 static void
2022 drop_role_if_exists(const char *rolename)
2023 {
2024  header(_("dropping role \"%s\""), rolename);
2025  psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
2026 }
2027 
2028 static void
2029 create_role(const char *rolename, const _stringlist *granted_dbs)
2030 {
2031  header(_("creating role \"%s\""), rolename);
2032  psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
2033  for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
2034  {
2035  psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
2036  granted_dbs->str, rolename);
2037  }
2038 }
2039 
2040 static void
2041 help(void)
2042 {
2043  printf(_("PostgreSQL regression test driver\n"));
2044  printf(_("\n"));
2045  printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
2046  printf(_("\n"));
2047  printf(_("Options:\n"));
2048  printf(_(" --bindir=BINPATH use BINPATH for programs that are run;\n"));
2049  printf(_(" if empty, use PATH from the environment\n"));
2050  printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
2051  printf(_(" --create-role=ROLE create the specified role before testing\n"));
2052  printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
2053  printf(_(" --debug turn on debug mode in programs that are run\n"));
2054  printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
2055  printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
2056  printf(_(" -h, --help show this help, then exit\n"));
2057  printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
2058  printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
2059  printf(_(" --load-extension=EXT load the named extension before running the\n"));
2060  printf(_(" tests; can appear multiple times\n"));
2061  printf(_(" --max-connections=N maximum number of concurrent connections\n"));
2062  printf(_(" (default is 0, meaning unlimited)\n"));
2063  printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n"));
2064  printf(_(" (default is 0, meaning unlimited)\n"));
2065  printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
2066  printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
2067  printf(_(" (can be used multiple times to concatenate)\n"));
2068  printf(_(" --temp-instance=DIR create a temporary instance in DIR\n"));
2069  printf(_(" --use-existing use an existing installation\n"));
2070  printf(_(" -V, --version output version information, then exit\n"));
2071  printf(_("\n"));
2072  printf(_("Options for \"temp-instance\" mode:\n"));
2073  printf(_(" --no-locale use C locale\n"));
2074  printf(_(" --port=PORT start postmaster on PORT\n"));
2075  printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
2076  printf(_("\n"));
2077  printf(_("Options for using an existing installation:\n"));
2078  printf(_(" --host=HOST use postmaster running on HOST\n"));
2079  printf(_(" --port=PORT use postmaster running at PORT\n"));
2080  printf(_(" --user=USER connect as USER\n"));
2081  printf(_("\n"));
2082  printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
2083  printf(_("if the tests could not be run for some reason.\n"));
2084  printf(_("\n"));
2085  printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
2086  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
2087 }
2088 
2089 int
2090 regression_main(int argc, char *argv[],
2091  init_function ifunc,
2092  test_start_function startfunc,
2093  postprocess_result_function postfunc)
2094 {
2095  static struct option long_options[] = {
2096  {"help", no_argument, NULL, 'h'},
2097  {"version", no_argument, NULL, 'V'},
2098  {"dbname", required_argument, NULL, 1},
2099  {"debug", no_argument, NULL, 2},
2100  {"inputdir", required_argument, NULL, 3},
2101  {"max-connections", required_argument, NULL, 5},
2102  {"encoding", required_argument, NULL, 6},
2103  {"outputdir", required_argument, NULL, 7},
2104  {"schedule", required_argument, NULL, 8},
2105  {"temp-instance", required_argument, NULL, 9},
2106  {"no-locale", no_argument, NULL, 10},
2107  {"host", required_argument, NULL, 13},
2108  {"port", required_argument, NULL, 14},
2109  {"user", required_argument, NULL, 15},
2110  {"bindir", required_argument, NULL, 16},
2111  {"dlpath", required_argument, NULL, 17},
2112  {"create-role", required_argument, NULL, 18},
2113  {"temp-config", required_argument, NULL, 19},
2114  {"use-existing", no_argument, NULL, 20},
2115  {"launcher", required_argument, NULL, 21},
2116  {"load-extension", required_argument, NULL, 22},
2117  {"config-auth", required_argument, NULL, 24},
2118  {"max-concurrent-tests", required_argument, NULL, 25},
2119  {NULL, 0, NULL, 0}
2120  };
2121 
2122  bool use_unix_sockets;
2123  _stringlist *sl;
2124  int c;
2125  int i;
2126  int option_index;
2127  char buf[MAXPGPATH * 4];
2128  char buf2[MAXPGPATH * 4];
2129 
2130  pg_logging_init(argv[0]);
2131  progname = get_progname(argv[0]);
2132  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
2133 
2135 
2136  atexit(stop_postmaster);
2137 
2138 #if !defined(HAVE_UNIX_SOCKETS)
2139  use_unix_sockets = false;
2140 #elif defined(WIN32)
2141 
2142  /*
2143  * We don't use Unix-domain sockets on Windows by default, even if the
2144  * build supports them. (See comment at remove_temp() for a reason.)
2145  * Override at your own risk.
2146  */
2147  use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
2148 #else
2149  use_unix_sockets = true;
2150 #endif
2151 
2152  if (!use_unix_sockets)
2153  hostname = "localhost";
2154 
2155  /*
2156  * We call the initialization function here because that way we can set
2157  * default parameters and let them be overwritten by the commandline.
2158  */
2159  ifunc(argc, argv);
2160 
2161  if (getenv("PG_REGRESS_DIFF_OPTS"))
2162  pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
2163 
2164  while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
2165  {
2166  switch (c)
2167  {
2168  case 'h':
2169  help();
2170  exit(0);
2171  case 'V':
2172  puts("pg_regress (PostgreSQL) " PG_VERSION);
2173  exit(0);
2174  case 1:
2175 
2176  /*
2177  * If a default database was specified, we need to remove it
2178  * before we add the specified one.
2179  */
2180  free_stringlist(&dblist);
2181  split_to_stringlist(optarg, ",", &dblist);
2182  break;
2183  case 2:
2184  debug = true;
2185  break;
2186  case 3:
2188  break;
2189  case 5:
2190  max_connections = atoi(optarg);
2191  break;
2192  case 6:
2194  break;
2195  case 7:
2197  break;
2198  case 8:
2199  add_stringlist_item(&schedulelist, optarg);
2200  break;
2201  case 9:
2203  break;
2204  case 10:
2205  nolocale = true;
2206  break;
2207  case 13:
2209  break;
2210  case 14:
2211  port = atoi(optarg);
2212  port_specified_by_user = true;
2213  break;
2214  case 15:
2215  user = pg_strdup(optarg);
2216  break;
2217  case 16:
2218  /* "--bindir=" means to use PATH */
2219  if (strlen(optarg))
2220  bindir = pg_strdup(optarg);
2221  else
2222  bindir = NULL;
2223  break;
2224  case 17:
2225  dlpath = pg_strdup(optarg);
2226  break;
2227  case 18:
2228  split_to_stringlist(optarg, ",", &extraroles);
2229  break;
2230  case 19:
2231  add_stringlist_item(&temp_configs, optarg);
2232  break;
2233  case 20:
2234  use_existing = true;
2235  break;
2236  case 21:
2238  break;
2239  case 22:
2240  add_stringlist_item(&loadextension, optarg);
2241  break;
2242  case 24:
2244  break;
2245  case 25:
2246  max_concurrent_tests = atoi(optarg);
2247  break;
2248  default:
2249  /* getopt_long already emitted a complaint */
2250  fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2251  progname);
2252  exit(2);
2253  }
2254  }
2255 
2256  /*
2257  * if we still have arguments, they are extra tests to run
2258  */
2259  while (argc - optind >= 1)
2260  {
2261  add_stringlist_item(&extra_tests, argv[optind]);
2262  optind++;
2263  }
2264 
2265  if (config_auth_datadir)
2266  {
2267 #ifdef ENABLE_SSPI
2268  if (!use_unix_sockets)
2269  config_sspi_auth(config_auth_datadir, user);
2270 #endif
2271  exit(0);
2272  }
2273 
2275 
2276  /*
2277  * To reduce chances of interference with parallel installations, use
2278  * a port number starting in the private range (49152-65535)
2279  * calculated from the version number. This aids !HAVE_UNIX_SOCKETS
2280  * systems; elsewhere, the use of a private socket directory already
2281  * prevents interference.
2282  */
2283  port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2284 
2288 
2289  /*
2290  * Initialization
2291  */
2293 
2295 
2296 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2297  unlimit_core_size();
2298 #endif
2299 
2300  if (temp_instance)
2301  {
2302  FILE *pg_conf;
2303  const char *env_wait;
2304  int wait_seconds;
2305 
2306  /*
2307  * Prepare the temp instance
2308  */
2309 
2311  {
2312  header(_("removing existing temp instance"));
2313  if (!rmtree(temp_instance, true))
2314  {
2315  fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
2317  exit(2);
2318  }
2319  }
2320 
2321  header(_("creating temporary instance"));
2322 
2323  /* make the temp instance top directory */
2325 
2326  /* and a directory for log files */
2327  snprintf(buf, sizeof(buf), "%s/log", outputdir);
2328  if (!directory_exists(buf))
2329  make_directory(buf);
2330 
2331  /* initdb */
2332  header(_("initializing database system"));
2333  snprintf(buf, sizeof(buf),
2334  "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1",
2335  bindir ? bindir : "",
2336  bindir ? "/" : "",
2337  temp_instance,
2338  debug ? " --debug" : "",
2339  nolocale ? " --no-locale" : "",
2340  outputdir);
2341  if (system(buf))
2342  {
2343  fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2344  exit(2);
2345  }
2346 
2347  /*
2348  * Adjust the default postgresql.conf for regression testing. The user
2349  * can specify a file to be appended; in any case we expand logging
2350  * and set max_prepared_transactions to enable testing of prepared
2351  * xacts. (Note: to reduce the probability of unexpected shmmax
2352  * failures, don't set max_prepared_transactions any higher than
2353  * actually needed by the prepared_xacts regression test.)
2354  */
2355  snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
2356  pg_conf = fopen(buf, "a");
2357  if (pg_conf == NULL)
2358  {
2359  fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2360  exit(2);
2361  }
2362  fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2363  fputs("log_autovacuum_min_duration = 0\n", pg_conf);
2364  fputs("log_checkpoints = on\n", pg_conf);
2365  fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
2366  fputs("log_lock_waits = on\n", pg_conf);
2367  fputs("log_temp_files = 128kB\n", pg_conf);
2368  fputs("max_prepared_transactions = 2\n", pg_conf);
2369 
2370  for (sl = temp_configs; sl != NULL; sl = sl->next)
2371  {
2372  char *temp_config = sl->str;
2373  FILE *extra_conf;
2374  char line_buf[1024];
2375 
2376  extra_conf = fopen(temp_config, "r");
2377  if (extra_conf == NULL)
2378  {
2379  fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2380  exit(2);
2381  }
2382  while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2383  fputs(line_buf, pg_conf);
2384  fclose(extra_conf);
2385  }
2386 
2387  fclose(pg_conf);
2388 
2389 #ifdef ENABLE_SSPI
2390  if (!use_unix_sockets)
2391  {
2392  /*
2393  * Since we successfully used the same buffer for the much-longer
2394  * "initdb" command, this can't truncate.
2395  */
2396  snprintf(buf, sizeof(buf), "%s/data", temp_instance);
2397  config_sspi_auth(buf, NULL);
2398  }
2399 #elif !defined(HAVE_UNIX_SOCKETS)
2400 #error Platform has no means to secure the test installation.
2401 #endif
2402 
2403  /*
2404  * Check if there is a postmaster running already.
2405  */
2406  snprintf(buf2, sizeof(buf2),
2407  "\"%s%spsql\" -X postgres <%s 2>%s",
2408  bindir ? bindir : "",
2409  bindir ? "/" : "",
2410  DEVNULL, DEVNULL);
2411 
2412  for (i = 0; i < 16; i++)
2413  {
2414  if (system(buf2) == 0)
2415  {
2416  char s[16];
2417 
2418  if (port_specified_by_user || i == 15)
2419  {
2420  fprintf(stderr, _("port %d apparently in use\n"), port);
2422  fprintf(stderr, _("%s: could not determine an available port\n"), progname);
2423  fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2424  exit(2);
2425  }
2426 
2427  fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2428  port++;
2429  sprintf(s, "%d", port);
2430  setenv("PGPORT", s, 1);
2431  }
2432  else
2433  break;
2434  }
2435 
2436  /*
2437  * Start the temp postmaster
2438  */
2439  header(_("starting postmaster"));
2440  snprintf(buf, sizeof(buf),
2441  "\"%s%spostgres\" -D \"%s/data\" -F%s "
2442  "-c \"listen_addresses=%s\" -k \"%s\" "
2443  "> \"%s/log/postmaster.log\" 2>&1",
2444  bindir ? bindir : "",
2445  bindir ? "/" : "",
2446  temp_instance, debug ? " -d 5" : "",
2447  hostname ? hostname : "", sockdir ? sockdir : "",
2448  outputdir);
2450  if (postmaster_pid == INVALID_PID)
2451  {
2452  fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2453  progname, strerror(errno));
2454  exit(2);
2455  }
2456 
2457  /*
2458  * Wait till postmaster is able to accept connections; normally this
2459  * is only a second or so, but Cygwin is reportedly *much* slower, and
2460  * test builds using Valgrind or similar tools might be too. Hence,
2461  * allow the default timeout of 60 seconds to be overridden from the
2462  * PGCTLTIMEOUT environment variable.
2463  */
2464  env_wait = getenv("PGCTLTIMEOUT");
2465  if (env_wait != NULL)
2466  {
2467  wait_seconds = atoi(env_wait);
2468  if (wait_seconds <= 0)
2469  wait_seconds = 60;
2470  }
2471  else
2472  wait_seconds = 60;
2473 
2474  for (i = 0; i < wait_seconds; i++)
2475  {
2476  /* Done if psql succeeds */
2477  if (system(buf2) == 0)
2478  break;
2479 
2480  /*
2481  * Fail immediately if postmaster has exited
2482  */
2483 #ifndef WIN32
2484  if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
2485 #else
2486  if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2487 #endif
2488  {
2489  fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2490  exit(2);
2491  }
2492 
2493  pg_usleep(1000000L);
2494  }
2495  if (i >= wait_seconds)
2496  {
2497  fprintf(stderr, _("\n%s: postmaster did not respond within %d seconds\nExamine %s/log/postmaster.log for the reason\n"),
2498  progname, wait_seconds, outputdir);
2499 
2500  /*
2501  * If we get here, the postmaster is probably wedged somewhere in
2502  * startup. Try to kill it ungracefully rather than leaving a
2503  * stuck postmaster that might interfere with subsequent test
2504  * attempts.
2505  */
2506 #ifndef WIN32
2507  if (kill(postmaster_pid, SIGKILL) != 0 &&
2508  errno != ESRCH)
2509  fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2510  progname, strerror(errno));
2511 #else
2512  if (TerminateProcess(postmaster_pid, 255) == 0)
2513  fprintf(stderr, _("\n%s: could not kill failed postmaster: error code %lu\n"),
2514  progname, GetLastError());
2515 #endif
2516 
2517  exit(2);
2518  }
2519 
2520  postmaster_running = true;
2521 
2522 #ifdef _WIN64
2523 /* need a series of two casts to convert HANDLE without compiler warning */
2524 #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2525 #else
2526 #define ULONGPID(x) (unsigned long) (x)
2527 #endif
2528  printf(_("running on port %d with PID %lu\n"),
2530  }
2531  else
2532  {
2533  /*
2534  * Using an existing installation, so may need to get rid of
2535  * pre-existing database(s) and role(s)
2536  */
2537  if (!use_existing)
2538  {
2539  for (sl = dblist; sl; sl = sl->next)
2541  for (sl = extraroles; sl; sl = sl->next)
2542  drop_role_if_exists(sl->str);
2543  }
2544  }
2545 
2546  /*
2547  * Create the test database(s) and role(s)
2548  */
2549  if (!use_existing)
2550  {
2551  for (sl = dblist; sl; sl = sl->next)
2552  create_database(sl->str);
2553  for (sl = extraroles; sl; sl = sl->next)
2554  create_role(sl->str, dblist);
2555  }
2556 
2557  /*
2558  * Ready to run the tests
2559  */
2560  header(_("running regression test queries"));
2561 
2562  for (sl = schedulelist; sl != NULL; sl = sl->next)
2563  {
2564  run_schedule(sl->str, startfunc, postfunc);
2565  }
2566 
2567  for (sl = extra_tests; sl != NULL; sl = sl->next)
2568  {
2569  run_single_test(sl->str, startfunc, postfunc);
2570  }
2571 
2572  /*
2573  * Shut down temp installation's postmaster
2574  */
2575  if (temp_instance)
2576  {
2577  header(_("shutting down postmaster"));
2578  stop_postmaster();
2579  }
2580 
2581  /*
2582  * If there were no errors, remove the temp instance immediately to
2583  * conserve disk space. (If there were errors, we leave the instance in
2584  * place for possible manual investigation.)
2585  */
2586  if (temp_instance && fail_count == 0 && fail_ignore_count == 0)
2587  {
2588  header(_("removing temporary instance"));
2589  if (!rmtree(temp_instance, true))
2590  fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
2592  }
2593 
2594  fclose(logfile);
2595 
2596  /*
2597  * Emit nice-looking summary message
2598  */
2599  if (fail_count == 0 && fail_ignore_count == 0)
2600  snprintf(buf, sizeof(buf),
2601  _(" All %d tests passed. "),
2602  success_count);
2603  else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2604  snprintf(buf, sizeof(buf),
2605  _(" %d of %d tests passed, %d failed test(s) ignored. "),
2606  success_count,
2609  else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2610  snprintf(buf, sizeof(buf),
2611  _(" %d of %d tests failed. "),
2612  fail_count,
2614  else
2615  /* fail_count>0 && fail_ignore_count>0 */
2616  snprintf(buf, sizeof(buf),
2617  _(" %d of %d tests failed, %d of these failures ignored. "),
2621 
2622  putchar('\n');
2623  for (i = strlen(buf); i > 0; i--)
2624  putchar('=');
2625  printf("\n%s\n", buf);
2626  for (i = strlen(buf); i > 0; i--)
2627  putchar('=');
2628  putchar('\n');
2629  putchar('\n');
2630 
2631  if (file_size(difffilename) > 0)
2632  {
2633  printf(_("The differences that caused some tests to fail can be viewed in the\n"
2634  "file \"%s\". A copy of the test summary that you see\n"
2635  "above is saved in the file \"%s\".\n\n"),
2637  }
2638  else
2639  {
2640  unlink(difffilename);
2641  unlink(logfilename);
2642  }
2643 
2644  if (fail_count != 0)
2645  exit(1);
2646 
2647  return 0;
2648 }
static char * shellprog
Definition: pg_regress.c:58
char * make_absolute_path(const char *path)
Definition: path.c:608
bool pg_get_line_buf(FILE *stream, StringInfo buf)
Definition: pg_get_line.c:88
#define getaddrinfo
Definition: getaddrinfo.h:136
static char * get_alternative_expectfile(const char *expectfile, int i)
Definition: pg_regress.c:1304
static bool directory_exists(const char *dir)
Definition: pg_regress.c:1277
static void drop_role_if_exists(const char *rolename)
Definition: pg_regress.c:2022
static void drop_database_if_exists(const char *dbname)
Definition: pg_regress.c:1979
#define UNIXSOCK_PATH(path, port, sockdir)
Definition: pqcomm.h:70
char ** pgfnames(const char *path)
Definition: pgfnames.c:37
static int max_concurrent_tests
Definition: pg_regress.c:83
#define WTERMSIG(w)
Definition: win32_port.h:146
static const char * sockdir
Definition: pg_regress.c:104
static int wait_seconds
Definition: pg_ctl.c:80
static void help(void)
Definition: pg_regress.c:2041
static _stringlist * extra_tests
Definition: pg_regress.c:86
static void log_child_failure(int exitstatus)
Definition: pg_regress.c:1593
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * str
Definition: pg_regress.h:26
static void initialize_environment(void)
Definition: pg_regress.c:729
char * host_platform
Definition: pg_regress.c:55
bool debug
Definition: pg_regress.c:76
const char * get_progname(const char *argv0)
Definition: path.c:453
static void static void static void void add_stringlist_item(_stringlist **listhead, const char *str)
Definition: pg_regress.c:157
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
void get_restricted_token(void)
void pg_logging_init(const char *argv0)
Definition: logging.c:81
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
static char * encoding
Definition: pg_regress.c:84
struct timeval instr_time
Definition: instr_time.h:150
static const char * progname
Definition: pg_regress.c:100
struct _resultmap * next
Definition: pg_regress.c:49
static void make_directory(const char *dir)
Definition: pg_regress.c:1290
static void status_end(void)
Definition: pg_regress.c:248
static bool use_existing
Definition: pg_regress.c:90
static bool postmaster_running
Definition: pg_regress.c:114
#define PID_TYPE
Definition: pg_regress.h:14
const char * pghost
Definition: pgbench.c:278
#define kill(pid, sig)
Definition: win32_port.h:454
#define printf(...)
Definition: port.h:222
static FILE * logfile
Definition: pg_regress.c:102
#define SIGPIPE
Definition: win32_port.h:164
static bool string_matches_pattern(const char *str, const char *pattern)
Definition: pg_regress.c:379
static void stop_postmaster(void)
Definition: pg_regress.c:260
#define AI_NUMERICHOST
Definition: getaddrinfo.h:73
#define fprintf
Definition: port.h:220
static char * temp_instance
Definition: pg_regress.c:87
char * launcher
Definition: pg_regress.c:80
static void convert_sourcefiles(void)
Definition: pg_regress.c:598
static bool results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
Definition: pg_regress.c:1371
static void split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
Definition: pg_regress.c:193
void(* init_function)(int argc, char **argv)
Definition: pg_regress.h:35
static void convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
Definition: pg_regress.c:476
#define pg_attribute_printf(f, a)
Definition: c.h:164
static void free_stringlist(_stringlist **listhead)
Definition: pg_regress.c:178
PID_TYPE spawn_process(const char *cmdline)
Definition: pg_regress.c:1156
const char * get_user_name(char **errstr)
Definition: username.c:31
#define malloc(a)
Definition: header.h:50
#define SIGKILL
Definition: win32_port.h:163
#define sprintf
Definition: port.h:218
#define setenv(x, y, z)
Definition: win32_port.h:497
#define true
Definition: c.h:395
static char * difffilename
Definition: pg_regress.c:103
void pg_usleep(long microsec)
Definition: signal.c:53
#define required_argument
Definition: getopt_long.h:25
static _resultmap * resultmap
Definition: pg_regress.c:111
void pfree(void *pointer)
Definition: mcxt.c:1169
int optind
Definition: getopt.c:50
static _stringlist * loadextension
Definition: pg_regress.c:81
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
static void run_schedule(const char *schedule, test_start_function startfunc, postprocess_result_function postfunc)
Definition: pg_regress.c:1617
#define vsnprintf
Definition: port.h:215
#define MAXPGPATH
static void static void static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2
Definition: pg_regress.c:1110
_stringlist * dblist
Definition: pg_regress.c:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
int regression_main(int argc, char *argv[], init_function ifunc, test_start_function startfunc, postprocess_result_function postfunc)
Definition: pg_regress.c:2090
char * ai_canonname
Definition: getaddrinfo.h:106
static _stringlist * extraroles
Definition: pg_regress.c:96
static _stringlist * temp_configs
Definition: pg_regress.c:88
char * c
const char * pretty_diff_opts
Definition: pg_regress.c:68
static char * buf
Definition: pg_test_fsync.c:68
#define MAX_PARALLEL_TESTS
#define S_IRWXG
Definition: win32_port.h:301
#define INVALID_PID
Definition: pg_regress.h:15
#define SIGHUP
Definition: win32_port.h:159
static void create_role(const char *rolename, const _stringlist *granted_dbs)
Definition: pg_regress.c:2029
static char * dlpath
Definition: pg_regress.c:94
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static int success_count
Definition: pg_regress.c:116
#define DEVNULL
Definition: port.h:147
static int run_diff(const char *cmd, const char *filename)
Definition: pg_regress.c:1338
static int max_connections
Definition: pg_regress.c:82
static int port
Definition: pg_regress.c:92
static PID_TYPE postmaster_pid
Definition: pg_regress.c:113
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:42
#define no_argument
Definition: getopt_long.h:24
static char * config_auth_datadir
Definition: pg_regress.c:97
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1215
static int fail_ignore_count
Definition: pg_regress.c:118
#define WIFEXITED(w)
Definition: win32_port.h:143
static int fail_count
Definition: pg_regress.c:117
unsigned short st_mode
Definition: win32_port.h:260
char * outputdir
Definition: pg_regress.c:78
static char * logfilename
Definition: pg_regress.c:101
char * test
Definition: pg_regress.c:46
char * type
Definition: pg_regress.c:47
char * inputdir
Definition: pg_regress.c:77
static void infile(const char *filename)
Definition: zic.c:1241
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
#define free(a)
Definition: header.h:65
int ai_protocol
Definition: getaddrinfo.h:103
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define SIG_DFL
Definition: win32_port.h:154
static long file_size(const char *file)
Definition: pg_regress.c:1223
#define Assert(condition)
Definition: c.h:804
void pgfnames_cleanup(char **filenames)
Definition: pgfnames.c:86
static bool port_specified_by_user
Definition: pg_regress.c:93
static const char * get_expectfile(const char *testname, const char *file)
Definition: pg_regress.c:700
char * bindir
Definition: pg_regress.c:79
const char * pg_strsignal(int signum)
Definition: pgstrsignal.c:42
static int file_line_count(const char *file)
Definition: pg_regress.c:1244
int ai_socktype
Definition: getaddrinfo.h:102
#define strerror
Definition: port.h:229
char * dbname
Definition: streamutil.c:51
static void load_resultmap(void)
Definition: pg_regress.c:618
char * mkdtemp(char *path)
Definition: mkdtemp.c:286
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define realloc(a, b)
Definition: header.h:60
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
const char * name
Definition: encode.c:515
char * resultfile
Definition: pg_regress.c:48
void replace_string(StringInfo string, const char *replace, const char *replacement)
Definition: pg_regress.c:447
#define S_ISDIR(m)
Definition: win32_port.h:316
struct _resultmap _resultmap
static char * filename
Definition: pg_dumpall.c:91
struct addrinfo * ai_next
Definition: getaddrinfo.h:107
static char * user
Definition: pg_regress.c:95
#define S_IRWXU
Definition: win32_port.h:289
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:433
void(* postprocess_result_function)(const char *filename)
Definition: pg_regress.h:44
char * optarg
Definition: getopt.c:52
static _stringlist * schedulelist
Definition: pg_regress.c:85
bool file_exists(const char *file)
Definition: pg_regress.c:1266
struct _stringlist * next
Definition: pg_regress.h:27
int i
static bool nolocale
Definition: pg_regress.c:89
const char * basic_diff_opts
Definition: pg_regress.c:67
static void open_result_files(void)
Definition: pg_regress.c:1939
static char * outfile
size_t ai_addrlen
Definition: getaddrinfo.h:104
#define mkdir(a, b)
Definition: win32_port.h:63
PID_TYPE(* test_start_function)(const char *testname, _stringlist **resultfiles, _stringlist **expectfiles, _stringlist **tags)
Definition: pg_regress.h:38
#define vfprintf
Definition: port.h:219
int ai_flags
Definition: getaddrinfo.h:100
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
static char * hostname
Definition: pg_regress.c:91
#define WIFSIGNALED(w)
Definition: win32_port.h:144
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89
struct sockaddr * ai_addr
Definition: getaddrinfo.h:105
static void run_single_test(const char *test, test_start_function startfunc, postprocess_result_function postfunc)
Definition: pg_regress.c:1871
#define S_IRWXO
Definition: win32_port.h:313
const char * pgport
Definition: pgbench.c:279
#define stat
Definition: win32_port.h:275
#define unsetenv(x)
Definition: win32_port.h:498
#define ULONGPID(x)
#define WEXITSTATUS(w)
Definition: win32_port.h:145
static void wait_for_tests(PID_TYPE *pids, int *statuses, instr_time *stoptimes, char **names, int num_tests)
Definition: pg_regress.c:1521
static void create_database(const char *dbname)
Definition: pg_regress.c:1986
int ai_family
Definition: getaddrinfo.h:101