1 /*-------------------------------------------------------------------------
3 * pg_regress --- regression test driver
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
9 * This code is released under the terms of the PostgreSQL License.
11 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.25 2007/01/05 22:20:03 momjian Exp $
16 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
27 #ifdef HAVE_SYS_RESOURCE_H
29 #include <sys/resource.h>
32 #include "getopt_long.h"
33 #include "pg_config_paths.h"
36 #define PID_TYPE pid_t
37 #define INVALID_PID (-1)
39 #define PID_TYPE HANDLE
40 #define INVALID_PID INVALID_HANDLE_VALUE
44 /* simple list of strings */
45 typedef struct _stringlist
48 struct _stringlist *next;
51 /* for resultmap we need a list of pairs of strings */
52 typedef struct _resultmap
56 struct _resultmap *next;
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.
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;
72 #ifndef WIN32 /* not used in WIN32 case */
73 static char *shellprog = SHELLPROG;
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";
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;
97 static char *user = NULL;
99 /* internal variables */
100 static const char *progname;
101 static char *logfilename;
102 static FILE *logfile;
103 static char *difffilename;
105 static _resultmap *resultmap = NULL;
107 static PID_TYPE postmaster_pid = INVALID_PID;
108 static bool postmaster_running = false;
110 static int success_count = 0;
111 static int fail_count = 0;
112 static int fail_ignore_count = 0;
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)));
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)));
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)));
131 * allow core files if possible.
133 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
135 unlimit_core_size(void)
138 getrlimit(RLIMIT_CORE,&lim);
139 if (lim.rlim_max == 0)
142 _("%s: cannot set core size,: disallowed by hard limit.\n"),
146 else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
148 lim.rlim_cur = lim.rlim_max;
149 setrlimit(RLIMIT_CORE,&lim);
156 * Add an item at the end of a stringlist.
159 add_stringlist_item(_stringlist ** listhead, const char *str)
161 _stringlist *newentry = malloc(sizeof(_stringlist));
162 _stringlist *oldentry;
164 newentry->str = strdup(str);
165 newentry->next = NULL;
166 if (*listhead == NULL)
167 *listhead = newentry;
170 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
172 oldentry->next = newentry;
177 * Print a progress banner on stdout.
180 header(const char *fmt,...)
186 vsnprintf(tmp, sizeof(tmp), fmt, ap);
189 fprintf(stdout, "============== %-38s ==============\n", tmp);
194 * Print "doing something ..." --- supplied text should not end with newline
197 status(const char *fmt,...)
202 vfprintf(stdout, fmt, ap);
209 vfprintf(logfile, fmt, ap);
215 * Done "doing something ..."
220 fprintf(stdout, "\n");
223 fprintf(logfile, "\n");
227 * shut down temp postmaster
230 stop_postmaster(void)
232 if (postmaster_running)
234 /* We use pg_ctl to issue the kill and wait for stop */
235 char buf[MAXPGPATH * 2];
237 /* On Windows, system() seems not to force fflush, so... */
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;
250 * Always exit through here, not through plain exit(), to ensure we make
251 * an effort to shut down a temp postmaster
254 exit_nicely(int code)
261 * Check whether string matches pattern
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).
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.
273 string_matches_pattern(const char *str, const char *pattern)
275 while (*str && *pattern)
277 if (*pattern == '.' && pattern[1] == '*')
280 /* Trailing .* matches everything. */
281 if (*pattern == '\0')
285 * Otherwise, scan for a text position at which we can match the
286 * rest of the pattern.
291 * Optimization to prevent most recursion: don't recurse
292 * unless first pattern char might match this text char.
294 if (*str == *pattern || *pattern == '.')
296 if (string_matches_pattern(str, pattern))
304 * End of text with no match.
308 else if (*pattern != '.' && *str != *pattern)
311 * Not the single-character wildcard and no explicit match? Then
321 if (*pattern == '\0')
322 return true; /* end of pattern, so declare match */
324 /* End of input string. Do we have matching pattern remaining? */
325 while (*pattern == '.' && pattern[1] == '*')
327 if (*pattern == '\0')
328 return true; /* end of pattern, so declare match */
334 * Scan resultmap file to find which platform-specific expected files to use.
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.)
352 /* scan the file ... */
353 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
357 /* OK if it doesn't exist, else complain */
360 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
361 progname, buf, strerror(errno));
365 while (fgets(buf, sizeof(buf), f))
371 /* strip trailing whitespace, especially the newline */
373 while (i > 0 && isspace((unsigned char) buf[i - 1]))
376 /* parse out the line fields */
377 platform = strchr(buf, '/');
380 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
385 expected = strchr(platform, '=');
388 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
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.
400 if (string_matches_pattern(host_platform, platform))
402 _resultmap *entry = malloc(sizeof(_resultmap));
404 entry->test = strdup(buf);
405 entry->resultfile = strdup(expected);
406 entry->next = resultmap;
414 * Handy subroutine for setting an environment variable "var" to "val"
417 doputenv(const char *var, const char *val)
419 char *s = malloc(strlen(var) + strlen(val) + 2);
421 sprintf(s, "%s=%s", var, val);
426 * Set the environment variable "pathname", prepending "addval" to its
427 * old value (if any).
430 add_to_path(const char *pathname, char separator, const char *addval)
432 char *oldval = getenv(pathname);
435 if (!oldval || !oldval[0])
437 /* no previous value */
438 newval = malloc(strlen(pathname) + strlen(addval) + 2);
439 sprintf(newval, "%s=%s", pathname, addval);
443 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
444 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
450 * Prepare environment variables for running regression tests
453 initialize_environment(void)
458 * Clear out any non-C locale settings
460 unsetenv("LC_COLLATE");
461 unsetenv("LC_CTYPE");
462 unsetenv("LC_MONETARY");
463 unsetenv("LC_MESSAGES");
464 unsetenv("LC_NUMERIC");
468 unsetenv("LANGUAGE");
469 /* On Windows the default locale may not be English, so force it */
470 #if defined(WIN32) || defined(__CYGWIN__)
475 * Set multibyte as requested
478 doputenv("PGCLIENTENCODING", encoding);
480 unsetenv("PGCLIENTENCODING");
483 * Set timezone and datestyle for datetime-related tests
485 putenv("PGTZ=PST8PDT");
486 putenv("PGDATESTYLE=Postgres, MDY");
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
498 unsetenv("PGDATABASE");
500 unsetenv("PGSERVICE");
501 unsetenv("PGSSLMODE");
502 unsetenv("PGREQUIRESSL");
503 unsetenv("PGCONNECT_TIMEOUT");
505 if (hostname != NULL)
506 doputenv("PGHOST", hostname);
509 unsetenv("PGHOSTADDR");
514 sprintf(s, "%d", port);
515 doputenv("PGPORT", s);
519 * Adjust path variables to point into the temp-install tree
521 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
522 sprintf(tmp, "%s/install/%s", temp_install, bindir);
525 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
526 sprintf(tmp, "%s/install/%s", temp_install, libdir);
529 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
530 sprintf(tmp, "%s/install/%s", temp_install, datadir);
533 /* psql will be installed into temp-install bindir */
537 * Set up shared library paths to include the temp install.
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
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);
558 * When testing an existing install, we honor existing environment
559 * variables, except if they're overridden by command line options.
561 if (hostname != NULL)
563 doputenv("PGHOST", hostname);
564 unsetenv("PGHOSTADDR");
570 sprintf(s, "%d", port);
571 doputenv("PGPORT", s);
574 doputenv("PGUSER", user);
577 * Report what we're connecting to
579 pghost = getenv("PGHOST");
580 pgport = getenv("PGPORT");
581 #ifndef HAVE_UNIX_SOCKETS
583 pghost = "localhost";
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"));
600 * Issue a command via psql, connecting to the specified database
602 * Since we use system(), this doesn't return until the operation finishes
605 psql_command(const char *database, const char *query,...)
607 char query_formatted[1024];
608 char query_escaped[2048];
609 char psql_cmd[MAXPGPATH + 2048];
614 /* Generate the query with insertion of sprintf arguments */
615 va_start(args, query);
616 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
619 /* Now escape any shell double-quote metacharacters */
621 for (s = query_formatted; *s; s++)
623 if (strchr("\\\"$`", *s))
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 : "",
637 if (system(psql_cmd) != 0)
639 /* psql probably already reported the error */
640 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
646 * Spawn a process to execute the given shell command; don't wait for it
648 * Returns the process ID (or HANDLE) so we can wait for it later
651 spawn_process(const char *cmdline)
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?
668 fprintf(stderr, _("%s: could not fork: %s\n"),
669 progname, strerror(errno));
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.
681 char *cmdline2 = malloc(strlen(cmdline) + 6);
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... */
694 PROCESS_INFORMATION pi;
696 ZeroMemory(&si, sizeof(si));
699 cmdline2 = malloc(strlen(cmdline) + 8);
700 sprintf(cmdline2, "cmd /c %s", cmdline);
702 if (!CreateProcess(NULL, cmdline2, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
704 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
705 cmdline2, GetLastError());
710 CloseHandle(pi.hThread);
716 * start a psql test process for specified file (including redirection),
717 * and return process ID
720 psql_start_test(const char *testname)
723 char infile[MAXPGPATH];
724 char outfile[MAXPGPATH];
725 char psql_cmd[MAXPGPATH * 3];
727 snprintf(infile, sizeof(infile), "%s/sql/%s.sql",
729 snprintf(outfile, sizeof(outfile), "%s/results/%s.out",
730 outputdir, testname);
732 snprintf(psql_cmd, sizeof(psql_cmd),
733 SYSTEMQUOTE "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
734 psqldir ? psqldir : "",
740 pid = spawn_process(psql_cmd);
742 if (pid == INVALID_PID)
744 fprintf(stderr, _("could not start process for test %s\n"),
753 * Count bytes in file
756 file_size(const char *file)
759 FILE *f = fopen(file, "r");
763 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
764 progname, file, strerror(errno));
767 fseek(f, 0, SEEK_END);
774 * Count lines in file
777 file_line_count(const char *file)
781 FILE *f = fopen(file, "r");
785 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
786 progname, file, strerror(errno));
789 while ((c = fgetc(f)) != EOF)
799 file_exists(const char *file)
801 FILE *f = fopen(file, "r");
810 directory_exists(const char *dir)
814 if (stat(dir, &st) != 0)
816 if (st.st_mode & S_IFDIR)
821 /* Create a directory */
823 make_directory(const char *dir)
825 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
827 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
828 progname, dir, strerror(errno));
834 * Run a "diff" command and also check that it didn't crash
837 run_diff(const char *cmd, const char *filename)
842 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
844 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
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.
853 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
855 fprintf(stderr, _("diff command not found: %s\n"), cmd);
860 return WEXITSTATUS(r);
864 * Check the actual result file for the given test against expected results
866 * Returns true if different (failure), false if correct match found.
867 * In the true case, the diff is appended to the diffs file.
870 results_differ(const char *testname)
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];
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)
888 if (strcmp(testname, rm->test) == 0)
890 expectname = rm->resultfile;
895 /* Name of test results file */
896 snprintf(resultsfile, sizeof(resultsfile), "%s/results/%s.out",
897 outputdir, testname);
899 /* Name of expected-results file */
900 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
901 inputdir, expectname);
903 /* Name to use for temporary diff file */
904 snprintf(diff, sizeof(diff), "%s/results/%s.diff",
905 outputdir, testname);
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);
912 /* Is the diff file empty? */
913 if (run_diff(cmd, diff) == 0)
919 /* There may be secondary comparison files that match better */
920 best_line_count = file_line_count(diff);
921 strcpy(best_expect_file, expectfile);
923 for (i = 0; i <= 9; i++)
925 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s_%d.out",
926 inputdir, expectname, i);
927 if (!file_exists(expectfile))
930 snprintf(cmd, sizeof(cmd),
931 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
932 basic_diff_opts, expectfile, resultsfile, diff);
934 if (run_diff(cmd, diff) == 0)
940 l = file_line_count(diff);
941 if (l < best_line_count)
943 /* This diff was a better match than the last one */
945 strcpy(best_expect_file, expectfile);
950 * fall back on the canonical results file if we haven't tried it yet and
951 * haven't found a complete match yet.
954 if (strcmp(expectname, testname) != 0)
956 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
959 snprintf(cmd, sizeof(cmd),
960 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
961 basic_diff_opts, expectfile, resultsfile, diff);
963 if (run_diff(cmd, diff) == 0)
965 /* No diff = no changes = good */
970 l = file_line_count(diff);
971 if (l < best_line_count)
973 /* This diff was a better match than the last one */
975 strcpy(best_expect_file, expectfile);
980 * Use the best comparison file to generate the "pretty" diff, which we
981 * append to the diffs summary file.
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);
988 /* And append a separator */
989 difffile = fopen(difffilename, "a");
993 "\n======================================================================\n\n");
1002 * Wait for specified subprocesses to finish
1004 * If names isn't NULL, report each subprocess as it finishes
1006 * Note: it's OK to scribble on the pids array, but not on the names array
1009 wait_for_tests(PID_TYPE * pids, char **names, int num_tests)
1015 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1017 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1020 tests_left = num_tests;
1021 while (tests_left > 0)
1028 if (p == INVALID_PID)
1030 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1037 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1038 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1040 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
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];
1049 for (i = 0; i < num_tests; i++)
1054 CloseHandle(pids[i]);
1056 pids[i] = INVALID_PID;
1058 status(" %s", names[i]);
1071 * Run all the tests specified in one schedule file
1074 run_schedule(const char *schedule)
1076 #define MAX_PARALLEL_TESTS 100
1077 char *tests[MAX_PARALLEL_TESTS];
1078 PID_TYPE pids[MAX_PARALLEL_TESTS];
1079 _stringlist *ignorelist = NULL;
1084 scf = fopen(schedule, "r");
1087 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1088 progname, schedule, strerror(errno));
1092 while (fgets(scbuf, sizeof(scbuf), scf))
1102 /* strip trailing whitespace, especially the newline */
1104 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1107 if (scbuf[0] == '\0' || scbuf[0] == '#')
1109 if (strncmp(scbuf, "test: ", 6) == 0)
1111 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1114 while (*c && isspace((unsigned char) *c))
1116 add_stringlist_item(&ignorelist, c);
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.
1127 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1128 schedule, line_num, scbuf);
1134 for (c = test; *c; c++)
1136 if (isspace((unsigned char) *c))
1143 if (num_tests >= MAX_PARALLEL_TESTS)
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);
1150 tests[num_tests] = c;
1158 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1159 schedule, line_num, scbuf);
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 */
1170 else if (max_connections > 0 && max_connections < num_tests)
1174 status(_("parallel group (%d tests, in groups of %d): "),
1175 num_tests, max_connections);
1176 for (i = 0; i < num_tests; i++)
1178 if (i - oldest >= max_connections)
1180 wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1183 pids[i] = psql_start_test(tests[i]);
1185 wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1190 status(_("parallel group (%d tests): "), num_tests);
1191 for (i = 0; i < num_tests; i++)
1193 pids[i] = psql_start_test(tests[i]);
1195 wait_for_tests(pids, tests, num_tests);
1199 /* Check results for all tests */
1200 for (i = 0; i < num_tests; i++)
1203 status(_(" %-20s ... "), tests[i]);
1205 if (results_differ(tests[i]))
1207 bool ignore = false;
1210 for (sl = ignorelist; sl != NULL; sl = sl->next)
1212 if (strcmp(tests[i], sl->str) == 0)
1220 status(_("failed (ignored)"));
1221 fail_ignore_count++;
1225 status(_("FAILED"));
1246 run_single_test(const char *test)
1250 status(_("test %-20s ... "), test);
1251 pid = psql_start_test(test);
1252 wait_for_tests(&pid, NULL, 1);
1254 if (results_differ(test))
1256 status(_("FAILED"));
1268 * Create the summary-output files (making them empty if already existing)
1271 open_result_files(void)
1273 char file[MAXPGPATH];
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");
1282 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1283 progname, logfilename, strerror(errno));
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");
1293 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1294 progname, difffilename, strerror(errno));
1297 /* we don't keep the diffs file open continuously */
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);
1309 printf(_("PostgreSQL regression test driver\n"));
1311 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
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"));
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"));
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"));
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"));
1341 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1345 main(int argc, char *argv[])
1351 char buf[MAXPGPATH * 4];
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},
1375 progname = get_progname(argv[0]);
1376 set_pglocale_pgservice(argv[0], "pg_regress");
1378 #ifndef HAVE_UNIX_SOCKETS
1379 /* no unix domain sockets available, so change default */
1380 hostname = "localhost";
1383 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1391 printf("pg_regress (PostgreSQL %s)\n", PG_VERSION);
1394 dbname = strdup(optarg);
1400 inputdir = strdup(optarg);
1403 add_stringlist_item(&loadlanguage, optarg);
1406 max_connections = atoi(optarg);
1409 encoding = strdup(optarg);
1412 outputdir = strdup(optarg);
1415 add_stringlist_item(&schedulelist, optarg);
1418 /* temp_install must be absolute path */
1419 if (is_absolute_path(optarg))
1420 temp_install = strdup(optarg);
1423 char cwdbuf[MAXPGPATH];
1425 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1427 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1430 temp_install = malloc(strlen(cwdbuf) + strlen(optarg) + 2);
1431 sprintf(temp_install, "%s/%s", cwdbuf, optarg);
1433 canonicalize_path(temp_install);
1439 top_builddir = strdup(optarg);
1443 int p = atoi(optarg);
1445 /* Since Makefile isn't very bright, check port range */
1446 if (p >= 1024 && p <= 65535)
1451 hostname = strdup(optarg);
1454 port = atoi(optarg);
1457 user = strdup(optarg);
1460 /* "--psqldir=" should mean to use PATH */
1462 psqldir = strdup(optarg);
1465 /* getopt_long already emitted a complaint */
1466 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
1473 * if we still have arguments, they are extra tests to run
1475 while (argc - optind >= 1)
1477 add_stringlist_item(&extra_tests, argv[optind]);
1487 open_result_files();
1489 initialize_environment();
1491 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
1492 unlimit_core_size();
1498 * Prepare the temp installation
1502 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
1506 if (directory_exists(temp_install))
1508 header(_("removing existing temp installation"));
1509 rmtree(temp_install, true);
1512 header(_("creating temporary installation"));
1514 /* make the temp install top directory */
1515 make_directory(temp_install);
1517 /* and a directory for log files */
1518 snprintf(buf, sizeof(buf), "%s/log", outputdir);
1519 if (!directory_exists(buf))
1520 make_directory(buf);
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);
1528 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
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" : "",
1542 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
1547 * Start the temp postmaster
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 : "",
1556 postmaster_pid = spawn_process(buf);
1557 if (postmaster_pid == INVALID_PID)
1559 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
1560 progname, strerror(errno));
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
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++)
1574 /* Done if psql succeeds */
1575 if (system(buf) == 0)
1579 * Fail immediately if postmaster has exited
1582 if (kill(postmaster_pid, 0) != 0)
1584 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
1587 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
1591 pg_usleep(1000000L);
1595 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
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
1604 if (kill(postmaster_pid, SIGKILL) != 0 &&
1606 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
1607 progname, strerror(errno));
1609 if (TerminateProcess(postmaster_pid, 255) == 0)
1610 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
1611 progname, GetLastError());
1617 postmaster_running = true;
1619 printf(_("running on port %d with pid %lu\n"),
1620 temp_port, (unsigned long) postmaster_pid);
1625 * Using an existing installation, so may need to get rid of
1626 * pre-existing database.
1628 header(_("dropping database \"%s\""), dbname);
1629 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1633 * Create the test database
1635 * We use template0 so that any installation-local cruft in template1 will
1636 * not mess up the tests.
1638 header(_("creating database \"%s\""), dbname);
1640 psql_command("postgres",
1641 "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'",
1644 /* use installation default */
1645 psql_command("postgres",
1646 "CREATE DATABASE \"%s\" TEMPLATE=template0",
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);
1658 * Install any requested PL languages
1660 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1662 header(_("installing %s"), sl->str);
1663 psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
1667 * Ready to run the tests
1669 header(_("running regression test queries"));
1671 for (sl = schedulelist; sl != NULL; sl = sl->next)
1673 run_schedule(sl->str);
1676 for (sl = extra_tests; sl != NULL; sl = sl->next)
1678 run_single_test(sl->str);
1682 * Shut down temp installation's postmaster
1686 header(_("shutting down postmaster"));
1693 * Emit nice-looking summary message
1695 if (fail_count == 0 && fail_ignore_count == 0)
1696 snprintf(buf, sizeof(buf),
1697 _(" All %d tests passed. "),
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. "),
1703 success_count + 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. "),
1709 success_count + fail_count);
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,
1719 for (i = strlen(buf); i > 0; i--)
1721 printf("\n%s\n", buf);
1722 for (i = strlen(buf); i > 0; i--)
1727 if (file_size(difffilename) > 0)
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);
1736 unlink(difffilename);
1737 unlink(logfilename);
1740 if (fail_count != 0)