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