]> granicus.if.org Git - postgresql/blob - src/test/regress/pg_regress.c
Update CVS HEAD for 2007 copyright. Back branches are typically not
[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-2007, 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.25 2007/01/05 22:20:03 momjian Exp $
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres_fe.h"
20
21 #include <ctype.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25 #include <unistd.h>
26
27 #ifdef HAVE_SYS_RESOURCE_H
28 #include <sys/time.h>
29 #include <sys/resource.h>
30 #endif
31
32 #include "getopt_long.h"
33 #include "pg_config_paths.h"
34
35 #ifndef WIN32
36 #define PID_TYPE pid_t
37 #define INVALID_PID (-1)
38 #else
39 #define PID_TYPE HANDLE
40 #define INVALID_PID INVALID_HANDLE_VALUE
41 #endif
42
43
44 /* simple list of strings */
45 typedef struct _stringlist
46 {
47         char       *str;
48         struct _stringlist *next;
49 }       _stringlist;
50
51 /* for resultmap we need a list of pairs of strings */
52 typedef struct _resultmap
53 {
54         char       *test;
55         char       *resultfile;
56         struct _resultmap *next;
57 }       _resultmap;
58
59 /*
60  * Values obtained from pg_config_paths.h and Makefile.  The PG installation
61  * paths are only used in temp_install mode: we use these strings to find
62  * out where "make install" will put stuff under the temp_install directory.
63  * In non-temp_install mode, the only thing we need is the location of psql,
64  * which we expect to find in psqldir, or in the PATH if psqldir isn't given.
65  */
66 static char *bindir = PGBINDIR;
67 static char *libdir = LIBDIR;
68 static char *datadir = PGSHAREDIR;
69 static char *host_platform = HOST_TUPLE;
70 static char *makeprog = MAKEPROG;
71
72 #ifndef WIN32                                   /* not used in WIN32 case */
73 static char *shellprog = SHELLPROG;
74 #endif
75
76 /* currently we can use the same diff switches on all platforms */
77 static const char *basic_diff_opts = "-w";
78 static const char *pretty_diff_opts = "-w -C3";
79
80 /* options settable from command line */
81 static char *dbname = "regression";
82 static bool debug = false;
83 static char *inputdir = ".";
84 static char *outputdir = ".";
85 static _stringlist *loadlanguage = NULL;
86 static int      max_connections = 0;
87 static char *encoding = NULL;
88 static _stringlist *schedulelist = NULL;
89 static _stringlist *extra_tests = NULL;
90 static char *temp_install = NULL;
91 static char *top_builddir = NULL;
92 static int      temp_port = 65432;
93 static bool nolocale = false;
94 static char *psqldir = NULL;
95 static char *hostname = NULL;
96 static int      port = -1;
97 static char *user = NULL;
98
99 /* internal variables */
100 static const char *progname;
101 static char *logfilename;
102 static FILE *logfile;
103 static char *difffilename;
104
105 static _resultmap *resultmap = NULL;
106
107 static PID_TYPE postmaster_pid = INVALID_PID;
108 static bool postmaster_running = false;
109
110 static int      success_count = 0;
111 static int      fail_count = 0;
112 static int      fail_ignore_count = 0;
113
114 static void
115 header(const char *fmt,...)
116 /* This extension allows gcc to check the format string for consistency with
117    the supplied arguments. */
118 __attribute__((format(printf, 1, 2)));
119 static void
120 status(const char *fmt,...)
121 /* This extension allows gcc to check the format string for consistency with
122    the supplied arguments. */
123 __attribute__((format(printf, 1, 2)));
124 static void
125 psql_command(const char *database, const char *query,...)
126 /* This extension allows gcc to check the format string for consistency with
127    the supplied arguments. */
128 __attribute__((format(printf, 2, 3)));
129
130 /*
131  * allow core files if possible.
132  */
133 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
134 static void 
135 unlimit_core_size(void)
136 {
137         struct rlimit lim;
138         getrlimit(RLIMIT_CORE,&lim);
139         if (lim.rlim_max == 0)
140         {
141                 fprintf(stderr,
142                                 _("%s: cannot set core size,: disallowed by hard limit.\n"), 
143                                 progname);
144                 return;
145         }
146         else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
147         {
148                 lim.rlim_cur = lim.rlim_max;
149                 setrlimit(RLIMIT_CORE,&lim);
150         }       
151 }
152 #endif
153
154
155 /*
156  * Add an item at the end of a stringlist.
157  */
158 static void
159 add_stringlist_item(_stringlist ** listhead, const char *str)
160 {
161         _stringlist *newentry = malloc(sizeof(_stringlist));
162         _stringlist *oldentry;
163
164         newentry->str = strdup(str);
165         newentry->next = NULL;
166         if (*listhead == NULL)
167                 *listhead = newentry;
168         else
169         {
170                 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
171                          /* skip */ ;
172                 oldentry->next = newentry;
173         }
174 }
175
176 /*
177  * Print a progress banner on stdout.
178  */
179 static void
180 header(const char *fmt,...)
181 {
182         char            tmp[64];
183         va_list         ap;
184
185         va_start(ap, fmt);
186         vsnprintf(tmp, sizeof(tmp), fmt, ap);
187         va_end(ap);
188
189         fprintf(stdout, "============== %-38s ==============\n", tmp);
190         fflush(stdout);
191 }
192
193 /*
194  * Print "doing something ..." --- supplied text should not end with newline
195  */
196 static void
197 status(const char *fmt,...)
198 {
199         va_list         ap;
200
201         va_start(ap, fmt);
202         vfprintf(stdout, fmt, ap);
203         fflush(stdout);
204         va_end(ap);
205
206         if (logfile)
207         {
208                 va_start(ap, fmt);
209                 vfprintf(logfile, fmt, ap);
210                 va_end(ap);
211         }
212 }
213
214 /*
215  * Done "doing something ..."
216  */
217 static void
218 status_end(void)
219 {
220         fprintf(stdout, "\n");
221         fflush(stdout);
222         if (logfile)
223                 fprintf(logfile, "\n");
224 }
225
226 /*
227  * shut down temp postmaster
228  */
229 static void
230 stop_postmaster(void)
231 {
232         if (postmaster_running)
233         {
234                 /* We use pg_ctl to issue the kill and wait for stop */
235                 char            buf[MAXPGPATH * 2];
236
237                 /* On Windows, system() seems not to force fflush, so... */
238                 fflush(stdout);
239                 fflush(stderr);
240
241                 snprintf(buf, sizeof(buf),
242                                  SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
243                                  bindir, temp_install);
244                 system(buf);                    /* ignore exit status */
245                 postmaster_running = false;
246         }
247 }
248
249 /*
250  * Always exit through here, not through plain exit(), to ensure we make
251  * an effort to shut down a temp postmaster
252  */
253 static void
254 exit_nicely(int code)
255 {
256         stop_postmaster();
257         exit(code);
258 }
259
260 /*
261  * Check whether string matches pattern
262  *
263  * In the original shell script, this function was implemented using expr(1),
264  * which provides basic regular expressions restricted to match starting at
265  * the string start (in conventional regex terms, there's an implicit "^"
266  * at the start of the pattern --- but no implicit "$" at the end).
267  *
268  * For now, we only support "." and ".*" as non-literal metacharacters,
269  * because that's all that anyone has found use for in resultmap.  This
270  * code could be extended if more functionality is needed.
271  */
272 static bool
273 string_matches_pattern(const char *str, const char *pattern)
274 {
275         while (*str && *pattern)
276         {
277                 if (*pattern == '.' && pattern[1] == '*')
278                 {
279                         pattern += 2;
280                         /* Trailing .* matches everything. */
281                         if (*pattern == '\0')
282                                 return true;
283
284                         /*
285                          * Otherwise, scan for a text position at which we can match the
286                          * rest of the pattern.
287                          */
288                         while (*str)
289                         {
290                                 /*
291                                  * Optimization to prevent most recursion: don't recurse
292                                  * unless first pattern char might match this text char.
293                                  */
294                                 if (*str == *pattern || *pattern == '.')
295                                 {
296                                         if (string_matches_pattern(str, pattern))
297                                                 return true;
298                                 }
299
300                                 str++;
301                         }
302
303                         /*
304                          * End of text with no match.
305                          */
306                         return false;
307                 }
308                 else if (*pattern != '.' && *str != *pattern)
309                 {
310                         /*
311                          * Not the single-character wildcard and no explicit match? Then
312                          * time to quit...
313                          */
314                         return false;
315                 }
316
317                 str++;
318                 pattern++;
319         }
320
321         if (*pattern == '\0')
322                 return true;                    /* end of pattern, so declare match */
323
324         /* End of input string.  Do we have matching pattern remaining? */
325         while (*pattern == '.' && pattern[1] == '*')
326                 pattern += 2;
327         if (*pattern == '\0')
328                 return true;                    /* end of pattern, so declare match */
329
330         return false;
331 }
332
333 /*
334  * Scan resultmap file to find which platform-specific expected files to use.
335  *
336  * The format of each line of the file is
337  *                 testname/hostplatformpattern=substitutefile
338  * where the hostplatformpattern is evaluated per the rules of expr(1),
339  * namely, it is a standard regular expression with an implicit ^ at the start.
340  * (We currently support only a very limited subset of regular expressions,
341  * see string_matches_pattern() above.)  What hostplatformpattern will be
342  * matched against is the config.guess output.  (In the shell-script version,
343  * we also provided an indication of whether gcc or another compiler was in
344  * use, but that facility isn't used anymore.)
345  */
346 static void
347 load_resultmap(void)
348 {
349         char            buf[MAXPGPATH];
350         FILE       *f;
351
352         /* scan the file ... */
353         snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
354         f = fopen(buf, "r");
355         if (!f)
356         {
357                 /* OK if it doesn't exist, else complain */
358                 if (errno == ENOENT)
359                         return;
360                 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
361                                 progname, buf, strerror(errno));
362                 exit_nicely(2);
363         }
364
365         while (fgets(buf, sizeof(buf), f))
366         {
367                 char       *platform;
368                 char       *expected;
369                 int                     i;
370
371                 /* strip trailing whitespace, especially the newline */
372                 i = strlen(buf);
373                 while (i > 0 && isspace((unsigned char) buf[i - 1]))
374                         buf[--i] = '\0';
375
376                 /* parse out the line fields */
377                 platform = strchr(buf, '/');
378                 if (!platform)
379                 {
380                         fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
381                                         buf);
382                         exit_nicely(2);
383                 }
384                 *platform++ = '\0';
385                 expected = strchr(platform, '=');
386                 if (!expected)
387                 {
388                         fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
389                                         buf);
390                         exit_nicely(2);
391                 }
392                 *expected++ = '\0';
393
394                 /*
395                  * if it's for current platform, save it in resultmap list. Note: by
396                  * adding at the front of the list, we ensure that in ambiguous cases,
397                  * the last match in the resultmap file is used. This mimics the
398                  * behavior of the old shell script.
399                  */
400                 if (string_matches_pattern(host_platform, platform))
401                 {
402                         _resultmap *entry = malloc(sizeof(_resultmap));
403
404                         entry->test = strdup(buf);
405                         entry->resultfile = strdup(expected);
406                         entry->next = resultmap;
407                         resultmap = entry;
408                 }
409         }
410         fclose(f);
411 }
412
413 /*
414  * Handy subroutine for setting an environment variable "var" to "val"
415  */
416 static void
417 doputenv(const char *var, const char *val)
418 {
419         char       *s = malloc(strlen(var) + strlen(val) + 2);
420
421         sprintf(s, "%s=%s", var, val);
422         putenv(s);
423 }
424
425 /*
426  * Set the environment variable "pathname", prepending "addval" to its
427  * old value (if any).
428  */
429 static void
430 add_to_path(const char *pathname, char separator, const char *addval)
431 {
432         char       *oldval = getenv(pathname);
433         char       *newval;
434
435         if (!oldval || !oldval[0])
436         {
437                 /* no previous value */
438                 newval = malloc(strlen(pathname) + strlen(addval) + 2);
439                 sprintf(newval, "%s=%s", pathname, addval);
440         }
441         else
442         {
443                 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
444                 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
445         }
446         putenv(newval);
447 }
448
449 /*
450  * Prepare environment variables for running regression tests
451  */
452 static void
453 initialize_environment(void)
454 {
455         char       *tmp;
456
457         /*
458          * Clear out any non-C locale settings
459          */
460         unsetenv("LC_COLLATE");
461         unsetenv("LC_CTYPE");
462         unsetenv("LC_MONETARY");
463         unsetenv("LC_MESSAGES");
464         unsetenv("LC_NUMERIC");
465         unsetenv("LC_TIME");
466         unsetenv("LC_ALL");
467         unsetenv("LANG");
468         unsetenv("LANGUAGE");
469         /* On Windows the default locale may not be English, so force it */
470 #if defined(WIN32) || defined(__CYGWIN__)
471         putenv("LANG=en");
472 #endif
473
474         /*
475          * Set multibyte as requested
476          */
477         if (encoding)
478                 doputenv("PGCLIENTENCODING", encoding);
479         else
480                 unsetenv("PGCLIENTENCODING");
481
482         /*
483          * Set timezone and datestyle for datetime-related tests
484          */
485         putenv("PGTZ=PST8PDT");
486         putenv("PGDATESTYLE=Postgres, MDY");
487
488         if (temp_install)
489         {
490                 /*
491                  * Clear out any environment vars that might cause psql to connect to
492                  * the wrong postmaster, or otherwise behave in nondefault ways. (Note
493                  * we also use psql's -X switch consistently, so that ~/.psqlrc files
494                  * won't mess things up.)  Also, set PGPORT to the temp port, and set
495                  * or unset PGHOST depending on whether we are using TCP or Unix
496                  * sockets.
497                  */
498                 unsetenv("PGDATABASE");
499                 unsetenv("PGUSER");
500                 unsetenv("PGSERVICE");
501                 unsetenv("PGSSLMODE");
502                 unsetenv("PGREQUIRESSL");
503                 unsetenv("PGCONNECT_TIMEOUT");
504                 unsetenv("PGDATA");
505                 if (hostname != NULL)
506                         doputenv("PGHOST", hostname);
507                 else
508                         unsetenv("PGHOST");
509                 unsetenv("PGHOSTADDR");
510                 if (port != -1)
511                 {
512                         char            s[16];
513
514                         sprintf(s, "%d", port);
515                         doputenv("PGPORT", s);
516                 }
517
518                 /*
519                  * Adjust path variables to point into the temp-install tree
520                  */
521                 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
522                 sprintf(tmp, "%s/install/%s", temp_install, bindir);
523                 bindir = tmp;
524
525                 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
526                 sprintf(tmp, "%s/install/%s", temp_install, libdir);
527                 libdir = tmp;
528
529                 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
530                 sprintf(tmp, "%s/install/%s", temp_install, datadir);
531                 datadir = tmp;
532
533                 /* psql will be installed into temp-install bindir */
534                 psqldir = bindir;
535
536                 /*
537                  * Set up shared library paths to include the temp install.
538                  *
539                  * LD_LIBRARY_PATH covers many platforms.  DYLD_LIBRARY_PATH works on
540                  * Darwin, and maybe other Mach-based systems.  LIBPATH is for AIX.
541                  * Windows needs shared libraries in PATH (only those linked into
542                  * executables, not dlopen'ed ones). Feel free to account for others
543                  * as well.
544                  */
545                 add_to_path("LD_LIBRARY_PATH", ':', libdir);
546                 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
547                 add_to_path("LIBPATH", ':', libdir);
548 #if defined(WIN32) || defined(__CYGWIN__)
549                 add_to_path("PATH", ';', libdir);
550 #endif
551         }
552         else
553         {
554                 const char *pghost;
555                 const char *pgport;
556
557                 /*
558                  * When testing an existing install, we honor existing environment
559                  * variables, except if they're overridden by command line options.
560                  */
561                 if (hostname != NULL)
562                 {
563                         doputenv("PGHOST", hostname);
564                         unsetenv("PGHOSTADDR");
565                 }
566                 if (port != -1)
567                 {
568                         char            s[16];
569
570                         sprintf(s, "%d", port);
571                         doputenv("PGPORT", s);
572                 }
573                 if (user != NULL)
574                         doputenv("PGUSER", user);
575
576                 /*
577                  * Report what we're connecting to
578                  */
579                 pghost = getenv("PGHOST");
580                 pgport = getenv("PGPORT");
581 #ifndef HAVE_UNIX_SOCKETS
582                 if (!pghost)
583                         pghost = "localhost";
584 #endif
585
586                 if (pghost && pgport)
587                         printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
588                 if (pghost && !pgport)
589                         printf(_("(using postmaster on %s, default port)\n"), pghost);
590                 if (!pghost && pgport)
591                         printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
592                 if (!pghost && !pgport)
593                         printf(_("(using postmaster on Unix socket, default port)\n"));
594         }
595
596         load_resultmap();
597 }
598
599 /*
600  * Issue a command via psql, connecting to the specified database
601  *
602  * Since we use system(), this doesn't return until the operation finishes
603  */
604 static void
605 psql_command(const char *database, const char *query,...)
606 {
607         char            query_formatted[1024];
608         char            query_escaped[2048];
609         char            psql_cmd[MAXPGPATH + 2048];
610         va_list         args;
611         char       *s;
612         char       *d;
613
614         /* Generate the query with insertion of sprintf arguments */
615         va_start(args, query);
616         vsnprintf(query_formatted, sizeof(query_formatted), query, args);
617         va_end(args);
618
619         /* Now escape any shell double-quote metacharacters */
620         d = query_escaped;
621         for (s = query_formatted; *s; s++)
622         {
623                 if (strchr("\\\"$`", *s))
624                         *d++ = '\\';
625                 *d++ = *s;
626         }
627         *d = '\0';
628
629         /* And now we can build and execute the shell command */
630         snprintf(psql_cmd, sizeof(psql_cmd),
631                          SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
632                          psqldir ? psqldir : "",
633                          psqldir ? "/" : "",
634                          query_escaped,
635                          database);
636
637         if (system(psql_cmd) != 0)
638         {
639                 /* psql probably already reported the error */
640                 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
641                 exit_nicely(2);
642         }
643 }
644
645 /*
646  * Spawn a process to execute the given shell command; don't wait for it
647  *
648  * Returns the process ID (or HANDLE) so we can wait for it later
649  */
650 static PID_TYPE
651 spawn_process(const char *cmdline)
652 {
653 #ifndef WIN32
654         pid_t           pid;
655
656         /*
657          * Must flush I/O buffers before fork.  Ideally we'd use fflush(NULL) here
658          * ... does anyone still care about systems where that doesn't work?
659          */
660         fflush(stdout);
661         fflush(stderr);
662         if (logfile)
663                 fflush(logfile);
664
665         pid = fork();
666         if (pid == -1)
667         {
668                 fprintf(stderr, _("%s: could not fork: %s\n"),
669                                 progname, strerror(errno));
670                 exit_nicely(2);
671         }
672         if (pid == 0)
673         {
674                 /*
675                  * In child
676                  *
677                  * Instead of using system(), exec the shell directly, and tell it to
678                  * "exec" the command too.      This saves two useless processes per
679                  * parallel test case.
680                  */
681                 char       *cmdline2 = malloc(strlen(cmdline) + 6);
682
683                 sprintf(cmdline2, "exec %s", cmdline);
684                 execl(shellprog, shellprog, "-c", cmdline2, NULL);
685                 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
686                                 progname, shellprog, strerror(errno));
687                 exit(1);                                /* not exit_nicely here... */
688         }
689         /* in parent */
690         return pid;
691 #else
692         char       *cmdline2;
693         STARTUPINFO si;
694         PROCESS_INFORMATION pi;
695
696         ZeroMemory(&si, sizeof(si));
697         si.cb = sizeof(si);
698
699         cmdline2 = malloc(strlen(cmdline) + 8);
700         sprintf(cmdline2, "cmd /c %s", cmdline);
701
702         if (!CreateProcess(NULL, cmdline2, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
703         {
704                 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
705                                 cmdline2, GetLastError());
706                 exit_nicely(2);
707         }
708         free(cmdline2);
709
710         CloseHandle(pi.hThread);
711         return pi.hProcess;
712 #endif
713 }
714
715 /*
716  * start a psql test process for specified file (including redirection),
717  * and return process ID
718  */
719 static PID_TYPE
720 psql_start_test(const char *testname)
721 {
722         PID_TYPE        pid;
723         char            infile[MAXPGPATH];
724         char            outfile[MAXPGPATH];
725         char            psql_cmd[MAXPGPATH * 3];
726
727         snprintf(infile, sizeof(infile), "%s/sql/%s.sql",
728                          inputdir, testname);
729         snprintf(outfile, sizeof(outfile), "%s/results/%s.out",
730                          outputdir, testname);
731
732         snprintf(psql_cmd, sizeof(psql_cmd),
733                          SYSTEMQUOTE "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
734                          psqldir ? psqldir : "",
735                          psqldir ? "/" : "",
736                          dbname,
737                          infile,
738                          outfile);
739
740         pid = spawn_process(psql_cmd);
741
742         if (pid == INVALID_PID)
743         {
744                 fprintf(stderr, _("could not start process for test %s\n"),
745                                 testname);
746                 exit_nicely(2);
747         }
748
749         return pid;
750 }
751
752 /*
753  * Count bytes in file
754  */
755 static long
756 file_size(const char *file)
757 {
758         long            r;
759         FILE       *f = fopen(file, "r");
760
761         if (!f)
762         {
763                 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
764                                 progname, file, strerror(errno));
765                 return -1;
766         }
767         fseek(f, 0, SEEK_END);
768         r = ftell(f);
769         fclose(f);
770         return r;
771 }
772
773 /*
774  * Count lines in file
775  */
776 static int
777 file_line_count(const char *file)
778 {
779         int                     c;
780         int                     l = 0;
781         FILE       *f = fopen(file, "r");
782
783         if (!f)
784         {
785                 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
786                                 progname, file, strerror(errno));
787                 return -1;
788         }
789         while ((c = fgetc(f)) != EOF)
790         {
791                 if (c == '\n')
792                         l++;
793         }
794         fclose(f);
795         return l;
796 }
797
798 static bool
799 file_exists(const char *file)
800 {
801         FILE       *f = fopen(file, "r");
802
803         if (!f)
804                 return false;
805         fclose(f);
806         return true;
807 }
808
809 static bool
810 directory_exists(const char *dir)
811 {
812         struct stat st;
813
814         if (stat(dir, &st) != 0)
815                 return false;
816         if (st.st_mode & S_IFDIR)
817                 return true;
818         return false;
819 }
820
821 /* Create a directory */
822 static void
823 make_directory(const char *dir)
824 {
825         if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
826         {
827                 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
828                                 progname, dir, strerror(errno));
829                 exit_nicely(2);
830         }
831 }
832
833 /*
834  * Run a "diff" command and also check that it didn't crash
835  */
836 static int
837 run_diff(const char *cmd, const char *filename)
838 {
839         int                     r;
840
841         r = system(cmd);
842         if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
843         {
844                 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
845                 exit_nicely(2);
846         }
847 #ifdef WIN32
848
849         /*
850          * On WIN32, if the 'diff' command cannot be found, system() returns 1,
851          * but produces nothing to stdout, so we check for that here.
852          */
853         if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
854         {
855                 fprintf(stderr, _("diff command not found: %s\n"), cmd);
856                 exit_nicely(2);
857         }
858 #endif
859
860         return WEXITSTATUS(r);
861 }
862
863 /*
864  * Check the actual result file for the given test against expected results
865  *
866  * Returns true if different (failure), false if correct match found.
867  * In the true case, the diff is appended to the diffs file.
868  */
869 static bool
870 results_differ(const char *testname)
871 {
872         const char *expectname;
873         char            resultsfile[MAXPGPATH];
874         char            expectfile[MAXPGPATH];
875         char            diff[MAXPGPATH];
876         char            cmd[MAXPGPATH * 3];
877         char            best_expect_file[MAXPGPATH];
878         _resultmap *rm;
879         FILE       *difffile;
880         int                     best_line_count;
881         int                     i;
882         int                     l;
883
884         /* Check in resultmap if we should be looking at a different file */
885         expectname = testname;
886         for (rm = resultmap; rm != NULL; rm = rm->next)
887         {
888                 if (strcmp(testname, rm->test) == 0)
889                 {
890                         expectname = rm->resultfile;
891                         break;
892                 }
893         }
894
895         /* Name of test results file */
896         snprintf(resultsfile, sizeof(resultsfile), "%s/results/%s.out",
897                          outputdir, testname);
898
899         /* Name of expected-results file */
900         snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
901                          inputdir, expectname);
902
903         /* Name to use for temporary diff file */
904         snprintf(diff, sizeof(diff), "%s/results/%s.diff",
905                          outputdir, testname);
906
907         /* OK, run the diff */
908         snprintf(cmd, sizeof(cmd),
909                          SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
910                          basic_diff_opts, expectfile, resultsfile, diff);
911
912         /* Is the diff file empty? */
913         if (run_diff(cmd, diff) == 0)
914         {
915                 unlink(diff);
916                 return false;
917         }
918
919         /* There may be secondary comparison files that match better */
920         best_line_count = file_line_count(diff);
921         strcpy(best_expect_file, expectfile);
922
923         for (i = 0; i <= 9; i++)
924         {
925                 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s_%d.out",
926                                  inputdir, expectname, i);
927                 if (!file_exists(expectfile))
928                         continue;
929
930                 snprintf(cmd, sizeof(cmd),
931                                  SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
932                                  basic_diff_opts, expectfile, resultsfile, diff);
933
934                 if (run_diff(cmd, diff) == 0)
935                 {
936                         unlink(diff);
937                         return false;
938                 }
939
940                 l = file_line_count(diff);
941                 if (l < best_line_count)
942                 {
943                         /* This diff was a better match than the last one */
944                         best_line_count = l;
945                         strcpy(best_expect_file, expectfile);
946                 }
947         }
948
949         /*
950          * fall back on the canonical results file if we haven't tried it yet and
951          * haven't found a complete match yet.
952          */
953
954         if (strcmp(expectname, testname) != 0)
955         {
956                 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
957                                  inputdir, testname);
958
959                 snprintf(cmd, sizeof(cmd),
960                                  SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
961                                  basic_diff_opts, expectfile, resultsfile, diff);
962
963                 if (run_diff(cmd, diff) == 0)
964                 {
965                         /* No diff = no changes = good */
966                         unlink(diff);
967                         return false;
968                 }
969
970                 l = file_line_count(diff);
971                 if (l < best_line_count)
972                 {
973                         /* This diff was a better match than the last one */
974                         best_line_count = l;
975                         strcpy(best_expect_file, expectfile);
976                 }
977         }
978
979         /*
980          * Use the best comparison file to generate the "pretty" diff, which we
981          * append to the diffs summary file.
982          */
983         snprintf(cmd, sizeof(cmd),
984                          SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
985                          pretty_diff_opts, best_expect_file, resultsfile, difffilename);
986         run_diff(cmd, difffilename);
987
988         /* And append a separator */
989         difffile = fopen(difffilename, "a");
990         if (difffile)
991         {
992                 fprintf(difffile,
993                                 "\n======================================================================\n\n");
994                 fclose(difffile);
995         }
996
997         unlink(diff);
998         return true;
999 }
1000
1001 /*
1002  * Wait for specified subprocesses to finish
1003  *
1004  * If names isn't NULL, report each subprocess as it finishes
1005  *
1006  * Note: it's OK to scribble on the pids array, but not on the names array
1007  */
1008 static void
1009 wait_for_tests(PID_TYPE * pids, char **names, int num_tests)
1010 {
1011         int                     tests_left;
1012         int                     i;
1013
1014 #ifdef WIN32
1015         PID_TYPE   *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1016
1017         memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1018 #endif
1019
1020         tests_left = num_tests;
1021         while (tests_left > 0)
1022         {
1023                 PID_TYPE        p;
1024
1025 #ifndef WIN32
1026                 p = wait(NULL);
1027
1028                 if (p == INVALID_PID)
1029                 {
1030                         fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1031                                         strerror(errno));
1032                         exit_nicely(2);
1033                 }
1034 #else
1035                 int                     r;
1036
1037                 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1038                 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1039                 {
1040                         fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
1041                                         GetLastError());
1042                         exit_nicely(2);
1043                 }
1044                 p = active_pids[r - WAIT_OBJECT_0];
1045                 /* compact the active_pids array */
1046                 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1047 #endif   /* WIN32 */
1048
1049                 for (i = 0; i < num_tests; i++)
1050                 {
1051                         if (p == pids[i])
1052                         {
1053 #ifdef WIN32
1054                                 CloseHandle(pids[i]);
1055 #endif
1056                                 pids[i] = INVALID_PID;
1057                                 if (names)
1058                                         status(" %s", names[i]);
1059                                 tests_left--;
1060                                 break;
1061                         }
1062                 }
1063         }
1064
1065 #ifdef WIN32
1066         free(active_pids);
1067 #endif
1068 }
1069
1070 /*
1071  * Run all the tests specified in one schedule file
1072  */
1073 static void
1074 run_schedule(const char *schedule)
1075 {
1076 #define MAX_PARALLEL_TESTS 100
1077         char       *tests[MAX_PARALLEL_TESTS];
1078         PID_TYPE        pids[MAX_PARALLEL_TESTS];
1079         _stringlist *ignorelist = NULL;
1080         char            scbuf[1024];
1081         FILE       *scf;
1082         int                     line_num = 0;
1083
1084         scf = fopen(schedule, "r");
1085         if (!scf)
1086         {
1087                 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1088                                 progname, schedule, strerror(errno));
1089                 exit_nicely(2);
1090         }
1091
1092         while (fgets(scbuf, sizeof(scbuf), scf))
1093         {
1094                 char       *test = NULL;
1095                 char       *c;
1096                 int                     num_tests;
1097                 bool            inword;
1098                 int                     i;
1099
1100                 line_num++;
1101
1102                 /* strip trailing whitespace, especially the newline */
1103                 i = strlen(scbuf);
1104                 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1105                         scbuf[--i] = '\0';
1106
1107                 if (scbuf[0] == '\0' || scbuf[0] == '#')
1108                         continue;
1109                 if (strncmp(scbuf, "test: ", 6) == 0)
1110                         test = scbuf + 6;
1111                 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1112                 {
1113                         c = scbuf + 8;
1114                         while (*c && isspace((unsigned char) *c))
1115                                 c++;
1116                         add_stringlist_item(&ignorelist, c);
1117
1118                         /*
1119                          * Note: ignore: lines do not run the test, they just say that
1120                          * failure of this test when run later on is to be ignored. A bit
1121                          * odd but that's how the shell-script version did it.
1122                          */
1123                         continue;
1124                 }
1125                 else
1126                 {
1127                         fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1128                                         schedule, line_num, scbuf);
1129                         exit_nicely(2);
1130                 }
1131
1132                 num_tests = 0;
1133                 inword = false;
1134                 for (c = test; *c; c++)
1135                 {
1136                         if (isspace((unsigned char) *c))
1137                         {
1138                                 *c = '\0';
1139                                 inword = false;
1140                         }
1141                         else if (!inword)
1142                         {
1143                                 if (num_tests >= MAX_PARALLEL_TESTS)
1144                                 {
1145                                         /* can't print scbuf here, it's already been trashed */
1146                                         fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1147                                                         schedule, line_num);
1148                                         exit_nicely(2);
1149                                 }
1150                                 tests[num_tests] = c;
1151                                 num_tests++;
1152                                 inword = true;
1153                         }
1154                 }
1155
1156                 if (num_tests == 0)
1157                 {
1158                         fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1159                                         schedule, line_num, scbuf);
1160                         exit_nicely(2);
1161                 }
1162
1163                 if (num_tests == 1)
1164                 {
1165                         status(_("test %-20s ... "), tests[0]);
1166                         pids[0] = psql_start_test(tests[0]);
1167                         wait_for_tests(pids, NULL, 1);
1168                         /* status line is finished below */
1169                 }
1170                 else if (max_connections > 0 && max_connections < num_tests)
1171                 {
1172                         int                     oldest = 0;
1173
1174                         status(_("parallel group (%d tests, in groups of %d): "),
1175                                    num_tests, max_connections);
1176                         for (i = 0; i < num_tests; i++)
1177                         {
1178                                 if (i - oldest >= max_connections)
1179                                 {
1180                                         wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1181                                         oldest = i;
1182                                 }
1183                                 pids[i] = psql_start_test(tests[i]);
1184                         }
1185                         wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1186                         status_end();
1187                 }
1188                 else
1189                 {
1190                         status(_("parallel group (%d tests): "), num_tests);
1191                         for (i = 0; i < num_tests; i++)
1192                         {
1193                                 pids[i] = psql_start_test(tests[i]);
1194                         }
1195                         wait_for_tests(pids, tests, num_tests);
1196                         status_end();
1197                 }
1198
1199                 /* Check results for all tests */
1200                 for (i = 0; i < num_tests; i++)
1201                 {
1202                         if (num_tests > 1)
1203                                 status(_("     %-20s ... "), tests[i]);
1204
1205                         if (results_differ(tests[i]))
1206                         {
1207                                 bool            ignore = false;
1208                                 _stringlist *sl;
1209
1210                                 for (sl = ignorelist; sl != NULL; sl = sl->next)
1211                                 {
1212                                         if (strcmp(tests[i], sl->str) == 0)
1213                                         {
1214                                                 ignore = true;
1215                                                 break;
1216                                         }
1217                                 }
1218                                 if (ignore)
1219                                 {
1220                                         status(_("failed (ignored)"));
1221                                         fail_ignore_count++;
1222                                 }
1223                                 else
1224                                 {
1225                                         status(_("FAILED"));
1226                                         fail_count++;
1227                                 }
1228                         }
1229                         else
1230                         {
1231                                 status(_("ok"));
1232                                 success_count++;
1233                         }
1234
1235                         status_end();
1236                 }
1237         }
1238
1239         fclose(scf);
1240 }
1241
1242 /*
1243  * Run a single test
1244  */
1245 static void
1246 run_single_test(const char *test)
1247 {
1248         PID_TYPE        pid;
1249
1250         status(_("test %-20s ... "), test);
1251         pid = psql_start_test(test);
1252         wait_for_tests(&pid, NULL, 1);
1253
1254         if (results_differ(test))
1255         {
1256                 status(_("FAILED"));
1257                 fail_count++;
1258         }
1259         else
1260         {
1261                 status(_("ok"));
1262                 success_count++;
1263         }
1264         status_end();
1265 }
1266
1267 /*
1268  * Create the summary-output files (making them empty if already existing)
1269  */
1270 static void
1271 open_result_files(void)
1272 {
1273         char            file[MAXPGPATH];
1274         FILE       *difffile;
1275
1276         /* create the log file (copy of running status output) */
1277         snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1278         logfilename = strdup(file);
1279         logfile = fopen(logfilename, "w");
1280         if (!logfile)
1281         {
1282                 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1283                                 progname, logfilename, strerror(errno));
1284                 exit_nicely(2);
1285         }
1286
1287         /* create the diffs file as empty */
1288         snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1289         difffilename = strdup(file);
1290         difffile = fopen(difffilename, "w");
1291         if (!difffile)
1292         {
1293                 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1294                                 progname, difffilename, strerror(errno));
1295                 exit_nicely(2);
1296         }
1297         /* we don't keep the diffs file open continuously */
1298         fclose(difffile);
1299
1300         /* also create the output directory if not present */
1301         snprintf(file, sizeof(file), "%s/results", outputdir);
1302         if (!directory_exists(file))
1303                 make_directory(file);
1304 }
1305
1306 static void
1307 help(void)
1308 {
1309         printf(_("PostgreSQL regression test driver\n"));
1310         printf(_("\n"));
1311         printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1312         printf(_("\n"));
1313         printf(_("Options:\n"));
1314         printf(_("  --dbname=DB               use database DB (default \"regression\")\n"));
1315         printf(_("  --debug                   turn on debug mode in programs that are run\n"));
1316         printf(_("  --inputdir=DIR            take input files from DIR (default \".\")\n"));
1317         printf(_("  --load-language=lang      load the named language before running the\n"));
1318         printf(_("                            tests; can appear multiple times\n"));
1319         printf(_("  --max-connections=N       maximum number of concurrent connections\n"));
1320         printf(_("                            (default is 0 meaning unlimited)\n"));
1321         printf(_("  --multibyte=ENCODING      use ENCODING as the multibyte encoding\n"));
1322         printf(_("  --outputdir=DIR           place output files in DIR (default \".\")\n"));
1323         printf(_("  --schedule=FILE           use test ordering schedule from FILE\n"));
1324         printf(_("                            (may be used multiple times to concatenate)\n"));
1325         printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
1326         printf(_("  --no-locale               use C locale\n"));
1327         printf(_("\n"));
1328         printf(_("Options for \"temp-install\" mode:\n"));
1329         printf(_("  --top-builddir=DIR        (relative) path to top level build directory\n"));
1330         printf(_("  --temp-port=PORT          port number to start temp postmaster on\n"));
1331         printf(_("\n"));
1332         printf(_("Options for using an existing installation:\n"));
1333         printf(_("  --host=HOST               use postmaster running on HOST\n"));
1334         printf(_("  --port=PORT               use postmaster running at PORT\n"));
1335         printf(_("  --user=USER               connect as USER\n"));
1336         printf(_("  --psqldir=DIR             use psql in DIR (default: find in PATH)\n"));
1337         printf(_("\n"));
1338         printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1339         printf(_("if the tests could not be run for some reason.\n"));
1340         printf(_("\n"));
1341         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1342 }
1343
1344 int
1345 main(int argc, char *argv[])
1346 {
1347         _stringlist *sl;
1348         int                     c;
1349         int                     i;
1350         int                     option_index;
1351         char            buf[MAXPGPATH * 4];
1352
1353         static struct option long_options[] = {
1354                 {"help", no_argument, NULL, 'h'},
1355                 {"version", no_argument, NULL, 'V'},
1356                 {"dbname", required_argument, NULL, 1},
1357                 {"debug", no_argument, NULL, 2},
1358                 {"inputdir", required_argument, NULL, 3},
1359                 {"load-language", required_argument, NULL, 4},
1360                 {"max-connections", required_argument, NULL, 5},
1361                 {"multibyte", required_argument, NULL, 6},
1362                 {"outputdir", required_argument, NULL, 7},
1363                 {"schedule", required_argument, NULL, 8},
1364                 {"temp-install", required_argument, NULL, 9},
1365                 {"no-locale", no_argument, NULL, 10},
1366                 {"top-builddir", required_argument, NULL, 11},
1367                 {"temp-port", required_argument, NULL, 12},
1368                 {"host", required_argument, NULL, 13},
1369                 {"port", required_argument, NULL, 14},
1370                 {"user", required_argument, NULL, 15},
1371                 {"psqldir", required_argument, NULL, 16},
1372                 {NULL, 0, NULL, 0}
1373         };
1374
1375         progname = get_progname(argv[0]);
1376         set_pglocale_pgservice(argv[0], "pg_regress");
1377
1378 #ifndef HAVE_UNIX_SOCKETS
1379         /* no unix domain sockets available, so change default */
1380         hostname = "localhost";
1381 #endif
1382
1383         while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1384         {
1385                 switch (c)
1386                 {
1387                         case 'h':
1388                                 help();
1389                                 exit_nicely(0);
1390                         case 'V':
1391                                 printf("pg_regress (PostgreSQL %s)\n", PG_VERSION);
1392                                 exit_nicely(0);
1393                         case 1:
1394                                 dbname = strdup(optarg);
1395                                 break;
1396                         case 2:
1397                                 debug = true;
1398                                 break;
1399                         case 3:
1400                                 inputdir = strdup(optarg);
1401                                 break;
1402                         case 4:
1403                                 add_stringlist_item(&loadlanguage, optarg);
1404                                 break;
1405                         case 5:
1406                                 max_connections = atoi(optarg);
1407                                 break;
1408                         case 6:
1409                                 encoding = strdup(optarg);
1410                                 break;
1411                         case 7:
1412                                 outputdir = strdup(optarg);
1413                                 break;
1414                         case 8:
1415                                 add_stringlist_item(&schedulelist, optarg);
1416                                 break;
1417                         case 9:
1418                                 /* temp_install must be absolute path */
1419                                 if (is_absolute_path(optarg))
1420                                         temp_install = strdup(optarg);
1421                                 else
1422                                 {
1423                                         char            cwdbuf[MAXPGPATH];
1424
1425                                         if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1426                                         {
1427                                                 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1428                                                 exit_nicely(2);
1429                                         }
1430                                         temp_install = malloc(strlen(cwdbuf) + strlen(optarg) + 2);
1431                                         sprintf(temp_install, "%s/%s", cwdbuf, optarg);
1432                                 }
1433                                 canonicalize_path(temp_install);
1434                                 break;
1435                         case 10:
1436                                 nolocale = true;
1437                                 break;
1438                         case 11:
1439                                 top_builddir = strdup(optarg);
1440                                 break;
1441                         case 12:
1442                                 {
1443                                         int                     p = atoi(optarg);
1444
1445                                         /* Since Makefile isn't very bright, check port range */
1446                                         if (p >= 1024 && p <= 65535)
1447                                                 temp_port = p;
1448                                 }
1449                                 break;
1450                         case 13:
1451                                 hostname = strdup(optarg);
1452                                 break;
1453                         case 14:
1454                                 port = atoi(optarg);
1455                                 break;
1456                         case 15:
1457                                 user = strdup(optarg);
1458                                 break;
1459                         case 16:
1460                                 /* "--psqldir=" should mean to use PATH */
1461                                 if (strlen(optarg))
1462                                         psqldir = strdup(optarg);
1463                                 break;
1464                         default:
1465                                 /* getopt_long already emitted a complaint */
1466                                 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
1467                                                 progname);
1468                                 exit_nicely(2);
1469                 }
1470         }
1471
1472         /*
1473          * if we still have arguments, they are extra tests to run
1474          */
1475         while (argc - optind >= 1)
1476         {
1477                 add_stringlist_item(&extra_tests, argv[optind]);
1478                 optind++;
1479         }
1480
1481         if (temp_install)
1482                 port = temp_port;
1483
1484         /*
1485          * Initialization
1486          */
1487         open_result_files();
1488
1489         initialize_environment();
1490
1491 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
1492         unlimit_core_size();
1493 #endif
1494
1495         if (temp_install)
1496         {
1497                 /*
1498                  * Prepare the temp installation
1499                  */
1500                 if (!top_builddir)
1501                 {
1502                         fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
1503                         exit_nicely(2);
1504                 }
1505
1506                 if (directory_exists(temp_install))
1507                 {
1508                         header(_("removing existing temp installation"));
1509                         rmtree(temp_install, true);
1510                 }
1511
1512                 header(_("creating temporary installation"));
1513
1514                 /* make the temp install top directory */
1515                 make_directory(temp_install);
1516
1517                 /* and a directory for log files */
1518                 snprintf(buf, sizeof(buf), "%s/log", outputdir);
1519                 if (!directory_exists(buf))
1520                         make_directory(buf);
1521
1522                 /* "make install" */
1523                 snprintf(buf, sizeof(buf),
1524                                  SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
1525                                  makeprog, top_builddir, temp_install, outputdir);
1526                 if (system(buf))
1527                 {
1528                         fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
1529                         exit_nicely(2);
1530                 }
1531
1532                 /* initdb */
1533                 header(_("initializing database system"));
1534                 snprintf(buf, sizeof(buf),
1535                                  SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
1536                                  bindir, temp_install, datadir,
1537                                  debug ? " --debug" : "",
1538                                  nolocale ? " --no-locale" : "",
1539                                  outputdir);
1540                 if (system(buf))
1541                 {
1542                         fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
1543                         exit_nicely(2);
1544                 }
1545
1546                 /*
1547                  * Start the temp postmaster
1548                  */
1549                 header(_("starting postmaster"));
1550                 snprintf(buf, sizeof(buf),
1551                                  SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
1552                                  bindir, temp_install,
1553                                  debug ? " -d 5" : "",
1554                                  hostname ? hostname : "",
1555                                  outputdir);
1556                 postmaster_pid = spawn_process(buf);
1557                 if (postmaster_pid == INVALID_PID)
1558                 {
1559                         fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
1560                                         progname, strerror(errno));
1561                         exit_nicely(2);
1562                 }
1563
1564                 /*
1565                  * Wait till postmaster is able to accept connections (normally only a
1566                  * second or so, but Cygwin is reportedly *much* slower).  Don't wait
1567                  * forever, however.
1568                  */
1569                 snprintf(buf, sizeof(buf),
1570                                  SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
1571                                  bindir, DEVNULL, DEVNULL);
1572                 for (i = 0; i < 60; i++)
1573                 {
1574                         /* Done if psql succeeds */
1575                         if (system(buf) == 0)
1576                                 break;
1577
1578                         /*
1579                          * Fail immediately if postmaster has exited
1580                          */
1581 #ifndef WIN32
1582                         if (kill(postmaster_pid, 0) != 0)
1583 #else
1584                         if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
1585 #endif
1586                         {
1587                                 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
1588                                 exit_nicely(2);
1589                         }
1590
1591                         pg_usleep(1000000L);
1592                 }
1593                 if (i >= 60)
1594                 {
1595                         fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
1596
1597                         /*
1598                          * If we get here, the postmaster is probably wedged somewhere in
1599                          * startup.  Try to kill it ungracefully rather than leaving a
1600                          * stuck postmaster that might interfere with subsequent test
1601                          * attempts.
1602                          */
1603 #ifndef WIN32
1604                         if (kill(postmaster_pid, SIGKILL) != 0 &&
1605                                 errno != ESRCH)
1606                                 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
1607                                                 progname, strerror(errno));
1608 #else
1609                         if (TerminateProcess(postmaster_pid, 255) == 0)
1610                                 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
1611                                                 progname, GetLastError());
1612 #endif
1613
1614                         exit_nicely(2);
1615                 }
1616
1617                 postmaster_running = true;
1618
1619                 printf(_("running on port %d with pid %lu\n"),
1620                            temp_port, (unsigned long) postmaster_pid);
1621         }
1622         else
1623         {
1624                 /*
1625                  * Using an existing installation, so may need to get rid of
1626                  * pre-existing database.
1627                  */
1628                 header(_("dropping database \"%s\""), dbname);
1629                 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1630         }
1631
1632         /*
1633          * Create the test database
1634          *
1635          * We use template0 so that any installation-local cruft in template1 will
1636          * not mess up the tests.
1637          */
1638         header(_("creating database \"%s\""), dbname);
1639         if (encoding)
1640                 psql_command("postgres",
1641                                    "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'",
1642                                          dbname, encoding);
1643         else
1644                 /* use installation default */
1645                 psql_command("postgres",
1646                                          "CREATE DATABASE \"%s\" TEMPLATE=template0",
1647                                          dbname);
1648
1649         psql_command(dbname,
1650                                  "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1651                                  "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1652                                  "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1653                                  "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1654                         "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1655                                  dbname, dbname, dbname, dbname, dbname);
1656
1657         /*
1658          * Install any requested PL languages
1659          */
1660         for (sl = loadlanguage; sl != NULL; sl = sl->next)
1661         {
1662                 header(_("installing %s"), sl->str);
1663                 psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
1664         }
1665
1666         /*
1667          * Ready to run the tests
1668          */
1669         header(_("running regression test queries"));
1670
1671         for (sl = schedulelist; sl != NULL; sl = sl->next)
1672         {
1673                 run_schedule(sl->str);
1674         }
1675
1676         for (sl = extra_tests; sl != NULL; sl = sl->next)
1677         {
1678                 run_single_test(sl->str);
1679         }
1680
1681         /*
1682          * Shut down temp installation's postmaster
1683          */
1684         if (temp_install)
1685         {
1686                 header(_("shutting down postmaster"));
1687                 stop_postmaster();
1688         }
1689
1690         fclose(logfile);
1691
1692         /*
1693          * Emit nice-looking summary message
1694          */
1695         if (fail_count == 0 && fail_ignore_count == 0)
1696                 snprintf(buf, sizeof(buf),
1697                                  _(" All %d tests passed. "),
1698                                  success_count);
1699         else if (fail_count == 0)       /* fail_count=0, fail_ignore_count>0 */
1700                 snprintf(buf, sizeof(buf),
1701                                  _(" %d of %d tests passed, %d failed test(s) ignored. "),
1702                                  success_count,
1703                                  success_count + fail_ignore_count,
1704                                  fail_ignore_count);
1705         else if (fail_ignore_count == 0)        /* fail_count>0 && fail_ignore_count=0 */
1706                 snprintf(buf, sizeof(buf),
1707                                  _(" %d of %d tests failed. "),
1708                                  fail_count,
1709                                  success_count + fail_count);
1710         else
1711                 /* fail_count>0 && fail_ignore_count>0 */
1712                 snprintf(buf, sizeof(buf),
1713                                  _(" %d of %d tests failed, %d of these failures ignored. "),
1714                                  fail_count + fail_ignore_count,
1715                                  success_count + fail_count + fail_ignore_count,
1716                                  fail_ignore_count);
1717
1718         putchar('\n');
1719         for (i = strlen(buf); i > 0; i--)
1720                 putchar('=');
1721         printf("\n%s\n", buf);
1722         for (i = strlen(buf); i > 0; i--)
1723                 putchar('=');
1724         putchar('\n');
1725         putchar('\n');
1726
1727         if (file_size(difffilename) > 0)
1728         {
1729                 printf(_("The differences that caused some tests to fail can be viewed in the\n"
1730                                  "file \"%s\".  A copy of the test summary that you see\n"
1731                                  "above is saved in the file \"%s\".\n\n"),
1732                            difffilename, logfilename);
1733         }
1734         else
1735         {
1736                 unlink(difffilename);
1737                 unlink(logfilename);
1738         }
1739
1740         if (fail_count != 0)
1741                 exit_nicely(1);
1742
1743         return 0;
1744 }