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