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-2010, 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.70 2010/02/24 01:35:14 tgl Exp $
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 static _stringlist *loadlanguage = NULL;
88 static int max_connections = 0;
89 static char *encoding = NULL;
90 static _stringlist *schedulelist = NULL;
91 static _stringlist *extra_tests = NULL;
92 static char *temp_install = NULL;
93 static char *temp_config = NULL;
94 static char *top_builddir = NULL;
95 static bool nolocale = false;
96 static bool use_existing = false;
97 static char *hostname = NULL;
99 static bool port_specified_by_user = false;
100 static char *dlpath = PKGLIBDIR;
101 static char *user = NULL;
102 static _stringlist *extraroles = NULL;
104 /* internal variables */
105 static const char *progname;
106 static char *logfilename;
107 static FILE *logfile;
108 static char *difffilename;
110 static _resultmap *resultmap = NULL;
112 static PID_TYPE postmaster_pid = INVALID_PID;
113 static bool postmaster_running = false;
115 static int success_count = 0;
116 static int fail_count = 0;
117 static int fail_ignore_count = 0;
119 static bool directory_exists(const char *dir);
120 static void make_directory(const char *dir);
123 header(const char *fmt,...)
124 /* This extension allows gcc to check the format string for consistency with
125 the supplied arguments. */
126 __attribute__((format(printf, 1, 2)));
128 status(const char *fmt,...)
129 /* This extension allows gcc to check the format string for consistency with
130 the supplied arguments. */
131 __attribute__((format(printf, 1, 2)));
133 psql_command(const char *database, const char *query,...)
134 /* This extension allows gcc to check the format string for consistency with
135 the supplied arguments. */
136 __attribute__((format(printf, 2, 3)));
139 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
141 /* Windows API define missing from MingW headers */
142 #define DISABLE_MAX_PRIVILEGE 0x1
146 * allow core files if possible.
148 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
150 unlimit_core_size(void)
154 getrlimit(RLIMIT_CORE, &lim);
155 if (lim.rlim_max == 0)
158 _("%s: could not set core size: disallowed by hard limit\n"),
162 else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
164 lim.rlim_cur = lim.rlim_max;
165 setrlimit(RLIMIT_CORE, &lim);
172 * Add an item at the end of a stringlist.
175 add_stringlist_item(_stringlist ** listhead, const char *str)
177 _stringlist *newentry = malloc(sizeof(_stringlist));
178 _stringlist *oldentry;
180 newentry->str = strdup(str);
181 newentry->next = NULL;
182 if (*listhead == NULL)
183 *listhead = newentry;
186 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
188 oldentry->next = newentry;
196 free_stringlist(_stringlist ** listhead)
198 if (listhead == NULL || *listhead == NULL)
200 if ((*listhead)->next != NULL)
201 free_stringlist(&((*listhead)->next));
202 free((*listhead)->str);
208 * Split a delimited string into a stringlist
211 split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
213 char *sc = strdup(s);
214 char *token = strtok(sc, delim);
218 add_stringlist_item(listhead, token);
219 token = strtok(NULL, delim);
225 * Print a progress banner on stdout.
228 header(const char *fmt,...)
234 vsnprintf(tmp, sizeof(tmp), fmt, ap);
237 fprintf(stdout, "============== %-38s ==============\n", tmp);
242 * Print "doing something ..." --- supplied text should not end with newline
245 status(const char *fmt,...)
250 vfprintf(stdout, fmt, ap);
257 vfprintf(logfile, fmt, ap);
263 * Done "doing something ..."
268 fprintf(stdout, "\n");
271 fprintf(logfile, "\n");
275 * shut down temp postmaster
278 stop_postmaster(void)
280 if (postmaster_running)
282 /* We use pg_ctl to issue the kill and wait for stop */
283 char buf[MAXPGPATH * 2];
286 /* On Windows, system() seems not to force fflush, so... */
290 snprintf(buf, sizeof(buf),
291 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
292 bindir, temp_install);
296 fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
298 exit(2); /* not exit_nicely(), that would be recursive */
301 postmaster_running = false;
306 * Always exit through here, not through plain exit(), to ensure we make
307 * an effort to shut down a temp postmaster
310 exit_nicely(int code)
317 * Check whether string matches pattern
319 * In the original shell script, this function was implemented using expr(1),
320 * which provides basic regular expressions restricted to match starting at
321 * the string start (in conventional regex terms, there's an implicit "^"
322 * at the start of the pattern --- but no implicit "$" at the end).
324 * For now, we only support "." and ".*" as non-literal metacharacters,
325 * because that's all that anyone has found use for in resultmap. This
326 * code could be extended if more functionality is needed.
329 string_matches_pattern(const char *str, const char *pattern)
331 while (*str && *pattern)
333 if (*pattern == '.' && pattern[1] == '*')
336 /* Trailing .* matches everything. */
337 if (*pattern == '\0')
341 * Otherwise, scan for a text position at which we can match the
342 * rest of the pattern.
347 * Optimization to prevent most recursion: don't recurse
348 * unless first pattern char might match this text char.
350 if (*str == *pattern || *pattern == '.')
352 if (string_matches_pattern(str, pattern))
360 * End of text with no match.
364 else if (*pattern != '.' && *str != *pattern)
367 * Not the single-character wildcard and no explicit match? Then
377 if (*pattern == '\0')
378 return true; /* end of pattern, so declare match */
380 /* End of input string. Do we have matching pattern remaining? */
381 while (*pattern == '.' && pattern[1] == '*')
383 if (*pattern == '\0')
384 return true; /* end of pattern, so declare match */
390 * Replace all occurances of a string in a string with a different string.
391 * NOTE: Assumes there is enough room in the target buffer!
394 replace_string(char *string, char *replace, char *replacement)
398 while ((ptr = strstr(string, replace)) != NULL)
400 char *dup = strdup(string);
402 strlcpy(string, dup, ptr - string + 1);
403 strcat(string, replacement);
404 strcat(string, dup + (ptr - string) + strlen(replace));
410 * Convert *.source found in the "source" directory, replacing certain tokens
411 * in the file contents with their intended values, and put the resulting files
412 * in the "dest" directory, replacing the ".source" prefix in their names with
416 convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
418 char testtablespace[MAXPGPATH];
419 char indir[MAXPGPATH];
426 snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
428 /* Check that indir actually exists and is a directory */
429 ret = stat(indir, &st);
430 if (ret != 0 || !S_ISDIR(st.st_mode))
433 * No warning, to avoid noise in tests that do not have these
434 * directories; for example, ecpg, contrib and src/pl.
439 names = pgfnames(indir);
441 /* Error logged in pgfnames */
444 snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
449 * On Windows only, clean out the test tablespace dir, or create it if it
450 * doesn't exist. On other platforms we expect the Makefile to take care
451 * of that. (We don't migrate that functionality in here because it'd be
452 * harder to cope with platform-specific issues such as SELinux.)
454 * XXX it would be better if pg_regress.c had nothing at all to do with
455 * testtablespace, and this were handled by a .BAT file or similar on
456 * Windows. See pgsql-hackers discussion of 2008-01-18.
458 if (directory_exists(testtablespace))
459 rmtree(testtablespace, true);
460 make_directory(testtablespace);
463 /* finally loop on each file and do the replacement */
464 for (name = names; *name; name++)
466 char srcfile[MAXPGPATH];
467 char destfile[MAXPGPATH];
468 char prefix[MAXPGPATH];
473 /* reject filenames not finishing in ".source" */
474 if (strlen(*name) < 8)
476 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
481 /* build the full actual paths to open */
482 snprintf(prefix, strlen(*name) - 6, "%s", *name);
483 snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
484 snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest_subdir, prefix, suffix);
486 infile = fopen(srcfile, "r");
489 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
490 progname, srcfile, strerror(errno));
493 outfile = fopen(destfile, "w");
496 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
497 progname, destfile, strerror(errno));
500 while (fgets(line, sizeof(line), infile))
502 replace_string(line, "@abs_srcdir@", inputdir);
503 replace_string(line, "@abs_builddir@", outputdir);
504 replace_string(line, "@testtablespace@", testtablespace);
505 replace_string(line, "@libdir@", dlpath);
506 replace_string(line, "@DLSUFFIX@", DLSUFFIX);
507 fputs(line, outfile);
514 * If we didn't process any files, complain because it probably means
515 * somebody neglected to pass the needed --inputdir argument.
519 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
524 pgfnames_cleanup(names);
527 /* Create the .sql and .out files from the .source files, if any */
529 convert_sourcefiles(void)
531 convert_sourcefiles_in("input", "sql", "sql");
532 convert_sourcefiles_in("output", "expected", "out");
536 * Scan resultmap file to find which platform-specific expected files to use.
538 * The format of each line of the file is
539 * testname/hostplatformpattern=substitutefile
540 * where the hostplatformpattern is evaluated per the rules of expr(1),
541 * namely, it is a standard regular expression with an implicit ^ at the start.
542 * (We currently support only a very limited subset of regular expressions,
543 * see string_matches_pattern() above.) What hostplatformpattern will be
544 * matched against is the config.guess output. (In the shell-script version,
545 * we also provided an indication of whether gcc or another compiler was in
546 * use, but that facility isn't used anymore.)
554 /* scan the file ... */
555 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
559 /* OK if it doesn't exist, else complain */
562 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
563 progname, buf, strerror(errno));
567 while (fgets(buf, sizeof(buf), f))
574 /* strip trailing whitespace, especially the newline */
576 while (i > 0 && isspace((unsigned char) buf[i - 1]))
579 /* parse out the line fields */
580 file_type = strchr(buf, ':');
583 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
589 platform = strchr(file_type, ':');
592 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
597 expected = strchr(platform, '=');
600 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
607 * if it's for current platform, save it in resultmap list. Note: by
608 * adding at the front of the list, we ensure that in ambiguous cases,
609 * the last match in the resultmap file is used. This mimics the
610 * behavior of the old shell script.
612 if (string_matches_pattern(host_platform, platform))
614 _resultmap *entry = malloc(sizeof(_resultmap));
616 entry->test = strdup(buf);
617 entry->type = strdup(file_type);
618 entry->resultfile = strdup(expected);
619 entry->next = resultmap;
627 * Check in resultmap if we should be looking at a different file
631 get_expectfile(const char *testname, const char *file)
637 * Determine the file type from the file name. This is just what is
638 * following the last dot in the file name.
640 if (!file || !(file_type = strrchr(file, '.')))
645 for (rm = resultmap; rm != NULL; rm = rm->next)
647 if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
649 return rm->resultfile;
657 * Handy subroutine for setting an environment variable "var" to "val"
660 doputenv(const char *var, const char *val)
662 char *s = malloc(strlen(var) + strlen(val) + 2);
664 sprintf(s, "%s=%s", var, val);
669 * Set the environment variable "pathname", prepending "addval" to its
670 * old value (if any).
673 add_to_path(const char *pathname, char separator, const char *addval)
675 char *oldval = getenv(pathname);
678 if (!oldval || !oldval[0])
680 /* no previous value */
681 newval = malloc(strlen(pathname) + strlen(addval) + 2);
682 sprintf(newval, "%s=%s", pathname, addval);
686 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
687 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
693 * Prepare environment variables for running regression tests
696 initialize_environment(void)
703 * Clear out any non-C locale settings
705 unsetenv("LC_COLLATE");
706 unsetenv("LC_CTYPE");
707 unsetenv("LC_MONETARY");
708 unsetenv("LC_NUMERIC");
711 /* On Windows the default locale cannot be English, so force it */
712 #if defined(WIN32) || defined(__CYGWIN__)
718 * Set translation-related settings to English; otherwise psql will
719 * produce translated messages and produce diffs. (XXX If we ever support
720 * translation of pg_regress, this needs to be moved elsewhere, where psql
721 * is actually called.)
723 unsetenv("LANGUAGE");
725 putenv("LC_MESSAGES=C");
728 * Set multibyte as requested
731 doputenv("PGCLIENTENCODING", encoding);
733 unsetenv("PGCLIENTENCODING");
736 * Set timezone and datestyle for datetime-related tests
738 putenv("PGTZ=PST8PDT");
739 putenv("PGDATESTYLE=Postgres, MDY");
742 * Likewise set intervalstyle to ensure consistent results. This is a bit
743 * more painful because we must use PGOPTIONS, and we want to preserve the
744 * user's ability to set other variables through that.
747 const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
748 const char *old_pgoptions = getenv("PGOPTIONS");
753 new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
754 sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
755 putenv(new_pgoptions);
761 * Clear out any environment vars that might cause psql to connect to
762 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
763 * we also use psql's -X switch consistently, so that ~/.psqlrc files
764 * won't mess things up.) Also, set PGPORT to the temp port, and set
765 * or unset PGHOST depending on whether we are using TCP or Unix
768 unsetenv("PGDATABASE");
770 unsetenv("PGSERVICE");
771 unsetenv("PGSSLMODE");
772 unsetenv("PGREQUIRESSL");
773 unsetenv("PGCONNECT_TIMEOUT");
775 if (hostname != NULL)
776 doputenv("PGHOST", hostname);
779 unsetenv("PGHOSTADDR");
784 sprintf(s, "%d", port);
785 doputenv("PGPORT", s);
789 * Adjust path variables to point into the temp-install tree
791 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
792 sprintf(tmp, "%s/install/%s", temp_install, bindir);
795 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
796 sprintf(tmp, "%s/install/%s", temp_install, libdir);
799 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
800 sprintf(tmp, "%s/install/%s", temp_install, datadir);
803 /* psql will be installed into temp-install bindir */
807 * Set up shared library paths to include the temp install.
809 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
810 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
811 * Windows needs shared libraries in PATH (only those linked into
812 * executables, not dlopen'ed ones). Feel free to account for others
815 add_to_path("LD_LIBRARY_PATH", ':', libdir);
816 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
817 add_to_path("LIBPATH", ':', libdir);
818 #if defined(WIN32) || defined(__CYGWIN__)
819 add_to_path("PATH", ';', libdir);
828 * When testing an existing install, we honor existing environment
829 * variables, except if they're overridden by command line options.
831 if (hostname != NULL)
833 doputenv("PGHOST", hostname);
834 unsetenv("PGHOSTADDR");
840 sprintf(s, "%d", port);
841 doputenv("PGPORT", s);
844 doputenv("PGUSER", user);
847 * Report what we're connecting to
849 pghost = getenv("PGHOST");
850 pgport = getenv("PGPORT");
851 #ifndef HAVE_UNIX_SOCKETS
853 pghost = "localhost";
856 if (pghost && pgport)
857 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
858 if (pghost && !pgport)
859 printf(_("(using postmaster on %s, default port)\n"), pghost);
860 if (!pghost && pgport)
861 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
862 if (!pghost && !pgport)
863 printf(_("(using postmaster on Unix socket, default port)\n"));
866 convert_sourcefiles();
871 * Issue a command via psql, connecting to the specified database
873 * Since we use system(), this doesn't return until the operation finishes
876 psql_command(const char *database, const char *query,...)
878 char query_formatted[1024];
879 char query_escaped[2048];
880 char psql_cmd[MAXPGPATH + 2048];
885 /* Generate the query with insertion of sprintf arguments */
886 va_start(args, query);
887 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
890 /* Now escape any shell double-quote metacharacters */
892 for (s = query_formatted; *s; s++)
894 if (strchr("\\\"$`", *s))
900 /* And now we can build and execute the shell command */
901 snprintf(psql_cmd, sizeof(psql_cmd),
902 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
903 psqldir ? psqldir : "",
908 if (system(psql_cmd) != 0)
910 /* psql probably already reported the error */
911 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
917 * Spawn a process to execute the given shell command; don't wait for it
919 * Returns the process ID (or HANDLE) so we can wait for it later
922 spawn_process(const char *cmdline)
928 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
929 * ... does anyone still care about systems where that doesn't work?
939 fprintf(stderr, _("%s: could not fork: %s\n"),
940 progname, strerror(errno));
948 * Instead of using system(), exec the shell directly, and tell it to
949 * "exec" the command too. This saves two useless processes per
950 * parallel test case.
952 char *cmdline2 = malloc(strlen(cmdline) + 6);
954 sprintf(cmdline2, "exec %s", cmdline);
955 execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
956 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
957 progname, shellprog, strerror(errno));
958 exit(1); /* not exit_nicely here... */
966 PROCESS_INFORMATION pi;
968 HANDLE restrictedToken;
969 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
970 SID_AND_ATTRIBUTES dropSids[2];
971 __CreateRestrictedToken _CreateRestrictedToken = NULL;
972 HANDLE Advapi32Handle;
974 ZeroMemory(&si, sizeof(si));
977 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
978 if (Advapi32Handle != NULL)
980 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
983 if (_CreateRestrictedToken == NULL)
985 if (Advapi32Handle != NULL)
986 FreeLibrary(Advapi32Handle);
987 fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
992 /* Open the current token to use as base for the restricted one */
993 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
995 fprintf(stderr, _("could not open process token: %lu\n"),
1000 /* Allocate list of SIDs to remove */
1001 ZeroMemory(&dropSids, sizeof(dropSids));
1002 if (!AllocateAndInitializeSid(&NtAuthority, 2,
1003 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
1004 !AllocateAndInitializeSid(&NtAuthority, 2,
1005 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
1007 fprintf(stderr, _("could not allocate SIDs: %lu\n"), GetLastError());
1011 b = _CreateRestrictedToken(origToken,
1012 DISABLE_MAX_PRIVILEGE,
1013 sizeof(dropSids) / sizeof(dropSids[0]),
1019 FreeSid(dropSids[1].Sid);
1020 FreeSid(dropSids[0].Sid);
1021 CloseHandle(origToken);
1022 FreeLibrary(Advapi32Handle);
1026 fprintf(stderr, _("could not create restricted token: %lu\n"),
1031 cmdline2 = malloc(strlen(cmdline) + 8);
1032 sprintf(cmdline2, "cmd /c %s", cmdline);
1035 AddUserToTokenDacl(restrictedToken);
1038 if (!CreateProcessAsUser(restrictedToken,
1050 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
1051 cmdline2, GetLastError());
1057 ResumeThread(pi.hThread);
1058 CloseHandle(pi.hThread);
1064 * Count bytes in file
1067 file_size(const char *file)
1070 FILE *f = fopen(file, "r");
1074 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1075 progname, file, strerror(errno));
1078 fseek(f, 0, SEEK_END);
1085 * Count lines in file
1088 file_line_count(const char *file)
1092 FILE *f = fopen(file, "r");
1096 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1097 progname, file, strerror(errno));
1100 while ((c = fgetc(f)) != EOF)
1110 file_exists(const char *file)
1112 FILE *f = fopen(file, "r");
1121 directory_exists(const char *dir)
1125 if (stat(dir, &st) != 0)
1127 if (S_ISDIR(st.st_mode))
1132 /* Create a directory */
1134 make_directory(const char *dir)
1136 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1138 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1139 progname, dir, strerror(errno));
1145 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1148 get_alternative_expectfile(const char *expectfile, int i)
1151 int ssize = strlen(expectfile) + 2 + 1;
1152 char *tmp = (char *) malloc(ssize);
1153 char *s = (char *) malloc(ssize);
1155 strcpy(tmp, expectfile);
1156 last_dot = strrchr(tmp, '.');
1164 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1170 * Run a "diff" command and also check that it didn't crash
1173 run_diff(const char *cmd, const char *filename)
1178 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1180 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1186 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1187 * but produces nothing to stdout, so we check for that here.
1189 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1191 fprintf(stderr, _("diff command not found: %s\n"), cmd);
1196 return WEXITSTATUS(r);
1200 * Check the actual result file for the given test against expected results
1202 * Returns true if different (failure), false if correct match found.
1203 * In the true case, the diff is appended to the diffs file.
1206 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1208 char expectfile[MAXPGPATH];
1209 char diff[MAXPGPATH];
1210 char cmd[MAXPGPATH * 3];
1211 char best_expect_file[MAXPGPATH];
1213 int best_line_count;
1216 const char *platform_expectfile;
1219 * We can pass either the resultsfile or the expectfile, they should have
1220 * the same type (filename.type) anyway.
1222 platform_expectfile = get_expectfile(testname, resultsfile);
1224 strcpy(expectfile, default_expectfile);
1225 if (platform_expectfile)
1228 * Replace everything afer the last slash in expectfile with what the
1229 * platform_expectfile contains.
1231 char *p = strrchr(expectfile, '/');
1234 strcpy(++p, platform_expectfile);
1237 /* Name to use for temporary diff file */
1238 snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1240 /* OK, run the diff */
1241 snprintf(cmd, sizeof(cmd),
1242 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1243 basic_diff_opts, expectfile, resultsfile, diff);
1245 /* Is the diff file empty? */
1246 if (run_diff(cmd, diff) == 0)
1252 /* There may be secondary comparison files that match better */
1253 best_line_count = file_line_count(diff);
1254 strcpy(best_expect_file, expectfile);
1256 for (i = 0; i <= 9; i++)
1258 char *alt_expectfile;
1260 alt_expectfile = get_alternative_expectfile(expectfile, i);
1261 if (!file_exists(alt_expectfile))
1264 snprintf(cmd, sizeof(cmd),
1265 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1266 basic_diff_opts, alt_expectfile, resultsfile, diff);
1268 if (run_diff(cmd, diff) == 0)
1274 l = file_line_count(diff);
1275 if (l < best_line_count)
1277 /* This diff was a better match than the last one */
1278 best_line_count = l;
1279 strcpy(best_expect_file, alt_expectfile);
1281 free(alt_expectfile);
1285 * fall back on the canonical results file if we haven't tried it yet and
1286 * haven't found a complete match yet.
1289 if (platform_expectfile)
1291 snprintf(cmd, sizeof(cmd),
1292 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1293 basic_diff_opts, default_expectfile, resultsfile, diff);
1295 if (run_diff(cmd, diff) == 0)
1297 /* No diff = no changes = good */
1302 l = file_line_count(diff);
1303 if (l < best_line_count)
1305 /* This diff was a better match than the last one */
1306 best_line_count = l;
1307 strcpy(best_expect_file, default_expectfile);
1312 * Use the best comparison file to generate the "pretty" diff, which we
1313 * append to the diffs summary file.
1315 snprintf(cmd, sizeof(cmd),
1316 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
1317 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1318 run_diff(cmd, difffilename);
1320 /* And append a separator */
1321 difffile = fopen(difffilename, "a");
1325 "\n======================================================================\n\n");
1334 * Wait for specified subprocesses to finish, and return their exit
1335 * statuses into statuses[]
1337 * If names isn't NULL, print each subprocess's name as it finishes
1339 * Note: it's OK to scribble on the pids array, but not on the names array
1342 wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
1348 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1350 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1353 tests_left = num_tests;
1354 while (tests_left > 0)
1361 p = wait(&exit_status);
1363 if (p == INVALID_PID)
1365 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1373 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1374 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1376 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
1380 p = active_pids[r - WAIT_OBJECT_0];
1381 /* compact the active_pids array */
1382 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1385 for (i = 0; i < num_tests; i++)
1390 GetExitCodeProcess(pids[i], &exit_status);
1391 CloseHandle(pids[i]);
1393 pids[i] = INVALID_PID;
1394 statuses[i] = (int) exit_status;
1396 status(" %s", names[i]);
1409 * report nonzero exit code from a test process
1412 log_child_failure(int exitstatus)
1414 if (WIFEXITED(exitstatus))
1415 status(_(" (test process exited with exit code %d)"),
1416 WEXITSTATUS(exitstatus));
1417 else if (WIFSIGNALED(exitstatus))
1420 status(_(" (test process was terminated by exception 0x%X)"),
1421 WTERMSIG(exitstatus));
1422 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1423 status(_(" (test process was terminated by signal %d: %s)"),
1424 WTERMSIG(exitstatus),
1425 WTERMSIG(exitstatus) < NSIG ?
1426 sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
1428 status(_(" (test process was terminated by signal %d)"),
1429 WTERMSIG(exitstatus));
1433 status(_(" (test process exited with unrecognized status %d)"),
1438 * Run all the tests specified in one schedule file
1441 run_schedule(const char *schedule, test_function tfunc)
1443 #define MAX_PARALLEL_TESTS 100
1444 char *tests[MAX_PARALLEL_TESTS];
1445 _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1446 _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1447 _stringlist *tags[MAX_PARALLEL_TESTS];
1448 PID_TYPE pids[MAX_PARALLEL_TESTS];
1449 int statuses[MAX_PARALLEL_TESTS];
1450 _stringlist *ignorelist = NULL;
1455 memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1456 memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1457 memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1459 scf = fopen(schedule, "r");
1462 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1463 progname, schedule, strerror(errno));
1467 while (fgets(scbuf, sizeof(scbuf), scf))
1477 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1479 if (resultfiles[i] == NULL)
1481 free_stringlist(&resultfiles[i]);
1482 free_stringlist(&expectfiles[i]);
1483 free_stringlist(&tags[i]);
1486 /* strip trailing whitespace, especially the newline */
1488 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1491 if (scbuf[0] == '\0' || scbuf[0] == '#')
1493 if (strncmp(scbuf, "test: ", 6) == 0)
1495 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1498 while (*c && isspace((unsigned char) *c))
1500 add_stringlist_item(&ignorelist, c);
1503 * Note: ignore: lines do not run the test, they just say that
1504 * failure of this test when run later on is to be ignored. A bit
1505 * odd but that's how the shell-script version did it.
1511 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1512 schedule, line_num, scbuf);
1518 for (c = test; *c; c++)
1520 if (isspace((unsigned char) *c))
1527 if (num_tests >= MAX_PARALLEL_TESTS)
1529 /* can't print scbuf here, it's already been trashed */
1530 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1531 schedule, line_num);
1534 tests[num_tests] = c;
1542 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1543 schedule, line_num, scbuf);
1549 status(_("test %-24s ... "), tests[0]);
1550 pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1551 wait_for_tests(pids, statuses, NULL, 1);
1552 /* status line is finished below */
1554 else if (max_connections > 0 && max_connections < num_tests)
1558 status(_("parallel group (%d tests, in groups of %d): "),
1559 num_tests, max_connections);
1560 for (i = 0; i < num_tests; i++)
1562 if (i - oldest >= max_connections)
1564 wait_for_tests(pids + oldest, statuses + oldest,
1565 tests + oldest, i - oldest);
1568 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1570 wait_for_tests(pids + oldest, statuses + oldest,
1571 tests + oldest, i - oldest);
1576 status(_("parallel group (%d tests): "), num_tests);
1577 for (i = 0; i < num_tests; i++)
1579 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1581 wait_for_tests(pids, statuses, tests, num_tests);
1585 /* Check results for all tests */
1586 for (i = 0; i < num_tests; i++)
1591 bool differ = false;
1594 status(_(" %-24s ... "), tests[i]);
1597 * Advance over all three lists simultaneously.
1599 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1600 * optional but if there are tags, the tag list has the same
1601 * length as the other two lists.
1603 for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1604 rl != NULL; /* rl and el have the same length */
1605 rl = rl->next, el = el->next)
1610 tl = tl->next; /* tl has the same length as rl and el
1613 newdiff = results_differ(tests[i], rl->str, el->str);
1616 printf("%s ", tl->str);
1623 bool ignore = false;
1626 for (sl = ignorelist; sl != NULL; sl = sl->next)
1628 if (strcmp(tests[i], sl->str) == 0)
1636 status(_("failed (ignored)"));
1637 fail_ignore_count++;
1641 status(_("FAILED"));
1651 if (statuses[i] != 0)
1652 log_child_failure(statuses[i]);
1665 run_single_test(const char *test, test_function tfunc)
1669 _stringlist *resultfiles = NULL;
1670 _stringlist *expectfiles = NULL;
1671 _stringlist *tags = NULL;
1675 bool differ = false;
1677 status(_("test %-20s ... "), test);
1678 pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
1679 wait_for_tests(&pid, &exit_status, NULL, 1);
1682 * Advance over all three lists simultaneously.
1684 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1685 * but if there are tags, the tag list has the same length as the other
1688 for (rl = resultfiles, el = expectfiles, tl = tags;
1689 rl != NULL; /* rl and el have the same length */
1690 rl = rl->next, el = el->next)
1695 tl = tl->next; /* tl has the same length as rl and el if it
1698 newdiff = results_differ(test, rl->str, el->str);
1701 printf("%s ", tl->str);
1708 status(_("FAILED"));
1717 if (exit_status != 0)
1718 log_child_failure(exit_status);
1724 * Create the summary-output files (making them empty if already existing)
1727 open_result_files(void)
1729 char file[MAXPGPATH];
1732 /* create the log file (copy of running status output) */
1733 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1734 logfilename = strdup(file);
1735 logfile = fopen(logfilename, "w");
1738 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1739 progname, logfilename, strerror(errno));
1743 /* create the diffs file as empty */
1744 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1745 difffilename = strdup(file);
1746 difffile = fopen(difffilename, "w");
1749 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1750 progname, difffilename, strerror(errno));
1753 /* we don't keep the diffs file open continuously */
1756 /* also create the output directory if not present */
1757 snprintf(file, sizeof(file), "%s/results", outputdir);
1758 if (!directory_exists(file))
1759 make_directory(file);
1763 drop_database_if_exists(const char *dbname)
1765 header(_("dropping database \"%s\""), dbname);
1766 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1770 create_database(const char *dbname)
1775 * We use template0 so that any installation-local cruft in template1 will
1776 * not mess up the tests.
1778 header(_("creating database \"%s\""), dbname);
1780 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
1781 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1783 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
1784 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1785 psql_command(dbname,
1786 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1787 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1788 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1789 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1790 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1791 dbname, dbname, dbname, dbname, dbname);
1794 * Install any requested procedural languages. We use CREATE OR REPLACE
1795 * so that this will work whether or not the language is preinstalled.
1797 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1799 header(_("installing %s"), sl->str);
1800 psql_command(dbname, "CREATE OR REPLACE LANGUAGE \"%s\"", sl->str);
1805 drop_role_if_exists(const char *rolename)
1807 header(_("dropping role \"%s\""), rolename);
1808 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1812 create_role(const char *rolename, const _stringlist * granted_dbs)
1814 header(_("creating role \"%s\""), rolename);
1815 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
1816 for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
1818 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1819 granted_dbs->str, rolename);
1824 make_absolute_path(const char *in)
1828 if (is_absolute_path(in))
1829 result = strdup(in);
1832 static char cwdbuf[MAXPGPATH];
1836 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1838 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1843 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1844 sprintf(result, "%s/%s", cwdbuf, in);
1847 canonicalize_path(result);
1854 printf(_("PostgreSQL regression test driver\n"));
1856 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1858 printf(_("Options:\n"));
1859 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1860 printf(_(" --debug turn on debug mode in programs that are run\n"));
1861 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1862 printf(_(" --load-language=lang load the named language before running the\n"));
1863 printf(_(" tests; can appear multiple times\n"));
1864 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1865 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1866 printf(_(" (default is 0 meaning unlimited)\n"));
1867 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1868 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1869 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1870 printf(_(" (can be used multiple times to concatenate)\n"));
1871 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1872 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1874 printf(_("Options for \"temp-install\" mode:\n"));
1875 printf(_(" --no-locale use C locale\n"));
1876 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1877 printf(_(" --port=PORT start postmaster on PORT\n"));
1878 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1880 printf(_("Options for using an existing installation:\n"));
1881 printf(_(" --host=HOST use postmaster running on HOST\n"));
1882 printf(_(" --port=PORT use postmaster running at PORT\n"));
1883 printf(_(" --user=USER connect as USER\n"));
1884 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1886 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1887 printf(_("if the tests could not be run for some reason.\n"));
1889 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1893 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1899 char buf[MAXPGPATH * 4];
1900 char buf2[MAXPGPATH * 4];
1902 static struct option long_options[] = {
1903 {"help", no_argument, NULL, 'h'},
1904 {"version", no_argument, NULL, 'V'},
1905 {"dbname", required_argument, NULL, 1},
1906 {"debug", no_argument, NULL, 2},
1907 {"inputdir", required_argument, NULL, 3},
1908 {"load-language", required_argument, NULL, 4},
1909 {"max-connections", required_argument, NULL, 5},
1910 {"multibyte", required_argument, NULL, 6},
1911 {"outputdir", required_argument, NULL, 7},
1912 {"schedule", required_argument, NULL, 8},
1913 {"temp-install", required_argument, NULL, 9},
1914 {"no-locale", no_argument, NULL, 10},
1915 {"top-builddir", required_argument, NULL, 11},
1916 {"host", required_argument, NULL, 13},
1917 {"port", required_argument, NULL, 14},
1918 {"user", required_argument, NULL, 15},
1919 {"psqldir", required_argument, NULL, 16},
1920 {"dlpath", required_argument, NULL, 17},
1921 {"create-role", required_argument, NULL, 18},
1922 {"temp-config", required_argument, NULL, 19},
1923 {"use-existing", no_argument, NULL, 20},
1927 progname = get_progname(argv[0]);
1928 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
1930 #ifndef HAVE_UNIX_SOCKETS
1931 /* no unix domain sockets available, so change default */
1932 hostname = "localhost";
1936 * We call the initialization function here because that way we can set
1937 * default parameters and let them be overwritten by the commandline.
1941 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1949 puts("pg_regress (PostgreSQL) " PG_VERSION);
1954 * If a default database was specified, we need to remove it
1955 * before we add the specified one.
1957 free_stringlist(&dblist);
1958 split_to_stringlist(strdup(optarg), ", ", &dblist);
1964 inputdir = strdup(optarg);
1967 add_stringlist_item(&loadlanguage, optarg);
1970 max_connections = atoi(optarg);
1973 encoding = strdup(optarg);
1976 outputdir = strdup(optarg);
1979 add_stringlist_item(&schedulelist, optarg);
1982 temp_install = make_absolute_path(optarg);
1988 top_builddir = strdup(optarg);
1991 hostname = strdup(optarg);
1994 port = atoi(optarg);
1995 port_specified_by_user = true;
1998 user = strdup(optarg);
2001 /* "--psqldir=" should mean to use PATH */
2003 psqldir = strdup(optarg);
2006 dlpath = strdup(optarg);
2009 split_to_stringlist(strdup(optarg), ", ", &extraroles);
2012 temp_config = strdup(optarg);
2015 use_existing = true;
2018 /* getopt_long already emitted a complaint */
2019 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2026 * if we still have arguments, they are extra tests to run
2028 while (argc - optind >= 1)
2030 add_stringlist_item(&extra_tests, argv[optind]);
2034 if (temp_install && !port_specified_by_user)
2037 * To reduce chances of interference with parallel installations, use
2038 * a port number starting in the private range (49152-65535)
2039 * calculated from the version number.
2041 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2043 inputdir = make_absolute_path(inputdir);
2044 outputdir = make_absolute_path(outputdir);
2045 dlpath = make_absolute_path(dlpath);
2050 open_result_files();
2052 initialize_environment();
2054 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2055 unlimit_core_size();
2063 * Prepare the temp installation
2067 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2071 if (directory_exists(temp_install))
2073 header(_("removing existing temp installation"));
2074 rmtree(temp_install, true);
2077 header(_("creating temporary installation"));
2079 /* make the temp install top directory */
2080 make_directory(temp_install);
2082 /* and a directory for log files */
2083 snprintf(buf, sizeof(buf), "%s/log", outputdir);
2084 if (!directory_exists(buf))
2085 make_directory(buf);
2087 /* "make install" */
2088 #ifndef WIN32_ONLY_COMPILER
2089 snprintf(buf, sizeof(buf),
2090 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2091 makeprog, top_builddir, temp_install, outputdir);
2093 snprintf(buf, sizeof(buf),
2094 SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2095 top_builddir, temp_install, outputdir);
2099 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2104 header(_("initializing database system"));
2105 snprintf(buf, sizeof(buf),
2106 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
2107 bindir, temp_install, datadir,
2108 debug ? " --debug" : "",
2109 nolocale ? " --no-locale" : "",
2113 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2118 * Adjust the default postgresql.conf as needed for regression
2119 * testing. The user can specify a file to be appended; in any case we
2120 * set max_prepared_transactions to enable testing of prepared xacts.
2121 * (Note: to reduce the probability of unexpected shmmax failures,
2122 * don't set max_prepared_transactions any higher than actually needed
2123 * by the prepared_xacts regression test.)
2125 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
2126 pg_conf = fopen(buf, "a");
2127 if (pg_conf == NULL)
2129 fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2132 fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2133 fputs("max_prepared_transactions = 2\n", pg_conf);
2135 if (temp_config != NULL)
2138 char line_buf[1024];
2140 extra_conf = fopen(temp_config, "r");
2141 if (extra_conf == NULL)
2143 fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2146 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2147 fputs(line_buf, pg_conf);
2154 * Check if there is a postmaster running already.
2156 snprintf(buf2, sizeof(buf2),
2157 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
2158 bindir, DEVNULL, DEVNULL);
2160 for (i = 0; i < 16; i++)
2162 if (system(buf2) == 0)
2166 if (port_specified_by_user || i == 15)
2168 fprintf(stderr, _("port %d apparently in use\n"), port);
2169 if (!port_specified_by_user)
2170 fprintf(stderr, _("%s: could not determine an available port\n"), progname);
2171 fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2175 fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2177 sprintf(s, "%d", port);
2178 doputenv("PGPORT", s);
2185 * Start the temp postmaster
2187 header(_("starting postmaster"));
2188 snprintf(buf, sizeof(buf),
2189 SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
2190 bindir, temp_install,
2191 debug ? " -d 5" : "",
2192 hostname ? hostname : "",
2194 postmaster_pid = spawn_process(buf);
2195 if (postmaster_pid == INVALID_PID)
2197 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2198 progname, strerror(errno));
2203 * Wait till postmaster is able to accept connections (normally only a
2204 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2207 for (i = 0; i < 60; i++)
2209 /* Done if psql succeeds */
2210 if (system(buf2) == 0)
2214 * Fail immediately if postmaster has exited
2217 if (kill(postmaster_pid, 0) != 0)
2219 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2222 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2226 pg_usleep(1000000L);
2230 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2233 * If we get here, the postmaster is probably wedged somewhere in
2234 * startup. Try to kill it ungracefully rather than leaving a
2235 * stuck postmaster that might interfere with subsequent test
2239 if (kill(postmaster_pid, SIGKILL) != 0 &&
2241 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2242 progname, strerror(errno));
2244 if (TerminateProcess(postmaster_pid, 255) == 0)
2245 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
2246 progname, GetLastError());
2252 postmaster_running = true;
2254 printf(_("running on port %d with pid %lu\n"),
2255 port, (unsigned long) postmaster_pid);
2260 * Using an existing installation, so may need to get rid of
2261 * pre-existing database(s) and role(s)
2265 for (sl = dblist; sl; sl = sl->next)
2266 drop_database_if_exists(sl->str);
2267 for (sl = extraroles; sl; sl = sl->next)
2268 drop_role_if_exists(sl->str);
2273 * Create the test database(s) and role(s)
2277 for (sl = dblist; sl; sl = sl->next)
2278 create_database(sl->str);
2279 for (sl = extraroles; sl; sl = sl->next)
2280 create_role(sl->str, dblist);
2284 * Ready to run the tests
2286 header(_("running regression test queries"));
2288 for (sl = schedulelist; sl != NULL; sl = sl->next)
2290 run_schedule(sl->str, tfunc);
2293 for (sl = extra_tests; sl != NULL; sl = sl->next)
2295 run_single_test(sl->str, tfunc);
2299 * Shut down temp installation's postmaster
2303 header(_("shutting down postmaster"));
2310 * Emit nice-looking summary message
2312 if (fail_count == 0 && fail_ignore_count == 0)
2313 snprintf(buf, sizeof(buf),
2314 _(" All %d tests passed. "),
2316 else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2317 snprintf(buf, sizeof(buf),
2318 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2320 success_count + fail_ignore_count,
2322 else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2323 snprintf(buf, sizeof(buf),
2324 _(" %d of %d tests failed. "),
2326 success_count + fail_count);
2328 /* fail_count>0 && fail_ignore_count>0 */
2329 snprintf(buf, sizeof(buf),
2330 _(" %d of %d tests failed, %d of these failures ignored. "),
2331 fail_count + fail_ignore_count,
2332 success_count + fail_count + fail_ignore_count,
2336 for (i = strlen(buf); i > 0; i--)
2338 printf("\n%s\n", buf);
2339 for (i = strlen(buf); i > 0; i--)
2344 if (file_size(difffilename) > 0)
2346 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2347 "file \"%s\". A copy of the test summary that you see\n"
2348 "above is saved in the file \"%s\".\n\n"),
2349 difffilename, logfilename);
2353 unlink(difffilename);
2354 unlink(logfilename);
2357 if (fail_count != 0)