OSDN Git Service

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