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-2011, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * src/test/regress/pg_regress.c
16 *-------------------------------------------------------------------------
19 #include "pg_regress.h"
27 #ifdef HAVE_SYS_RESOURCE_H
29 #include <sys/resource.h>
32 #include "getopt_long.h"
33 #include "pg_config_paths.h"
35 /* for resultmap we need a list of pairs of strings */
36 typedef struct _resultmap
41 struct _resultmap *next;
45 * Values obtained from pg_config_paths.h and Makefile. The PG installation
46 * paths are only used in temp_install mode: we use these strings to find
47 * out where "make install" will put stuff under the temp_install directory.
48 * In non-temp_install mode, the only thing we need is the location of psql,
49 * which we expect to find in psqldir, or in the PATH if psqldir isn't given.
51 * XXX Because pg_regress is not installed in bindir, we can't support
52 * this for relocatable trees as it is. --psqldir would need to be
53 * specified in those cases.
55 char *bindir = PGBINDIR;
56 char *libdir = LIBDIR;
57 char *datadir = PGSHAREDIR;
58 char *host_platform = HOST_TUPLE;
60 #ifndef WIN32_ONLY_COMPILER
61 static char *makeprog = MAKEPROG;
64 #ifndef WIN32 /* not used in WIN32 case */
65 static char *shellprog = SHELLPROG;
69 * On Windows we use -w in diff switches to avoid problems with inconsistent
70 * newline representation. The actual result files will generally have
71 * Windows-style newlines, but the comparison files might or might not.
74 const char *basic_diff_opts = "";
75 const char *pretty_diff_opts = "-C3";
77 const char *basic_diff_opts = "-w";
78 const char *pretty_diff_opts = "-w -C3";
81 /* options settable from command line */
82 _stringlist *dblist = NULL;
85 char *outputdir = ".";
86 char *psqldir = PGBINDIR;
87 char *launcher = NULL;
88 static _stringlist *loadlanguage = NULL;
89 static _stringlist *loadextension = NULL;
90 static int max_connections = 0;
91 static char *encoding = NULL;
92 static _stringlist *schedulelist = NULL;
93 static _stringlist *extra_tests = NULL;
94 static char *temp_install = NULL;
95 static char *temp_config = NULL;
96 static char *top_builddir = NULL;
97 static bool nolocale = false;
98 static bool use_existing = false;
99 static char *hostname = NULL;
100 static int port = -1;
101 static bool port_specified_by_user = false;
102 static char *dlpath = PKGLIBDIR;
103 static char *user = NULL;
104 static _stringlist *extraroles = NULL;
105 static _stringlist *extra_install = NULL;
107 /* internal variables */
108 static const char *progname;
109 static char *logfilename;
110 static FILE *logfile;
111 static char *difffilename;
113 static _resultmap *resultmap = NULL;
115 static PID_TYPE postmaster_pid = INVALID_PID;
116 static bool postmaster_running = false;
118 static int success_count = 0;
119 static int fail_count = 0;
120 static int fail_ignore_count = 0;
122 static bool directory_exists(const char *dir);
123 static void make_directory(const char *dir);
126 header(const char *fmt,...)
127 /* This extension allows gcc to check the format string for consistency with
128 the supplied arguments. */
129 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
131 status(const char *fmt,...)
132 /* This extension allows gcc to check the format string for consistency with
133 the supplied arguments. */
134 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
136 psql_command(const char *database, const char *query,...)
137 /* This extension allows gcc to check the format string for consistency with
138 the supplied arguments. */
139 __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
142 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
144 /* Windows API define missing from some versions of MingW headers */
145 #ifndef DISABLE_MAX_PRIVILEGE
146 #define DISABLE_MAX_PRIVILEGE 0x1
151 * allow core files if possible.
153 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
155 unlimit_core_size(void)
159 getrlimit(RLIMIT_CORE, &lim);
160 if (lim.rlim_max == 0)
163 _("%s: could not set core size: disallowed by hard limit\n"),
167 else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
169 lim.rlim_cur = lim.rlim_max;
170 setrlimit(RLIMIT_CORE, &lim);
177 * Add an item at the end of a stringlist.
180 add_stringlist_item(_stringlist ** listhead, const char *str)
182 _stringlist *newentry = malloc(sizeof(_stringlist));
183 _stringlist *oldentry;
185 newentry->str = strdup(str);
186 newentry->next = NULL;
187 if (*listhead == NULL)
188 *listhead = newentry;
191 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
193 oldentry->next = newentry;
201 free_stringlist(_stringlist ** listhead)
203 if (listhead == NULL || *listhead == NULL)
205 if ((*listhead)->next != NULL)
206 free_stringlist(&((*listhead)->next));
207 free((*listhead)->str);
213 * Split a delimited string into a stringlist
216 split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
218 char *sc = strdup(s);
219 char *token = strtok(sc, delim);
223 add_stringlist_item(listhead, token);
224 token = strtok(NULL, delim);
230 * Print a progress banner on stdout.
233 header(const char *fmt,...)
239 vsnprintf(tmp, sizeof(tmp), fmt, ap);
242 fprintf(stdout, "============== %-38s ==============\n", tmp);
247 * Print "doing something ..." --- supplied text should not end with newline
250 status(const char *fmt,...)
255 vfprintf(stdout, fmt, ap);
262 vfprintf(logfile, fmt, ap);
268 * Done "doing something ..."
273 fprintf(stdout, "\n");
276 fprintf(logfile, "\n");
280 * shut down temp postmaster
283 stop_postmaster(void)
285 if (postmaster_running)
287 /* We use pg_ctl to issue the kill and wait for stop */
288 char buf[MAXPGPATH * 2];
291 /* On Windows, system() seems not to force fflush, so... */
295 snprintf(buf, sizeof(buf),
296 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
297 bindir, temp_install);
301 fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
303 exit(2); /* not exit_nicely(), that would be recursive */
306 postmaster_running = false;
311 * Always exit through here, not through plain exit(), to ensure we make
312 * an effort to shut down a temp postmaster
315 exit_nicely(int code)
322 * Check whether string matches pattern
324 * In the original shell script, this function was implemented using expr(1),
325 * which provides basic regular expressions restricted to match starting at
326 * the string start (in conventional regex terms, there's an implicit "^"
327 * at the start of the pattern --- but no implicit "$" at the end).
329 * For now, we only support "." and ".*" as non-literal metacharacters,
330 * because that's all that anyone has found use for in resultmap. This
331 * code could be extended if more functionality is needed.
334 string_matches_pattern(const char *str, const char *pattern)
336 while (*str && *pattern)
338 if (*pattern == '.' && pattern[1] == '*')
341 /* Trailing .* matches everything. */
342 if (*pattern == '\0')
346 * Otherwise, scan for a text position at which we can match the
347 * rest of the pattern.
352 * Optimization to prevent most recursion: don't recurse
353 * unless first pattern char might match this text char.
355 if (*str == *pattern || *pattern == '.')
357 if (string_matches_pattern(str, pattern))
365 * End of text with no match.
369 else if (*pattern != '.' && *str != *pattern)
372 * Not the single-character wildcard and no explicit match? Then
382 if (*pattern == '\0')
383 return true; /* end of pattern, so declare match */
385 /* End of input string. Do we have matching pattern remaining? */
386 while (*pattern == '.' && pattern[1] == '*')
388 if (*pattern == '\0')
389 return true; /* end of pattern, so declare match */
395 * Replace all occurances of a string in a string with a different string.
396 * NOTE: Assumes there is enough room in the target buffer!
399 replace_string(char *string, char *replace, char *replacement)
403 while ((ptr = strstr(string, replace)) != NULL)
405 char *dup = strdup(string);
407 strlcpy(string, dup, ptr - string + 1);
408 strcat(string, replacement);
409 strcat(string, dup + (ptr - string) + strlen(replace));
415 * Convert *.source found in the "source" directory, replacing certain tokens
416 * in the file contents with their intended values, and put the resulting files
417 * in the "dest" directory, replacing the ".source" prefix in their names with
421 convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
423 char testtablespace[MAXPGPATH];
424 char indir[MAXPGPATH];
431 snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
433 /* Check that indir actually exists and is a directory */
434 ret = stat(indir, &st);
435 if (ret != 0 || !S_ISDIR(st.st_mode))
438 * No warning, to avoid noise in tests that do not have these
439 * directories; for example, ecpg, contrib and src/pl.
444 names = pgfnames(indir);
446 /* Error logged in pgfnames */
449 snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
454 * On Windows only, clean out the test tablespace dir, or create it if it
455 * doesn't exist. On other platforms we expect the Makefile to take care
456 * of that. (We don't migrate that functionality in here because it'd be
457 * harder to cope with platform-specific issues such as SELinux.)
459 * XXX it would be better if pg_regress.c had nothing at all to do with
460 * testtablespace, and this were handled by a .BAT file or similar on
461 * Windows. See pgsql-hackers discussion of 2008-01-18.
463 if (directory_exists(testtablespace))
464 rmtree(testtablespace, true);
465 make_directory(testtablespace);
468 /* finally loop on each file and do the replacement */
469 for (name = names; *name; name++)
471 char srcfile[MAXPGPATH];
472 char destfile[MAXPGPATH];
473 char prefix[MAXPGPATH];
478 /* reject filenames not finishing in ".source" */
479 if (strlen(*name) < 8)
481 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
486 /* build the full actual paths to open */
487 snprintf(prefix, strlen(*name) - 6, "%s", *name);
488 snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
489 snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest_subdir, prefix, suffix);
491 infile = fopen(srcfile, "r");
494 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
495 progname, srcfile, strerror(errno));
498 outfile = fopen(destfile, "w");
501 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
502 progname, destfile, strerror(errno));
505 while (fgets(line, sizeof(line), infile))
507 replace_string(line, "@abs_srcdir@", inputdir);
508 replace_string(line, "@abs_builddir@", outputdir);
509 replace_string(line, "@testtablespace@", testtablespace);
510 replace_string(line, "@libdir@", dlpath);
511 replace_string(line, "@DLSUFFIX@", DLSUFFIX);
512 fputs(line, outfile);
519 * If we didn't process any files, complain because it probably means
520 * somebody neglected to pass the needed --inputdir argument.
524 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
529 pgfnames_cleanup(names);
532 /* Create the .sql and .out files from the .source files, if any */
534 convert_sourcefiles(void)
536 convert_sourcefiles_in("input", "sql", "sql");
537 convert_sourcefiles_in("output", "expected", "out");
541 * Scan resultmap file to find which platform-specific expected files to use.
543 * The format of each line of the file is
544 * testname/hostplatformpattern=substitutefile
545 * where the hostplatformpattern is evaluated per the rules of expr(1),
546 * namely, it is a standard regular expression with an implicit ^ at the start.
547 * (We currently support only a very limited subset of regular expressions,
548 * see string_matches_pattern() above.) What hostplatformpattern will be
549 * matched against is the config.guess output. (In the shell-script version,
550 * we also provided an indication of whether gcc or another compiler was in
551 * use, but that facility isn't used anymore.)
559 /* scan the file ... */
560 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
564 /* OK if it doesn't exist, else complain */
567 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
568 progname, buf, strerror(errno));
572 while (fgets(buf, sizeof(buf), f))
579 /* strip trailing whitespace, especially the newline */
581 while (i > 0 && isspace((unsigned char) buf[i - 1]))
584 /* parse out the line fields */
585 file_type = strchr(buf, ':');
588 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
594 platform = strchr(file_type, ':');
597 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
602 expected = strchr(platform, '=');
605 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
612 * if it's for current platform, save it in resultmap list. Note: by
613 * adding at the front of the list, we ensure that in ambiguous cases,
614 * the last match in the resultmap file is used. This mimics the
615 * behavior of the old shell script.
617 if (string_matches_pattern(host_platform, platform))
619 _resultmap *entry = malloc(sizeof(_resultmap));
621 entry->test = strdup(buf);
622 entry->type = strdup(file_type);
623 entry->resultfile = strdup(expected);
624 entry->next = resultmap;
632 * Check in resultmap if we should be looking at a different file
636 get_expectfile(const char *testname, const char *file)
642 * Determine the file type from the file name. This is just what is
643 * following the last dot in the file name.
645 if (!file || !(file_type = strrchr(file, '.')))
650 for (rm = resultmap; rm != NULL; rm = rm->next)
652 if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
654 return rm->resultfile;
662 * Handy subroutine for setting an environment variable "var" to "val"
665 doputenv(const char *var, const char *val)
667 char *s = malloc(strlen(var) + strlen(val) + 2);
669 sprintf(s, "%s=%s", var, val);
674 * Set the environment variable "pathname", prepending "addval" to its
675 * old value (if any).
678 add_to_path(const char *pathname, char separator, const char *addval)
680 char *oldval = getenv(pathname);
683 if (!oldval || !oldval[0])
685 /* no previous value */
686 newval = malloc(strlen(pathname) + strlen(addval) + 2);
687 sprintf(newval, "%s=%s", pathname, addval);
691 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
692 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
698 * Prepare environment variables for running regression tests
701 initialize_environment(void)
708 * Clear out any non-C locale settings
710 unsetenv("LC_COLLATE");
711 unsetenv("LC_CTYPE");
712 unsetenv("LC_MONETARY");
713 unsetenv("LC_NUMERIC");
716 /* On Windows the default locale cannot be English, so force it */
717 #if defined(WIN32) || defined(__CYGWIN__)
723 * Set translation-related settings to English; otherwise psql will
724 * produce translated messages and produce diffs. (XXX If we ever support
725 * translation of pg_regress, this needs to be moved elsewhere, where psql
726 * is actually called.)
728 unsetenv("LANGUAGE");
730 putenv("LC_MESSAGES=C");
733 * Set encoding as requested
736 doputenv("PGCLIENTENCODING", encoding);
738 unsetenv("PGCLIENTENCODING");
741 * Set timezone and datestyle for datetime-related tests
743 putenv("PGTZ=PST8PDT");
744 putenv("PGDATESTYLE=Postgres, MDY");
747 * Likewise set intervalstyle to ensure consistent results. This is a bit
748 * more painful because we must use PGOPTIONS, and we want to preserve the
749 * user's ability to set other variables through that.
752 const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
753 const char *old_pgoptions = getenv("PGOPTIONS");
758 new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
759 sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
760 putenv(new_pgoptions);
766 * Clear out any environment vars that might cause psql to connect to
767 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
768 * we also use psql's -X switch consistently, so that ~/.psqlrc files
769 * won't mess things up.) Also, set PGPORT to the temp port, and set
770 * or unset PGHOST depending on whether we are using TCP or Unix
773 unsetenv("PGDATABASE");
775 unsetenv("PGSERVICE");
776 unsetenv("PGSSLMODE");
777 unsetenv("PGREQUIRESSL");
778 unsetenv("PGCONNECT_TIMEOUT");
780 if (hostname != NULL)
781 doputenv("PGHOST", hostname);
784 unsetenv("PGHOSTADDR");
789 sprintf(s, "%d", port);
790 doputenv("PGPORT", s);
794 * Adjust path variables to point into the temp-install tree
796 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
797 sprintf(tmp, "%s/install/%s", temp_install, bindir);
800 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
801 sprintf(tmp, "%s/install/%s", temp_install, libdir);
804 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
805 sprintf(tmp, "%s/install/%s", temp_install, datadir);
808 /* psql will be installed into temp-install bindir */
812 * Set up shared library paths to include the temp install.
814 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
815 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
816 * Windows needs shared libraries in PATH (only those linked into
817 * executables, not dlopen'ed ones). Feel free to account for others
820 add_to_path("LD_LIBRARY_PATH", ':', libdir);
821 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
822 add_to_path("LIBPATH", ':', libdir);
824 add_to_path("PATH", ';', libdir);
825 #elif defined(__CYGWIN__)
826 add_to_path("PATH", ':', libdir);
835 * When testing an existing install, we honor existing environment
836 * variables, except if they're overridden by command line options.
838 if (hostname != NULL)
840 doputenv("PGHOST", hostname);
841 unsetenv("PGHOSTADDR");
847 sprintf(s, "%d", port);
848 doputenv("PGPORT", s);
851 doputenv("PGUSER", user);
854 * Report what we're connecting to
856 pghost = getenv("PGHOST");
857 pgport = getenv("PGPORT");
858 #ifndef HAVE_UNIX_SOCKETS
860 pghost = "localhost";
863 if (pghost && pgport)
864 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
865 if (pghost && !pgport)
866 printf(_("(using postmaster on %s, default port)\n"), pghost);
867 if (!pghost && pgport)
868 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
869 if (!pghost && !pgport)
870 printf(_("(using postmaster on Unix socket, default port)\n"));
873 convert_sourcefiles();
878 * Issue a command via psql, connecting to the specified database
880 * Since we use system(), this doesn't return until the operation finishes
883 psql_command(const char *database, const char *query,...)
885 char query_formatted[1024];
886 char query_escaped[2048];
887 char psql_cmd[MAXPGPATH + 2048];
892 /* Generate the query with insertion of sprintf arguments */
893 va_start(args, query);
894 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
897 /* Now escape any shell double-quote metacharacters */
899 for (s = query_formatted; *s; s++)
901 if (strchr("\\\"$`", *s))
907 /* And now we can build and execute the shell command */
908 snprintf(psql_cmd, sizeof(psql_cmd),
909 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
910 psqldir ? psqldir : "",
915 if (system(psql_cmd) != 0)
917 /* psql probably already reported the error */
918 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
924 * Spawn a process to execute the given shell command; don't wait for it
926 * Returns the process ID (or HANDLE) so we can wait for it later
929 spawn_process(const char *cmdline)
935 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
936 * ... does anyone still care about systems where that doesn't work?
946 fprintf(stderr, _("%s: could not fork: %s\n"),
947 progname, strerror(errno));
955 * Instead of using system(), exec the shell directly, and tell it to
956 * "exec" the command too. This saves two useless processes per
957 * parallel test case.
959 char *cmdline2 = malloc(strlen(cmdline) + 6);
961 sprintf(cmdline2, "exec %s", cmdline);
962 execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
963 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
964 progname, shellprog, strerror(errno));
965 exit(1); /* not exit_nicely here... */
973 PROCESS_INFORMATION pi;
975 HANDLE restrictedToken;
976 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
977 SID_AND_ATTRIBUTES dropSids[2];
978 __CreateRestrictedToken _CreateRestrictedToken = NULL;
979 HANDLE Advapi32Handle;
981 ZeroMemory(&si, sizeof(si));
984 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
985 if (Advapi32Handle != NULL)
987 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
990 if (_CreateRestrictedToken == NULL)
992 if (Advapi32Handle != NULL)
993 FreeLibrary(Advapi32Handle);
994 fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
999 /* Open the current token to use as base for the restricted one */
1000 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
1002 fprintf(stderr, _("could not open process token: %lu\n"),
1007 /* Allocate list of SIDs to remove */
1008 ZeroMemory(&dropSids, sizeof(dropSids));
1009 if (!AllocateAndInitializeSid(&NtAuthority, 2,
1010 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
1011 !AllocateAndInitializeSid(&NtAuthority, 2,
1012 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
1014 fprintf(stderr, _("could not allocate SIDs: %lu\n"), GetLastError());
1018 b = _CreateRestrictedToken(origToken,
1019 DISABLE_MAX_PRIVILEGE,
1020 sizeof(dropSids) / sizeof(dropSids[0]),
1026 FreeSid(dropSids[1].Sid);
1027 FreeSid(dropSids[0].Sid);
1028 CloseHandle(origToken);
1029 FreeLibrary(Advapi32Handle);
1033 fprintf(stderr, _("could not create restricted token: %lu\n"),
1038 cmdline2 = malloc(strlen(cmdline) + 8);
1039 sprintf(cmdline2, "cmd /c %s", cmdline);
1042 AddUserToTokenDacl(restrictedToken);
1045 if (!CreateProcessAsUser(restrictedToken,
1057 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
1058 cmdline2, GetLastError());
1064 ResumeThread(pi.hThread);
1065 CloseHandle(pi.hThread);
1071 * Count bytes in file
1074 file_size(const char *file)
1077 FILE *f = fopen(file, "r");
1081 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1082 progname, file, strerror(errno));
1085 fseek(f, 0, SEEK_END);
1092 * Count lines in file
1095 file_line_count(const char *file)
1099 FILE *f = fopen(file, "r");
1103 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1104 progname, file, strerror(errno));
1107 while ((c = fgetc(f)) != EOF)
1117 file_exists(const char *file)
1119 FILE *f = fopen(file, "r");
1128 directory_exists(const char *dir)
1132 if (stat(dir, &st) != 0)
1134 if (S_ISDIR(st.st_mode))
1139 /* Create a directory */
1141 make_directory(const char *dir)
1143 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1145 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1146 progname, dir, strerror(errno));
1152 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1155 get_alternative_expectfile(const char *expectfile, int i)
1158 int ssize = strlen(expectfile) + 2 + 1;
1159 char *tmp = (char *) malloc(ssize);
1160 char *s = (char *) malloc(ssize);
1162 strcpy(tmp, expectfile);
1163 last_dot = strrchr(tmp, '.');
1171 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1177 * Run a "diff" command and also check that it didn't crash
1180 run_diff(const char *cmd, const char *filename)
1185 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1187 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1193 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1194 * but produces nothing to stdout, so we check for that here.
1196 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1198 fprintf(stderr, _("diff command not found: %s\n"), cmd);
1203 return WEXITSTATUS(r);
1207 * Check the actual result file for the given test against expected results
1209 * Returns true if different (failure), false if correct match found.
1210 * In the true case, the diff is appended to the diffs file.
1213 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1215 char expectfile[MAXPGPATH];
1216 char diff[MAXPGPATH];
1217 char cmd[MAXPGPATH * 3];
1218 char best_expect_file[MAXPGPATH];
1220 int best_line_count;
1223 const char *platform_expectfile;
1226 * We can pass either the resultsfile or the expectfile, they should have
1227 * the same type (filename.type) anyway.
1229 platform_expectfile = get_expectfile(testname, resultsfile);
1231 strcpy(expectfile, default_expectfile);
1232 if (platform_expectfile)
1235 * Replace everything afer the last slash in expectfile with what the
1236 * platform_expectfile contains.
1238 char *p = strrchr(expectfile, '/');
1241 strcpy(++p, platform_expectfile);
1244 /* Name to use for temporary diff file */
1245 snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1247 /* OK, run the diff */
1248 snprintf(cmd, sizeof(cmd),
1249 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1250 basic_diff_opts, expectfile, resultsfile, diff);
1252 /* Is the diff file empty? */
1253 if (run_diff(cmd, diff) == 0)
1259 /* There may be secondary comparison files that match better */
1260 best_line_count = file_line_count(diff);
1261 strcpy(best_expect_file, expectfile);
1263 for (i = 0; i <= 9; i++)
1265 char *alt_expectfile;
1267 alt_expectfile = get_alternative_expectfile(expectfile, i);
1268 if (!file_exists(alt_expectfile))
1271 snprintf(cmd, sizeof(cmd),
1272 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1273 basic_diff_opts, alt_expectfile, resultsfile, diff);
1275 if (run_diff(cmd, diff) == 0)
1281 l = file_line_count(diff);
1282 if (l < best_line_count)
1284 /* This diff was a better match than the last one */
1285 best_line_count = l;
1286 strcpy(best_expect_file, alt_expectfile);
1288 free(alt_expectfile);
1292 * fall back on the canonical results file if we haven't tried it yet and
1293 * haven't found a complete match yet.
1296 if (platform_expectfile)
1298 snprintf(cmd, sizeof(cmd),
1299 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1300 basic_diff_opts, default_expectfile, resultsfile, diff);
1302 if (run_diff(cmd, diff) == 0)
1304 /* No diff = no changes = good */
1309 l = file_line_count(diff);
1310 if (l < best_line_count)
1312 /* This diff was a better match than the last one */
1313 best_line_count = l;
1314 strcpy(best_expect_file, default_expectfile);
1319 * Use the best comparison file to generate the "pretty" diff, which we
1320 * append to the diffs summary file.
1322 snprintf(cmd, sizeof(cmd),
1323 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
1324 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1325 run_diff(cmd, difffilename);
1327 /* And append a separator */
1328 difffile = fopen(difffilename, "a");
1332 "\n======================================================================\n\n");
1341 * Wait for specified subprocesses to finish, and return their exit
1342 * statuses into statuses[]
1344 * If names isn't NULL, print each subprocess's name as it finishes
1346 * Note: it's OK to scribble on the pids array, but not on the names array
1349 wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
1355 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1357 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1360 tests_left = num_tests;
1361 while (tests_left > 0)
1368 p = wait(&exit_status);
1370 if (p == INVALID_PID)
1372 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1380 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1381 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1383 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
1387 p = active_pids[r - WAIT_OBJECT_0];
1388 /* compact the active_pids array */
1389 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1392 for (i = 0; i < num_tests; i++)
1397 GetExitCodeProcess(pids[i], &exit_status);
1398 CloseHandle(pids[i]);
1400 pids[i] = INVALID_PID;
1401 statuses[i] = (int) exit_status;
1403 status(" %s", names[i]);
1416 * report nonzero exit code from a test process
1419 log_child_failure(int exitstatus)
1421 if (WIFEXITED(exitstatus))
1422 status(_(" (test process exited with exit code %d)"),
1423 WEXITSTATUS(exitstatus));
1424 else if (WIFSIGNALED(exitstatus))
1427 status(_(" (test process was terminated by exception 0x%X)"),
1428 WTERMSIG(exitstatus));
1429 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1430 status(_(" (test process was terminated by signal %d: %s)"),
1431 WTERMSIG(exitstatus),
1432 WTERMSIG(exitstatus) < NSIG ?
1433 sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
1435 status(_(" (test process was terminated by signal %d)"),
1436 WTERMSIG(exitstatus));
1440 status(_(" (test process exited with unrecognized status %d)"),
1445 * Run all the tests specified in one schedule file
1448 run_schedule(const char *schedule, test_function tfunc)
1450 #define MAX_PARALLEL_TESTS 100
1451 char *tests[MAX_PARALLEL_TESTS];
1452 _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1453 _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1454 _stringlist *tags[MAX_PARALLEL_TESTS];
1455 PID_TYPE pids[MAX_PARALLEL_TESTS];
1456 int statuses[MAX_PARALLEL_TESTS];
1457 _stringlist *ignorelist = NULL;
1462 memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1463 memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1464 memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1466 scf = fopen(schedule, "r");
1469 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1470 progname, schedule, strerror(errno));
1474 while (fgets(scbuf, sizeof(scbuf), scf))
1484 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1486 if (resultfiles[i] == NULL)
1488 free_stringlist(&resultfiles[i]);
1489 free_stringlist(&expectfiles[i]);
1490 free_stringlist(&tags[i]);
1493 /* strip trailing whitespace, especially the newline */
1495 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1498 if (scbuf[0] == '\0' || scbuf[0] == '#')
1500 if (strncmp(scbuf, "test: ", 6) == 0)
1502 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1505 while (*c && isspace((unsigned char) *c))
1507 add_stringlist_item(&ignorelist, c);
1510 * Note: ignore: lines do not run the test, they just say that
1511 * failure of this test when run later on is to be ignored. A bit
1512 * odd but that's how the shell-script version did it.
1518 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1519 schedule, line_num, scbuf);
1525 for (c = test; *c; c++)
1527 if (isspace((unsigned char) *c))
1534 if (num_tests >= MAX_PARALLEL_TESTS)
1536 /* can't print scbuf here, it's already been trashed */
1537 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1538 schedule, line_num);
1541 tests[num_tests] = c;
1549 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1550 schedule, line_num, scbuf);
1556 status(_("test %-24s ... "), tests[0]);
1557 pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1558 wait_for_tests(pids, statuses, NULL, 1);
1559 /* status line is finished below */
1561 else if (max_connections > 0 && max_connections < num_tests)
1565 status(_("parallel group (%d tests, in groups of %d): "),
1566 num_tests, max_connections);
1567 for (i = 0; i < num_tests; i++)
1569 if (i - oldest >= max_connections)
1571 wait_for_tests(pids + oldest, statuses + oldest,
1572 tests + oldest, i - oldest);
1575 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1577 wait_for_tests(pids + oldest, statuses + oldest,
1578 tests + oldest, i - oldest);
1583 status(_("parallel group (%d tests): "), num_tests);
1584 for (i = 0; i < num_tests; i++)
1586 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1588 wait_for_tests(pids, statuses, tests, num_tests);
1592 /* Check results for all tests */
1593 for (i = 0; i < num_tests; i++)
1598 bool differ = false;
1601 status(_(" %-24s ... "), tests[i]);
1604 * Advance over all three lists simultaneously.
1606 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1607 * optional but if there are tags, the tag list has the same
1608 * length as the other two lists.
1610 for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1611 rl != NULL; /* rl and el have the same length */
1612 rl = rl->next, el = el->next)
1617 tl = tl->next; /* tl has the same length as rl and el
1620 newdiff = results_differ(tests[i], rl->str, el->str);
1623 printf("%s ", tl->str);
1630 bool ignore = false;
1633 for (sl = ignorelist; sl != NULL; sl = sl->next)
1635 if (strcmp(tests[i], sl->str) == 0)
1643 status(_("failed (ignored)"));
1644 fail_ignore_count++;
1648 status(_("FAILED"));
1658 if (statuses[i] != 0)
1659 log_child_failure(statuses[i]);
1672 run_single_test(const char *test, test_function tfunc)
1676 _stringlist *resultfiles = NULL;
1677 _stringlist *expectfiles = NULL;
1678 _stringlist *tags = NULL;
1682 bool differ = false;
1684 status(_("test %-24s ... "), test);
1685 pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
1686 wait_for_tests(&pid, &exit_status, NULL, 1);
1689 * Advance over all three lists simultaneously.
1691 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1692 * but if there are tags, the tag list has the same length as the other
1695 for (rl = resultfiles, el = expectfiles, tl = tags;
1696 rl != NULL; /* rl and el have the same length */
1697 rl = rl->next, el = el->next)
1702 tl = tl->next; /* tl has the same length as rl and el if it
1705 newdiff = results_differ(test, rl->str, el->str);
1708 printf("%s ", tl->str);
1715 status(_("FAILED"));
1724 if (exit_status != 0)
1725 log_child_failure(exit_status);
1731 * Create the summary-output files (making them empty if already existing)
1734 open_result_files(void)
1736 char file[MAXPGPATH];
1739 /* create the log file (copy of running status output) */
1740 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1741 logfilename = strdup(file);
1742 logfile = fopen(logfilename, "w");
1745 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1746 progname, logfilename, strerror(errno));
1750 /* create the diffs file as empty */
1751 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1752 difffilename = strdup(file);
1753 difffile = fopen(difffilename, "w");
1756 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1757 progname, difffilename, strerror(errno));
1760 /* we don't keep the diffs file open continuously */
1763 /* also create the output directory if not present */
1764 snprintf(file, sizeof(file), "%s/results", outputdir);
1765 if (!directory_exists(file))
1766 make_directory(file);
1770 drop_database_if_exists(const char *dbname)
1772 header(_("dropping database \"%s\""), dbname);
1773 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1777 create_database(const char *dbname)
1782 * We use template0 so that any installation-local cruft in template1 will
1783 * not mess up the tests.
1785 header(_("creating database \"%s\""), dbname);
1787 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
1788 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1790 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
1791 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1792 psql_command(dbname,
1793 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1794 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1795 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1796 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1797 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1798 dbname, dbname, dbname, dbname, dbname);
1801 * Install any requested procedural languages. We use CREATE OR REPLACE
1802 * so that this will work whether or not the language is preinstalled.
1804 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1806 header(_("installing %s"), sl->str);
1807 psql_command(dbname, "CREATE OR REPLACE LANGUAGE \"%s\"", sl->str);
1811 * Install any requested extensions. We use CREATE IF NOT EXISTS so that
1812 * this will work whether or not the extension is preinstalled.
1814 for (sl = loadextension; sl != NULL; sl = sl->next)
1816 header(_("installing %s"), sl->str);
1817 psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
1822 drop_role_if_exists(const char *rolename)
1824 header(_("dropping role \"%s\""), rolename);
1825 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1829 create_role(const char *rolename, const _stringlist * granted_dbs)
1831 header(_("creating role \"%s\""), rolename);
1832 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
1833 for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
1835 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1836 granted_dbs->str, rolename);
1841 make_absolute_path(const char *in)
1845 if (is_absolute_path(in))
1846 result = strdup(in);
1849 static char cwdbuf[MAXPGPATH];
1853 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1855 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1860 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1861 sprintf(result, "%s/%s", cwdbuf, in);
1864 canonicalize_path(result);
1871 printf(_("PostgreSQL regression test driver\n"));
1873 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1875 printf(_("Options:\n"));
1876 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1877 printf(_(" --debug turn on debug mode in programs that are run\n"));
1878 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1879 printf(_(" --load-language=lang load the named language before running the\n"));
1880 printf(_(" tests; can appear multiple times\n"));
1881 printf(_(" --load-extension=ext load the named extension before running the\n"));
1882 printf(_(" tests; can appear multiple times\n"));
1883 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1884 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1885 printf(_(" (default is 0 meaning unlimited)\n"));
1886 printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
1887 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1888 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1889 printf(_(" (can be used multiple times to concatenate)\n"));
1890 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1891 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1892 printf(_(" --use-existing use an existing installation\n"));
1893 printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
1895 printf(_("Options for \"temp-install\" mode:\n"));
1896 printf(_(" --no-locale use C locale\n"));
1897 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1898 printf(_(" --port=PORT start postmaster on PORT\n"));
1899 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1900 printf(_(" --extra-install=DIR additional directory to install (e.g., contrib\n"));
1902 printf(_("Options for using an existing installation:\n"));
1903 printf(_(" --host=HOST use postmaster running on HOST\n"));
1904 printf(_(" --port=PORT use postmaster running at PORT\n"));
1905 printf(_(" --user=USER connect as USER\n"));
1906 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1908 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1909 printf(_("if the tests could not be run for some reason.\n"));
1911 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1915 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1921 char buf[MAXPGPATH * 4];
1922 char buf2[MAXPGPATH * 4];
1924 static struct option long_options[] = {
1925 {"help", no_argument, NULL, 'h'},
1926 {"version", no_argument, NULL, 'V'},
1927 {"dbname", required_argument, NULL, 1},
1928 {"debug", no_argument, NULL, 2},
1929 {"inputdir", required_argument, NULL, 3},
1930 {"load-language", required_argument, NULL, 4},
1931 {"max-connections", required_argument, NULL, 5},
1932 {"encoding", required_argument, NULL, 6},
1933 {"outputdir", required_argument, NULL, 7},
1934 {"schedule", required_argument, NULL, 8},
1935 {"temp-install", required_argument, NULL, 9},
1936 {"no-locale", no_argument, NULL, 10},
1937 {"top-builddir", required_argument, NULL, 11},
1938 {"host", required_argument, NULL, 13},
1939 {"port", required_argument, NULL, 14},
1940 {"user", required_argument, NULL, 15},
1941 {"psqldir", required_argument, NULL, 16},
1942 {"dlpath", required_argument, NULL, 17},
1943 {"create-role", required_argument, NULL, 18},
1944 {"temp-config", required_argument, NULL, 19},
1945 {"use-existing", no_argument, NULL, 20},
1946 {"launcher", required_argument, NULL, 21},
1947 {"load-extension", required_argument, NULL, 22},
1948 {"extra-install", required_argument, NULL, 23},
1952 progname = get_progname(argv[0]);
1953 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
1955 #ifndef HAVE_UNIX_SOCKETS
1956 /* no unix domain sockets available, so change default */
1957 hostname = "localhost";
1961 * We call the initialization function here because that way we can set
1962 * default parameters and let them be overwritten by the commandline.
1966 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1974 puts("pg_regress (PostgreSQL) " PG_VERSION);
1979 * If a default database was specified, we need to remove it
1980 * before we add the specified one.
1982 free_stringlist(&dblist);
1983 split_to_stringlist(strdup(optarg), ", ", &dblist);
1989 inputdir = strdup(optarg);
1992 add_stringlist_item(&loadlanguage, optarg);
1995 max_connections = atoi(optarg);
1998 encoding = strdup(optarg);
2001 outputdir = strdup(optarg);
2004 add_stringlist_item(&schedulelist, optarg);
2007 temp_install = make_absolute_path(optarg);
2013 top_builddir = strdup(optarg);
2016 hostname = strdup(optarg);
2019 port = atoi(optarg);
2020 port_specified_by_user = true;
2023 user = strdup(optarg);
2026 /* "--psqldir=" should mean to use PATH */
2028 psqldir = strdup(optarg);
2031 dlpath = strdup(optarg);
2034 split_to_stringlist(strdup(optarg), ", ", &extraroles);
2037 temp_config = strdup(optarg);
2040 use_existing = true;
2043 launcher = strdup(optarg);
2046 add_stringlist_item(&loadextension, optarg);
2049 add_stringlist_item(&extra_install, optarg);
2052 /* getopt_long already emitted a complaint */
2053 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2060 * if we still have arguments, they are extra tests to run
2062 while (argc - optind >= 1)
2064 add_stringlist_item(&extra_tests, argv[optind]);
2068 if (temp_install && !port_specified_by_user)
2071 * To reduce chances of interference with parallel installations, use
2072 * a port number starting in the private range (49152-65535)
2073 * calculated from the version number.
2075 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2077 inputdir = make_absolute_path(inputdir);
2078 outputdir = make_absolute_path(outputdir);
2079 dlpath = make_absolute_path(dlpath);
2084 open_result_files();
2086 initialize_environment();
2088 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2089 unlimit_core_size();
2098 * Prepare the temp installation
2102 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2106 if (directory_exists(temp_install))
2108 header(_("removing existing temp installation"));
2109 rmtree(temp_install, true);
2112 header(_("creating temporary installation"));
2114 /* make the temp install top directory */
2115 make_directory(temp_install);
2117 /* and a directory for log files */
2118 snprintf(buf, sizeof(buf), "%s/log", outputdir);
2119 if (!directory_exists(buf))
2120 make_directory(buf);
2122 /* "make install" */
2123 #ifndef WIN32_ONLY_COMPILER
2124 snprintf(buf, sizeof(buf),
2125 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2126 makeprog, top_builddir, temp_install, outputdir);
2128 snprintf(buf, sizeof(buf),
2129 SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2130 top_builddir, temp_install, outputdir);
2134 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2138 for (sl = extra_install; sl != NULL; sl = sl->next)
2140 #ifndef WIN32_ONLY_COMPILER
2141 snprintf(buf, sizeof(buf),
2142 SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2143 makeprog, top_builddir, sl->str, temp_install, outputdir);
2145 fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
2151 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2157 header(_("initializing database system"));
2158 snprintf(buf, sizeof(buf),
2159 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
2160 bindir, temp_install, datadir,
2161 debug ? " --debug" : "",
2162 nolocale ? " --no-locale" : "",
2166 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2171 * Adjust the default postgresql.conf as needed for regression
2172 * testing. The user can specify a file to be appended; in any case we
2173 * set max_prepared_transactions to enable testing of prepared xacts.
2174 * (Note: to reduce the probability of unexpected shmmax failures,
2175 * don't set max_prepared_transactions any higher than actually needed
2176 * by the prepared_xacts regression test.)
2178 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
2179 pg_conf = fopen(buf, "a");
2180 if (pg_conf == NULL)
2182 fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2185 fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2186 fputs("max_prepared_transactions = 2\n", pg_conf);
2188 if (temp_config != NULL)
2191 char line_buf[1024];
2193 extra_conf = fopen(temp_config, "r");
2194 if (extra_conf == NULL)
2196 fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2199 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2200 fputs(line_buf, pg_conf);
2207 * Check if there is a postmaster running already.
2209 snprintf(buf2, sizeof(buf2),
2210 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
2211 bindir, DEVNULL, DEVNULL);
2213 for (i = 0; i < 16; i++)
2215 if (system(buf2) == 0)
2219 if (port_specified_by_user || i == 15)
2221 fprintf(stderr, _("port %d apparently in use\n"), port);
2222 if (!port_specified_by_user)
2223 fprintf(stderr, _("%s: could not determine an available port\n"), progname);
2224 fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2228 fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2230 sprintf(s, "%d", port);
2231 doputenv("PGPORT", s);
2238 * Start the temp postmaster
2240 header(_("starting postmaster"));
2241 snprintf(buf, sizeof(buf),
2242 SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
2243 bindir, temp_install,
2244 debug ? " -d 5" : "",
2245 hostname ? hostname : "",
2247 postmaster_pid = spawn_process(buf);
2248 if (postmaster_pid == INVALID_PID)
2250 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2251 progname, strerror(errno));
2256 * Wait till postmaster is able to accept connections (normally only a
2257 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2260 for (i = 0; i < 60; i++)
2262 /* Done if psql succeeds */
2263 if (system(buf2) == 0)
2267 * Fail immediately if postmaster has exited
2270 if (kill(postmaster_pid, 0) != 0)
2272 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2275 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2279 pg_usleep(1000000L);
2283 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2286 * If we get here, the postmaster is probably wedged somewhere in
2287 * startup. Try to kill it ungracefully rather than leaving a
2288 * stuck postmaster that might interfere with subsequent test
2292 if (kill(postmaster_pid, SIGKILL) != 0 &&
2294 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2295 progname, strerror(errno));
2297 if (TerminateProcess(postmaster_pid, 255) == 0)
2298 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
2299 progname, GetLastError());
2305 postmaster_running = true;
2308 /* need a series of two casts to convert HANDLE without compiler warning */
2309 #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2311 #define ULONGPID(x) (unsigned long) (x)
2313 printf(_("running on port %d with PID %lu\n"),
2314 port, ULONGPID(postmaster_pid));
2319 * Using an existing installation, so may need to get rid of
2320 * pre-existing database(s) and role(s)
2324 for (sl = dblist; sl; sl = sl->next)
2325 drop_database_if_exists(sl->str);
2326 for (sl = extraroles; sl; sl = sl->next)
2327 drop_role_if_exists(sl->str);
2332 * Create the test database(s) and role(s)
2336 for (sl = dblist; sl; sl = sl->next)
2337 create_database(sl->str);
2338 for (sl = extraroles; sl; sl = sl->next)
2339 create_role(sl->str, dblist);
2343 * Ready to run the tests
2345 header(_("running regression test queries"));
2347 for (sl = schedulelist; sl != NULL; sl = sl->next)
2349 run_schedule(sl->str, tfunc);
2352 for (sl = extra_tests; sl != NULL; sl = sl->next)
2354 run_single_test(sl->str, tfunc);
2358 * Shut down temp installation's postmaster
2362 header(_("shutting down postmaster"));
2369 * Emit nice-looking summary message
2371 if (fail_count == 0 && fail_ignore_count == 0)
2372 snprintf(buf, sizeof(buf),
2373 _(" All %d tests passed. "),
2375 else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2376 snprintf(buf, sizeof(buf),
2377 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2379 success_count + fail_ignore_count,
2381 else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2382 snprintf(buf, sizeof(buf),
2383 _(" %d of %d tests failed. "),
2385 success_count + fail_count);
2387 /* fail_count>0 && fail_ignore_count>0 */
2388 snprintf(buf, sizeof(buf),
2389 _(" %d of %d tests failed, %d of these failures ignored. "),
2390 fail_count + fail_ignore_count,
2391 success_count + fail_count + fail_ignore_count,
2395 for (i = strlen(buf); i > 0; i--)
2397 printf("\n%s\n", buf);
2398 for (i = strlen(buf); i > 0; i--)
2403 if (file_size(difffilename) > 0)
2405 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2406 "file \"%s\". A copy of the test summary that you see\n"
2407 "above is saved in the file \"%s\".\n\n"),
2408 difffilename, logfilename);
2412 unlink(difffilename);
2413 unlink(logfilename);
2416 if (fail_count != 0)