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-2008, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
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
;
68 /* currently we can use the same diff switches on all platforms */
69 const char *basic_diff_opts
= "-w";
70 const char *pretty_diff_opts
= "-w -C3";
72 /* options settable from command line */
73 _stringlist
*dblist
= NULL
;
76 char *outputdir
= ".";
77 char *psqldir
= PGBINDIR
;
78 static _stringlist
*loadlanguage
= NULL
;
79 static int max_connections
= 0;
80 static char *encoding
= NULL
;
81 static _stringlist
*schedulelist
= NULL
;
82 static _stringlist
*extra_tests
= NULL
;
83 static char *temp_install
= NULL
;
84 static char *temp_config
= NULL
;
85 static char *top_builddir
= NULL
;
86 static int temp_port
= 65432;
87 static bool nolocale
= false;
88 static char *hostname
= NULL
;
90 static char *dlpath
= PKGLIBDIR
;
91 static char *user
= NULL
;
92 static _stringlist
*extraroles
= NULL
;
94 /* internal variables */
95 static const char *progname
;
96 static char *logfilename
;
98 static char *difffilename
;
100 static _resultmap
*resultmap
= NULL
;
102 static PID_TYPE postmaster_pid
= INVALID_PID
;
103 static bool postmaster_running
= false;
105 static int success_count
= 0;
106 static int fail_count
= 0;
107 static int fail_ignore_count
= 0;
109 static bool directory_exists(const char *dir
);
110 static void make_directory(const char *dir
);
113 header(const char *fmt
,...)
114 /* This extension allows gcc to check the format string for consistency with
115 the supplied arguments. */
116 __attribute__((format(printf
, 1, 2)));
118 status(const char *fmt
,...)
119 /* This extension allows gcc to check the format string for consistency with
120 the supplied arguments. */
121 __attribute__((format(printf
, 1, 2)));
123 psql_command(const char *database
, const char *query
,...)
124 /* This extension allows gcc to check the format string for consistency with
125 the supplied arguments. */
126 __attribute__((format(printf
, 2, 3)));
129 typedef BOOL(WINAPI
* __CreateRestrictedToken
) (HANDLE
, DWORD
, DWORD
, PSID_AND_ATTRIBUTES
, DWORD
, PLUID_AND_ATTRIBUTES
, DWORD
, PSID_AND_ATTRIBUTES
, PHANDLE
);
131 /* Windows API define missing from MingW headers */
132 #define DISABLE_MAX_PRIVILEGE 0x1
136 * allow core files if possible.
138 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
140 unlimit_core_size(void)
144 getrlimit(RLIMIT_CORE
, &lim
);
145 if (lim
.rlim_max
== 0)
148 _("%s: could not set core size: disallowed by hard limit\n"),
152 else if (lim
.rlim_max
== RLIM_INFINITY
|| lim
.rlim_cur
< lim
.rlim_max
)
154 lim
.rlim_cur
= lim
.rlim_max
;
155 setrlimit(RLIMIT_CORE
, &lim
);
162 * Add an item at the end of a stringlist.
165 add_stringlist_item(_stringlist
** listhead
, const char *str
)
167 _stringlist
*newentry
= malloc(sizeof(_stringlist
));
168 _stringlist
*oldentry
;
170 newentry
->str
= strdup(str
);
171 newentry
->next
= NULL
;
172 if (*listhead
== NULL
)
173 *listhead
= newentry
;
176 for (oldentry
= *listhead
; oldentry
->next
; oldentry
= oldentry
->next
)
178 oldentry
->next
= newentry
;
186 free_stringlist(_stringlist
** listhead
)
188 if (listhead
== NULL
|| *listhead
== NULL
)
190 if ((*listhead
)->next
!= NULL
)
191 free_stringlist(&((*listhead
)->next
));
192 free((*listhead
)->str
);
198 * Split a delimited string into a stringlist
201 split_to_stringlist(const char *s
, const char *delim
, _stringlist
** listhead
)
203 char *sc
= strdup(s
);
204 char *token
= strtok(sc
, delim
);
208 add_stringlist_item(listhead
, token
);
209 token
= strtok(NULL
, delim
);
215 * Print a progress banner on stdout.
218 header(const char *fmt
,...)
224 vsnprintf(tmp
, sizeof(tmp
), fmt
, ap
);
227 fprintf(stdout
, "============== %-38s ==============\n", tmp
);
232 * Print "doing something ..." --- supplied text should not end with newline
235 status(const char *fmt
,...)
240 vfprintf(stdout
, fmt
, ap
);
247 vfprintf(logfile
, fmt
, ap
);
253 * Done "doing something ..."
258 fprintf(stdout
, "\n");
261 fprintf(logfile
, "\n");
265 * shut down temp postmaster
268 stop_postmaster(void)
270 if (postmaster_running
)
272 /* We use pg_ctl to issue the kill and wait for stop */
273 char buf
[MAXPGPATH
* 2];
275 /* On Windows, system() seems not to force fflush, so... */
279 snprintf(buf
, sizeof(buf
),
280 SYSTEMQUOTE
"\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE
,
281 bindir
, temp_install
);
282 system(buf
); /* ignore exit status */
283 postmaster_running
= false;
288 * Always exit through here, not through plain exit(), to ensure we make
289 * an effort to shut down a temp postmaster
292 exit_nicely(int code
)
299 * Check whether string matches pattern
301 * In the original shell script, this function was implemented using expr(1),
302 * which provides basic regular expressions restricted to match starting at
303 * the string start (in conventional regex terms, there's an implicit "^"
304 * at the start of the pattern --- but no implicit "$" at the end).
306 * For now, we only support "." and ".*" as non-literal metacharacters,
307 * because that's all that anyone has found use for in resultmap. This
308 * code could be extended if more functionality is needed.
311 string_matches_pattern(const char *str
, const char *pattern
)
313 while (*str
&& *pattern
)
315 if (*pattern
== '.' && pattern
[1] == '*')
318 /* Trailing .* matches everything. */
319 if (*pattern
== '\0')
323 * Otherwise, scan for a text position at which we can match the
324 * rest of the pattern.
329 * Optimization to prevent most recursion: don't recurse
330 * unless first pattern char might match this text char.
332 if (*str
== *pattern
|| *pattern
== '.')
334 if (string_matches_pattern(str
, pattern
))
342 * End of text with no match.
346 else if (*pattern
!= '.' && *str
!= *pattern
)
349 * Not the single-character wildcard and no explicit match? Then
359 if (*pattern
== '\0')
360 return true; /* end of pattern, so declare match */
362 /* End of input string. Do we have matching pattern remaining? */
363 while (*pattern
== '.' && pattern
[1] == '*')
365 if (*pattern
== '\0')
366 return true; /* end of pattern, so declare match */
372 * Replace all occurances of a string in a string with a different string.
373 * NOTE: Assumes there is enough room in the target buffer!
376 replace_string(char *string
, char *replace
, char *replacement
)
380 while ((ptr
= strstr(string
, replace
)) != NULL
)
382 char *dup
= strdup(string
);
384 strlcpy(string
, dup
, ptr
- string
+ 1);
385 strcat(string
, replacement
);
386 strcat(string
, dup
+ (ptr
- string
) + strlen(replace
));
392 * Convert *.source found in the "source" directory, replacing certain tokens
393 * in the file contents with their intended values, and put the resulting files
394 * in the "dest" directory, replacing the ".source" prefix in their names with
398 convert_sourcefiles_in(char *source_subdir
, char *dest_subdir
, char *suffix
)
400 char testtablespace
[MAXPGPATH
];
401 char indir
[MAXPGPATH
];
408 snprintf(indir
, MAXPGPATH
, "%s/%s", inputdir
, source_subdir
);
410 /* Check that indir actually exists and is a directory */
411 ret
= stat(indir
, &st
);
412 if (ret
!= 0 || !S_ISDIR(st
.st_mode
))
415 * No warning, to avoid noise in tests that do not have
416 * these directories; for example, ecpg, contrib and src/pl.
421 names
= pgfnames(indir
);
423 /* Error logged in pgfnames */
426 snprintf(testtablespace
, MAXPGPATH
, "%s/testtablespace", outputdir
);
430 * On Windows only, clean out the test tablespace dir, or create it if it
431 * doesn't exist. On other platforms we expect the Makefile to take
432 * care of that. (We don't migrate that functionality in here because
433 * it'd be harder to cope with platform-specific issues such as SELinux.)
435 * XXX it would be better if pg_regress.c had nothing at all to do with
436 * testtablespace, and this were handled by a .BAT file or similar on
437 * Windows. See pgsql-hackers discussion of 2008-01-18.
439 if (directory_exists(testtablespace
))
440 rmtree(testtablespace
, true);
441 make_directory(testtablespace
);
444 /* finally loop on each file and do the replacement */
445 for (name
= names
; *name
; name
++)
447 char srcfile
[MAXPGPATH
];
448 char destfile
[MAXPGPATH
];
449 char prefix
[MAXPGPATH
];
454 /* reject filenames not finishing in ".source" */
455 if (strlen(*name
) < 8)
457 if (strcmp(*name
+ strlen(*name
) - 7, ".source") != 0)
462 /* build the full actual paths to open */
463 snprintf(prefix
, strlen(*name
) - 6, "%s", *name
);
464 snprintf(srcfile
, MAXPGPATH
, "%s/%s", indir
, *name
);
465 snprintf(destfile
, MAXPGPATH
, "%s/%s.%s", dest_subdir
, prefix
, suffix
);
467 infile
= fopen(srcfile
, "r");
470 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
471 progname
, srcfile
, strerror(errno
));
474 outfile
= fopen(destfile
, "w");
477 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
478 progname
, destfile
, strerror(errno
));
481 while (fgets(line
, sizeof(line
), infile
))
483 replace_string(line
, "@abs_srcdir@", inputdir
);
484 replace_string(line
, "@abs_builddir@", outputdir
);
485 replace_string(line
, "@testtablespace@", testtablespace
);
486 replace_string(line
, "@libdir@", dlpath
);
487 replace_string(line
, "@DLSUFFIX@", DLSUFFIX
);
488 fputs(line
, outfile
);
495 * If we didn't process any files, complain because it probably means
496 * somebody neglected to pass the needed --inputdir argument.
500 fprintf(stderr
, _("%s: no *.source files found in \"%s\"\n"),
505 pgfnames_cleanup(names
);
508 /* Create the .sql and .out files from the .source files, if any */
510 convert_sourcefiles(void)
512 convert_sourcefiles_in("input", "sql", "sql");
513 convert_sourcefiles_in("output", "expected", "out");
517 * Scan resultmap file to find which platform-specific expected files to use.
519 * The format of each line of the file is
520 * testname/hostplatformpattern=substitutefile
521 * where the hostplatformpattern is evaluated per the rules of expr(1),
522 * namely, it is a standard regular expression with an implicit ^ at the start.
523 * (We currently support only a very limited subset of regular expressions,
524 * see string_matches_pattern() above.) What hostplatformpattern will be
525 * matched against is the config.guess output. (In the shell-script version,
526 * we also provided an indication of whether gcc or another compiler was in
527 * use, but that facility isn't used anymore.)
535 /* scan the file ... */
536 snprintf(buf
, sizeof(buf
), "%s/resultmap", inputdir
);
540 /* OK if it doesn't exist, else complain */
543 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
544 progname
, buf
, strerror(errno
));
548 while (fgets(buf
, sizeof(buf
), f
))
555 /* strip trailing whitespace, especially the newline */
557 while (i
> 0 && isspace((unsigned char) buf
[i
- 1]))
560 /* parse out the line fields */
561 file_type
= strchr(buf
, ':');
564 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
570 platform
= strchr(file_type
, ':');
573 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
578 expected
= strchr(platform
, '=');
581 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
588 * if it's for current platform, save it in resultmap list. Note: by
589 * adding at the front of the list, we ensure that in ambiguous cases,
590 * the last match in the resultmap file is used. This mimics the
591 * behavior of the old shell script.
593 if (string_matches_pattern(host_platform
, platform
))
595 _resultmap
*entry
= malloc(sizeof(_resultmap
));
597 entry
->test
= strdup(buf
);
598 entry
->type
= strdup(file_type
);
599 entry
->resultfile
= strdup(expected
);
600 entry
->next
= resultmap
;
608 * Check in resultmap if we should be looking at a different file
612 get_expectfile(const char *testname
, const char *file
)
618 * Determine the file type from the file name. This is just what is
619 * following the last dot in the file name.
621 if (!file
|| !(file_type
= strrchr(file
, '.')))
626 for (rm
= resultmap
; rm
!= NULL
; rm
= rm
->next
)
628 if (strcmp(testname
, rm
->test
) == 0 && strcmp(file_type
, rm
->type
) == 0)
630 return rm
->resultfile
;
638 * Handy subroutine for setting an environment variable "var" to "val"
641 doputenv(const char *var
, const char *val
)
643 char *s
= malloc(strlen(var
) + strlen(val
) + 2);
645 sprintf(s
, "%s=%s", var
, val
);
650 * Set the environment variable "pathname", prepending "addval" to its
651 * old value (if any).
654 add_to_path(const char *pathname
, char separator
, const char *addval
)
656 char *oldval
= getenv(pathname
);
659 if (!oldval
|| !oldval
[0])
661 /* no previous value */
662 newval
= malloc(strlen(pathname
) + strlen(addval
) + 2);
663 sprintf(newval
, "%s=%s", pathname
, addval
);
667 newval
= malloc(strlen(pathname
) + strlen(addval
) + strlen(oldval
) + 3);
668 sprintf(newval
, "%s=%s%c%s", pathname
, addval
, separator
, oldval
);
674 * Prepare environment variables for running regression tests
677 initialize_environment(void)
682 * Clear out any non-C locale settings
684 unsetenv("LC_COLLATE");
685 unsetenv("LC_CTYPE");
686 unsetenv("LC_MONETARY");
687 unsetenv("LC_MESSAGES");
688 unsetenv("LC_NUMERIC");
692 unsetenv("LANGUAGE");
693 /* On Windows the default locale cannot be English, so force it */
694 #if defined(WIN32) || defined(__CYGWIN__)
699 * Set multibyte as requested
702 doputenv("PGCLIENTENCODING", encoding
);
704 unsetenv("PGCLIENTENCODING");
707 * Set timezone and datestyle for datetime-related tests
709 putenv("PGTZ=PST8PDT");
710 putenv("PGDATESTYLE=Postgres, MDY");
715 * Clear out any environment vars that might cause psql to connect to
716 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
717 * we also use psql's -X switch consistently, so that ~/.psqlrc files
718 * won't mess things up.) Also, set PGPORT to the temp port, and set
719 * or unset PGHOST depending on whether we are using TCP or Unix
722 unsetenv("PGDATABASE");
724 unsetenv("PGSERVICE");
725 unsetenv("PGSSLMODE");
726 unsetenv("PGREQUIRESSL");
727 unsetenv("PGCONNECT_TIMEOUT");
729 if (hostname
!= NULL
)
730 doputenv("PGHOST", hostname
);
733 unsetenv("PGHOSTADDR");
738 sprintf(s
, "%d", port
);
739 doputenv("PGPORT", s
);
743 * Adjust path variables to point into the temp-install tree
745 tmp
= malloc(strlen(temp_install
) + 32 + strlen(bindir
));
746 sprintf(tmp
, "%s/install/%s", temp_install
, bindir
);
749 tmp
= malloc(strlen(temp_install
) + 32 + strlen(libdir
));
750 sprintf(tmp
, "%s/install/%s", temp_install
, libdir
);
753 tmp
= malloc(strlen(temp_install
) + 32 + strlen(datadir
));
754 sprintf(tmp
, "%s/install/%s", temp_install
, datadir
);
757 /* psql will be installed into temp-install bindir */
761 * Set up shared library paths to include the temp install.
763 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
764 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
765 * Windows needs shared libraries in PATH (only those linked into
766 * executables, not dlopen'ed ones). Feel free to account for others
769 add_to_path("LD_LIBRARY_PATH", ':', libdir
);
770 add_to_path("DYLD_LIBRARY_PATH", ':', libdir
);
771 add_to_path("LIBPATH", ':', libdir
);
772 #if defined(WIN32) || defined(__CYGWIN__)
773 add_to_path("PATH", ';', libdir
);
782 * When testing an existing install, we honor existing environment
783 * variables, except if they're overridden by command line options.
785 if (hostname
!= NULL
)
787 doputenv("PGHOST", hostname
);
788 unsetenv("PGHOSTADDR");
794 sprintf(s
, "%d", port
);
795 doputenv("PGPORT", s
);
798 doputenv("PGUSER", user
);
801 * Report what we're connecting to
803 pghost
= getenv("PGHOST");
804 pgport
= getenv("PGPORT");
805 #ifndef HAVE_UNIX_SOCKETS
807 pghost
= "localhost";
810 if (pghost
&& pgport
)
811 printf(_("(using postmaster on %s, port %s)\n"), pghost
, pgport
);
812 if (pghost
&& !pgport
)
813 printf(_("(using postmaster on %s, default port)\n"), pghost
);
814 if (!pghost
&& pgport
)
815 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport
);
816 if (!pghost
&& !pgport
)
817 printf(_("(using postmaster on Unix socket, default port)\n"));
820 convert_sourcefiles();
825 * Issue a command via psql, connecting to the specified database
827 * Since we use system(), this doesn't return until the operation finishes
830 psql_command(const char *database
, const char *query
,...)
832 char query_formatted
[1024];
833 char query_escaped
[2048];
834 char psql_cmd
[MAXPGPATH
+ 2048];
839 /* Generate the query with insertion of sprintf arguments */
840 va_start(args
, query
);
841 vsnprintf(query_formatted
, sizeof(query_formatted
), query
, args
);
844 /* Now escape any shell double-quote metacharacters */
846 for (s
= query_formatted
; *s
; s
++)
848 if (strchr("\\\"$`", *s
))
854 /* And now we can build and execute the shell command */
855 snprintf(psql_cmd
, sizeof(psql_cmd
),
856 SYSTEMQUOTE
"\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE
,
857 psqldir
? psqldir
: "",
862 if (system(psql_cmd
) != 0)
864 /* psql probably already reported the error */
865 fprintf(stderr
, _("command failed: %s\n"), psql_cmd
);
871 * Spawn a process to execute the given shell command; don't wait for it
873 * Returns the process ID (or HANDLE) so we can wait for it later
876 spawn_process(const char *cmdline
)
882 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
883 * ... does anyone still care about systems where that doesn't work?
893 fprintf(stderr
, _("%s: could not fork: %s\n"),
894 progname
, strerror(errno
));
902 * Instead of using system(), exec the shell directly, and tell it to
903 * "exec" the command too. This saves two useless processes per
904 * parallel test case.
906 char *cmdline2
= malloc(strlen(cmdline
) + 6);
908 sprintf(cmdline2
, "exec %s", cmdline
);
909 execl(shellprog
, shellprog
, "-c", cmdline2
, (char *) NULL
);
910 fprintf(stderr
, _("%s: could not exec \"%s\": %s\n"),
911 progname
, shellprog
, strerror(errno
));
912 exit(1); /* not exit_nicely here... */
920 PROCESS_INFORMATION pi
;
922 HANDLE restrictedToken
;
923 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
924 SID_AND_ATTRIBUTES dropSids
[2];
925 __CreateRestrictedToken _CreateRestrictedToken
= NULL
;
926 HANDLE Advapi32Handle
;
928 ZeroMemory(&si
, sizeof(si
));
931 Advapi32Handle
= LoadLibrary("ADVAPI32.DLL");
932 if (Advapi32Handle
!= NULL
)
934 _CreateRestrictedToken
= (__CreateRestrictedToken
) GetProcAddress(Advapi32Handle
, "CreateRestrictedToken");
937 if (_CreateRestrictedToken
== NULL
)
939 if (Advapi32Handle
!= NULL
)
940 FreeLibrary(Advapi32Handle
);
941 fprintf(stderr
, _("%s: cannot create restricted tokens on this platform\n"),
946 /* Open the current token to use as base for the restricted one */
947 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS
, &origToken
))
949 fprintf(stderr
, _("could not open process token: %lu\n"),
954 /* Allocate list of SIDs to remove */
955 ZeroMemory(&dropSids
, sizeof(dropSids
));
956 if (!AllocateAndInitializeSid(&NtAuthority
, 2,
957 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &dropSids
[0].Sid
) ||
958 !AllocateAndInitializeSid(&NtAuthority
, 2,
959 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_POWER_USERS
, 0, 0, 0, 0, 0, 0, &dropSids
[1].Sid
))
961 fprintf(stderr
, _("could not allocate SIDs: %lu\n"), GetLastError());
965 b
= _CreateRestrictedToken(origToken
,
966 DISABLE_MAX_PRIVILEGE
,
967 sizeof(dropSids
) / sizeof(dropSids
[0]),
973 FreeSid(dropSids
[1].Sid
);
974 FreeSid(dropSids
[0].Sid
);
975 CloseHandle(origToken
);
976 FreeLibrary(Advapi32Handle
);
980 fprintf(stderr
, _("could not create restricted token: %lu\n"),
985 cmdline2
= malloc(strlen(cmdline
) + 8);
986 sprintf(cmdline2
, "cmd /c %s", cmdline
);
988 if (!CreateProcessAsUser(restrictedToken
,
1000 fprintf(stderr
, _("could not start process for \"%s\": %lu\n"),
1001 cmdline2
, GetLastError());
1006 AddUserToDacl(pi
.hProcess
);
1011 ResumeThread(pi
.hThread
);
1012 CloseHandle(pi
.hThread
);
1018 * Count bytes in file
1021 file_size(const char *file
)
1024 FILE *f
= fopen(file
, "r");
1028 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
1029 progname
, file
, strerror(errno
));
1032 fseek(f
, 0, SEEK_END
);
1039 * Count lines in file
1042 file_line_count(const char *file
)
1046 FILE *f
= fopen(file
, "r");
1050 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
1051 progname
, file
, strerror(errno
));
1054 while ((c
= fgetc(f
)) != EOF
)
1064 file_exists(const char *file
)
1066 FILE *f
= fopen(file
, "r");
1075 directory_exists(const char *dir
)
1079 if (stat(dir
, &st
) != 0)
1081 if (S_ISDIR(st
.st_mode
))
1086 /* Create a directory */
1088 make_directory(const char *dir
)
1090 if (mkdir(dir
, S_IRWXU
| S_IRWXG
| S_IRWXO
) < 0)
1092 fprintf(stderr
, _("%s: could not create directory \"%s\": %s\n"),
1093 progname
, dir
, strerror(errno
));
1099 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1102 get_alternative_expectfile(const char *expectfile
, int i
)
1105 int ssize
= strlen(expectfile
) + 2 + 1;
1106 char *tmp
= (char *) malloc(ssize
);
1107 char *s
= (char *) malloc(ssize
);
1109 strcpy(tmp
, expectfile
);
1110 last_dot
= strrchr(tmp
, '.');
1114 snprintf(s
, ssize
, "%s_%d.%s", tmp
, i
, last_dot
+ 1);
1120 * Run a "diff" command and also check that it didn't crash
1123 run_diff(const char *cmd
, const char *filename
)
1128 if (!WIFEXITED(r
) || WEXITSTATUS(r
) > 1)
1130 fprintf(stderr
, _("diff command failed with status %d: %s\n"), r
, cmd
);
1136 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1137 * but produces nothing to stdout, so we check for that here.
1139 if (WEXITSTATUS(r
) == 1 && file_size(filename
) <= 0)
1141 fprintf(stderr
, _("diff command not found: %s\n"), cmd
);
1146 return WEXITSTATUS(r
);
1150 * Check the actual result file for the given test against expected results
1152 * Returns true if different (failure), false if correct match found.
1153 * In the true case, the diff is appended to the diffs file.
1156 results_differ(const char *testname
, const char *resultsfile
, const char *default_expectfile
)
1158 char expectfile
[MAXPGPATH
];
1159 char diff
[MAXPGPATH
];
1160 char cmd
[MAXPGPATH
* 3];
1161 char best_expect_file
[MAXPGPATH
];
1163 int best_line_count
;
1166 const char *platform_expectfile
;
1169 * We can pass either the resultsfile or the expectfile, they should have
1170 * the same type (filename.type) anyway.
1172 platform_expectfile
= get_expectfile(testname
, resultsfile
);
1174 strcpy(expectfile
, default_expectfile
);
1175 if (platform_expectfile
)
1178 * Replace everything afer the last slash in expectfile with what the
1179 * platform_expectfile contains.
1181 char *p
= strrchr(expectfile
, '/');
1184 strcpy(++p
, platform_expectfile
);
1187 /* Name to use for temporary diff file */
1188 snprintf(diff
, sizeof(diff
), "%s.diff", resultsfile
);
1190 /* OK, run the diff */
1191 snprintf(cmd
, sizeof(cmd
),
1192 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1193 basic_diff_opts
, expectfile
, resultsfile
, diff
);
1195 /* Is the diff file empty? */
1196 if (run_diff(cmd
, diff
) == 0)
1202 /* There may be secondary comparison files that match better */
1203 best_line_count
= file_line_count(diff
);
1204 strcpy(best_expect_file
, expectfile
);
1206 for (i
= 0; i
<= 9; i
++)
1208 char *alt_expectfile
;
1210 alt_expectfile
= get_alternative_expectfile(expectfile
, i
);
1211 if (!file_exists(alt_expectfile
))
1214 snprintf(cmd
, sizeof(cmd
),
1215 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1216 basic_diff_opts
, alt_expectfile
, resultsfile
, diff
);
1218 if (run_diff(cmd
, diff
) == 0)
1224 l
= file_line_count(diff
);
1225 if (l
< best_line_count
)
1227 /* This diff was a better match than the last one */
1228 best_line_count
= l
;
1229 strcpy(best_expect_file
, alt_expectfile
);
1231 free(alt_expectfile
);
1235 * fall back on the canonical results file if we haven't tried it yet and
1236 * haven't found a complete match yet.
1239 if (platform_expectfile
)
1241 snprintf(cmd
, sizeof(cmd
),
1242 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1243 basic_diff_opts
, default_expectfile
, resultsfile
, diff
);
1245 if (run_diff(cmd
, diff
) == 0)
1247 /* No diff = no changes = good */
1252 l
= file_line_count(diff
);
1253 if (l
< best_line_count
)
1255 /* This diff was a better match than the last one */
1256 best_line_count
= l
;
1257 strcpy(best_expect_file
, default_expectfile
);
1262 * Use the best comparison file to generate the "pretty" diff, which we
1263 * append to the diffs summary file.
1265 snprintf(cmd
, sizeof(cmd
),
1266 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE
,
1267 pretty_diff_opts
, best_expect_file
, resultsfile
, difffilename
);
1268 run_diff(cmd
, difffilename
);
1270 /* And append a separator */
1271 difffile
= fopen(difffilename
, "a");
1275 "\n======================================================================\n\n");
1284 * Wait for specified subprocesses to finish, and return their exit
1285 * statuses into statuses[]
1287 * If names isn't NULL, print each subprocess's name as it finishes
1289 * Note: it's OK to scribble on the pids array, but not on the names array
1292 wait_for_tests(PID_TYPE
*pids
, int *statuses
, char **names
, int num_tests
)
1298 PID_TYPE
*active_pids
= malloc(num_tests
* sizeof(PID_TYPE
));
1300 memcpy(active_pids
, pids
, num_tests
* sizeof(PID_TYPE
));
1303 tests_left
= num_tests
;
1304 while (tests_left
> 0)
1310 p
= wait(&exit_status
);
1312 if (p
== INVALID_PID
)
1314 fprintf(stderr
, _("failed to wait for subprocesses: %s\n"),
1321 r
= WaitForMultipleObjects(tests_left
, active_pids
, FALSE
, INFINITE
);
1322 if (r
< WAIT_OBJECT_0
|| r
>= WAIT_OBJECT_0
+ tests_left
)
1324 fprintf(stderr
, _("failed to wait for subprocesses: %lu\n"),
1328 p
= active_pids
[r
- WAIT_OBJECT_0
];
1329 /* compact the active_pids array */
1330 active_pids
[r
- WAIT_OBJECT_0
] = active_pids
[tests_left
- 1];
1333 for (i
= 0; i
< num_tests
; i
++)
1338 GetExitCodeProcess(pids
[i
], &exit_status
);
1339 CloseHandle(pids
[i
]);
1341 pids
[i
] = INVALID_PID
;
1342 statuses
[i
] = exit_status
;
1344 status(" %s", names
[i
]);
1357 * report nonzero exit code from a test process
1360 log_child_failure(int exitstatus
)
1362 if (WIFEXITED(exitstatus
))
1363 status(_(" (test process exited with exit code %d)"),
1364 WEXITSTATUS(exitstatus
));
1365 else if (WIFSIGNALED(exitstatus
))
1368 status(_(" (test process was terminated by exception 0x%X)"),
1369 WTERMSIG(exitstatus
));
1370 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1371 status(_(" (test process was terminated by signal %d: %s)"),
1372 WTERMSIG(exitstatus
),
1373 WTERMSIG(exitstatus
) < NSIG
?
1374 sys_siglist
[WTERMSIG(exitstatus
)] : "(unknown))");
1376 status(_(" (test process was terminated by signal %d)"),
1377 WTERMSIG(exitstatus
));
1381 status(_(" (test process exited with unrecognized status %d)"),
1386 * Run all the tests specified in one schedule file
1389 run_schedule(const char *schedule
, test_function tfunc
)
1391 #define MAX_PARALLEL_TESTS 100
1392 char *tests
[MAX_PARALLEL_TESTS
];
1393 _stringlist
*resultfiles
[MAX_PARALLEL_TESTS
];
1394 _stringlist
*expectfiles
[MAX_PARALLEL_TESTS
];
1395 _stringlist
*tags
[MAX_PARALLEL_TESTS
];
1396 PID_TYPE pids
[MAX_PARALLEL_TESTS
];
1397 int statuses
[MAX_PARALLEL_TESTS
];
1398 _stringlist
*ignorelist
= NULL
;
1403 memset(resultfiles
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1404 memset(expectfiles
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1405 memset(tags
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1407 scf
= fopen(schedule
, "r");
1410 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
1411 progname
, schedule
, strerror(errno
));
1415 while (fgets(scbuf
, sizeof(scbuf
), scf
))
1425 for (i
= 0; i
< MAX_PARALLEL_TESTS
; i
++)
1427 if (resultfiles
[i
] == NULL
)
1429 free_stringlist(&resultfiles
[i
]);
1430 free_stringlist(&expectfiles
[i
]);
1431 free_stringlist(&tags
[i
]);
1434 /* strip trailing whitespace, especially the newline */
1436 while (i
> 0 && isspace((unsigned char) scbuf
[i
- 1]))
1439 if (scbuf
[0] == '\0' || scbuf
[0] == '#')
1441 if (strncmp(scbuf
, "test: ", 6) == 0)
1443 else if (strncmp(scbuf
, "ignore: ", 8) == 0)
1446 while (*c
&& isspace((unsigned char) *c
))
1448 add_stringlist_item(&ignorelist
, c
);
1451 * Note: ignore: lines do not run the test, they just say that
1452 * failure of this test when run later on is to be ignored. A bit
1453 * odd but that's how the shell-script version did it.
1459 fprintf(stderr
, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1460 schedule
, line_num
, scbuf
);
1466 for (c
= test
; *c
; c
++)
1468 if (isspace((unsigned char) *c
))
1475 if (num_tests
>= MAX_PARALLEL_TESTS
)
1477 /* can't print scbuf here, it's already been trashed */
1478 fprintf(stderr
, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1479 schedule
, line_num
);
1482 tests
[num_tests
] = c
;
1490 fprintf(stderr
, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1491 schedule
, line_num
, scbuf
);
1497 status(_("test %-20s ... "), tests
[0]);
1498 pids
[0] = (tfunc
) (tests
[0], &resultfiles
[0], &expectfiles
[0], &tags
[0]);
1499 wait_for_tests(pids
, statuses
, NULL
, 1);
1500 /* status line is finished below */
1502 else if (max_connections
> 0 && max_connections
< num_tests
)
1506 status(_("parallel group (%d tests, in groups of %d): "),
1507 num_tests
, max_connections
);
1508 for (i
= 0; i
< num_tests
; i
++)
1510 if (i
- oldest
>= max_connections
)
1512 wait_for_tests(pids
+ oldest
, statuses
+ oldest
,
1513 tests
+ oldest
, i
- oldest
);
1516 pids
[i
] = (tfunc
) (tests
[i
], &resultfiles
[i
], &expectfiles
[i
], &tags
[i
]);
1518 wait_for_tests(pids
+ oldest
, statuses
+ oldest
,
1519 tests
+ oldest
, i
- oldest
);
1524 status(_("parallel group (%d tests): "), num_tests
);
1525 for (i
= 0; i
< num_tests
; i
++)
1527 pids
[i
] = (tfunc
) (tests
[i
], &resultfiles
[i
], &expectfiles
[i
], &tags
[i
]);
1529 wait_for_tests(pids
, statuses
, tests
, num_tests
);
1533 /* Check results for all tests */
1534 for (i
= 0; i
< num_tests
; i
++)
1539 bool differ
= false;
1542 status(_(" %-20s ... "), tests
[i
]);
1545 * Advance over all three lists simultaneously.
1547 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1548 * optional but if there are tags, the tag list has the same
1549 * length as the other two lists.
1551 for (rl
= resultfiles
[i
], el
= expectfiles
[i
], tl
= tags
[i
];
1552 rl
!= NULL
; /* rl and el have the same length */
1553 rl
= rl
->next
, el
= el
->next
)
1558 tl
= tl
->next
; /* tl has the same length as rl and el
1561 newdiff
= results_differ(tests
[i
], rl
->str
, el
->str
);
1564 printf("%s ", tl
->str
);
1571 bool ignore
= false;
1574 for (sl
= ignorelist
; sl
!= NULL
; sl
= sl
->next
)
1576 if (strcmp(tests
[i
], sl
->str
) == 0)
1584 status(_("failed (ignored)"));
1585 fail_ignore_count
++;
1589 status(_("FAILED"));
1599 if (statuses
[i
] != 0)
1600 log_child_failure(statuses
[i
]);
1613 run_single_test(const char *test
, test_function tfunc
)
1617 _stringlist
*resultfiles
= NULL
;
1618 _stringlist
*expectfiles
= NULL
;
1619 _stringlist
*tags
= NULL
;
1623 bool differ
= false;
1625 status(_("test %-20s ... "), test
);
1626 pid
= (tfunc
) (test
, &resultfiles
, &expectfiles
, &tags
);
1627 wait_for_tests(&pid
, &exit_status
, NULL
, 1);
1630 * Advance over all three lists simultaneously.
1632 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1633 * but if there are tags, the tag list has the same length as the other
1636 for (rl
= resultfiles
, el
= expectfiles
, tl
= tags
;
1637 rl
!= NULL
; /* rl and el have the same length */
1638 rl
= rl
->next
, el
= el
->next
)
1643 tl
= tl
->next
; /* tl has the same length as rl and el if it
1646 newdiff
= results_differ(test
, rl
->str
, el
->str
);
1649 printf("%s ", tl
->str
);
1656 status(_("FAILED"));
1665 if (exit_status
!= 0)
1666 log_child_failure(exit_status
);
1672 * Create the summary-output files (making them empty if already existing)
1675 open_result_files(void)
1677 char file
[MAXPGPATH
];
1680 /* create the log file (copy of running status output) */
1681 snprintf(file
, sizeof(file
), "%s/regression.out", outputdir
);
1682 logfilename
= strdup(file
);
1683 logfile
= fopen(logfilename
, "w");
1686 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
1687 progname
, logfilename
, strerror(errno
));
1691 /* create the diffs file as empty */
1692 snprintf(file
, sizeof(file
), "%s/regression.diffs", outputdir
);
1693 difffilename
= strdup(file
);
1694 difffile
= fopen(difffilename
, "w");
1697 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
1698 progname
, difffilename
, strerror(errno
));
1701 /* we don't keep the diffs file open continuously */
1704 /* also create the output directory if not present */
1705 snprintf(file
, sizeof(file
), "%s/results", outputdir
);
1706 if (!directory_exists(file
))
1707 make_directory(file
);
1711 drop_database_if_exists(const char *dbname
)
1713 header(_("dropping database \"%s\""), dbname
);
1714 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname
);
1718 create_database(const char *dbname
)
1723 * We use template0 so that any installation-local cruft in template1 will
1724 * not mess up the tests.
1726 header(_("creating database \"%s\""), dbname
);
1728 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname
, encoding
);
1730 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0", dbname
);
1731 psql_command(dbname
,
1732 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1733 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1734 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1735 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1736 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1737 dbname
, dbname
, dbname
, dbname
, dbname
);
1740 * Install any requested procedural languages
1742 for (sl
= loadlanguage
; sl
!= NULL
; sl
= sl
->next
)
1744 header(_("installing %s"), sl
->str
);
1745 psql_command(dbname
, "CREATE LANGUAGE \"%s\"", sl
->str
);
1750 drop_role_if_exists(const char *rolename
)
1752 header(_("dropping role \"%s\""), rolename
);
1753 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename
);
1757 create_role(const char *rolename
, const _stringlist
* granted_dbs
)
1759 header(_("creating role \"%s\""), rolename
);
1760 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename
);
1761 for (; granted_dbs
!= NULL
; granted_dbs
= granted_dbs
->next
)
1763 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1764 granted_dbs
->str
, rolename
);
1769 make_absolute_path(const char *in
)
1773 if (is_absolute_path(in
))
1774 result
= strdup(in
);
1777 static char cwdbuf
[MAXPGPATH
];
1781 if (!getcwd(cwdbuf
, sizeof(cwdbuf
)))
1783 fprintf(stderr
, _("could not get current working directory: %s\n"), strerror(errno
));
1788 result
= malloc(strlen(cwdbuf
) + strlen(in
) + 2);
1789 sprintf(result
, "%s/%s", cwdbuf
, in
);
1792 canonicalize_path(result
);
1799 printf(_("PostgreSQL regression test driver\n"));
1801 printf(_("Usage: %s [options...] [extra tests...]\n"), progname
);
1803 printf(_("Options:\n"));
1804 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1805 printf(_(" --debug turn on debug mode in programs that are run\n"));
1806 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1807 printf(_(" --load-language=lang load the named language before running the\n"));
1808 printf(_(" tests; can appear multiple times\n"));
1809 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1810 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1811 printf(_(" (default is 0 meaning unlimited)\n"));
1812 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1813 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1814 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1815 printf(_(" (can be used multiple times to concatenate)\n"));
1816 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1817 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1819 printf(_("Options for \"temp-install\" mode:\n"));
1820 printf(_(" --no-locale use C locale\n"));
1821 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1822 printf(_(" --temp-port=PORT port number to start temp postmaster on\n"));
1823 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1825 printf(_("Options for using an existing installation:\n"));
1826 printf(_(" --host=HOST use postmaster running on HOST\n"));
1827 printf(_(" --port=PORT use postmaster running at PORT\n"));
1828 printf(_(" --user=USER connect as USER\n"));
1829 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1831 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1832 printf(_("if the tests could not be run for some reason.\n"));
1834 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1838 regression_main(int argc
, char *argv
[], init_function ifunc
, test_function tfunc
)
1844 char buf
[MAXPGPATH
* 4];
1846 static struct option long_options
[] = {
1847 {"help", no_argument
, NULL
, 'h'},
1848 {"version", no_argument
, NULL
, 'V'},
1849 {"dbname", required_argument
, NULL
, 1},
1850 {"debug", no_argument
, NULL
, 2},
1851 {"inputdir", required_argument
, NULL
, 3},
1852 {"load-language", required_argument
, NULL
, 4},
1853 {"max-connections", required_argument
, NULL
, 5},
1854 {"multibyte", required_argument
, NULL
, 6},
1855 {"outputdir", required_argument
, NULL
, 7},
1856 {"schedule", required_argument
, NULL
, 8},
1857 {"temp-install", required_argument
, NULL
, 9},
1858 {"no-locale", no_argument
, NULL
, 10},
1859 {"top-builddir", required_argument
, NULL
, 11},
1860 {"temp-port", required_argument
, NULL
, 12},
1861 {"host", required_argument
, NULL
, 13},
1862 {"port", required_argument
, NULL
, 14},
1863 {"user", required_argument
, NULL
, 15},
1864 {"psqldir", required_argument
, NULL
, 16},
1865 {"dlpath", required_argument
, NULL
, 17},
1866 {"create-role", required_argument
, NULL
, 18},
1867 {"temp-config", required_argument
, NULL
, 19},
1871 progname
= get_progname(argv
[0]);
1872 set_pglocale_pgservice(argv
[0], "pg_regress");
1874 #ifndef HAVE_UNIX_SOCKETS
1875 /* no unix domain sockets available, so change default */
1876 hostname
= "localhost";
1880 * We call the initialization function here because that way we can set
1881 * default parameters and let them be overwritten by the commandline.
1885 while ((c
= getopt_long(argc
, argv
, "hV", long_options
, &option_index
)) != -1)
1893 puts("pg_regress (PostgreSQL) " PG_VERSION
);
1898 * If a default database was specified, we need to remove it
1899 * before we add the specified one.
1901 free_stringlist(&dblist
);
1902 split_to_stringlist(strdup(optarg
), ", ", &dblist
);
1908 inputdir
= strdup(optarg
);
1911 add_stringlist_item(&loadlanguage
, optarg
);
1914 max_connections
= atoi(optarg
);
1917 encoding
= strdup(optarg
);
1920 outputdir
= strdup(optarg
);
1923 add_stringlist_item(&schedulelist
, optarg
);
1926 temp_install
= make_absolute_path(optarg
);
1932 top_builddir
= strdup(optarg
);
1936 int p
= atoi(optarg
);
1938 /* Since Makefile isn't very bright, check port range */
1939 if (p
>= 1024 && p
<= 65535)
1944 hostname
= strdup(optarg
);
1947 port
= atoi(optarg
);
1950 user
= strdup(optarg
);
1953 /* "--psqldir=" should mean to use PATH */
1955 psqldir
= strdup(optarg
);
1958 dlpath
= strdup(optarg
);
1961 split_to_stringlist(strdup(optarg
), ", ", &extraroles
);
1964 temp_config
= strdup(optarg
);
1967 /* getopt_long already emitted a complaint */
1968 fprintf(stderr
, _("\nTry \"%s -h\" for more information.\n"),
1975 * if we still have arguments, they are extra tests to run
1977 while (argc
- optind
>= 1)
1979 add_stringlist_item(&extra_tests
, argv
[optind
]);
1986 inputdir
= make_absolute_path(inputdir
);
1987 outputdir
= make_absolute_path(outputdir
);
1988 dlpath
= make_absolute_path(dlpath
);
1993 open_result_files();
1995 initialize_environment();
1997 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
1998 unlimit_core_size();
2004 * Prepare the temp installation
2008 fprintf(stderr
, _("--top-builddir must be specified when using --temp-install\n"));
2012 if (directory_exists(temp_install
))
2014 header(_("removing existing temp installation"));
2015 rmtree(temp_install
, true);
2018 header(_("creating temporary installation"));
2020 /* make the temp install top directory */
2021 make_directory(temp_install
);
2023 /* and a directory for log files */
2024 snprintf(buf
, sizeof(buf
), "%s/log", outputdir
);
2025 if (!directory_exists(buf
))
2026 make_directory(buf
);
2028 /* "make install" */
2029 #ifndef WIN32_ONLY_COMPILER
2030 snprintf(buf
, sizeof(buf
),
2031 SYSTEMQUOTE
"\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE
,
2032 makeprog
, top_builddir
, temp_install
, outputdir
);
2034 snprintf(buf
, sizeof(buf
),
2035 SYSTEMQUOTE
"perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE
,
2036 top_builddir
, temp_install
, outputdir
);
2040 fprintf(stderr
, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname
, outputdir
, buf
);
2045 header(_("initializing database system"));
2046 snprintf(buf
, sizeof(buf
),
2047 SYSTEMQUOTE
"\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE
,
2048 bindir
, temp_install
, datadir
,
2049 debug
? " --debug" : "",
2050 nolocale
? " --no-locale" : "",
2054 fprintf(stderr
, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname
, outputdir
, buf
);
2058 /* add any extra config specified to the postgresql.conf */
2059 if (temp_config
!= NULL
)
2063 char line_buf
[1024];
2065 snprintf(buf
, sizeof(buf
), "%s/data/postgresql.conf", temp_install
);
2066 pg_conf
= fopen(buf
, "a");
2067 if (pg_conf
== NULL
)
2069 fprintf(stderr
, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname
, buf
, strerror(errno
));
2072 extra_conf
= fopen(temp_config
, "r");
2073 if (extra_conf
== NULL
)
2075 fprintf(stderr
, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname
, temp_config
, strerror(errno
));
2078 while (fgets(line_buf
, sizeof(line_buf
), extra_conf
) != NULL
)
2079 fputs(line_buf
, pg_conf
);
2085 * Start the temp postmaster
2087 header(_("starting postmaster"));
2088 snprintf(buf
, sizeof(buf
),
2089 SYSTEMQUOTE
"\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE
,
2090 bindir
, temp_install
,
2091 debug
? " -d 5" : "",
2092 hostname
? hostname
: "",
2094 postmaster_pid
= spawn_process(buf
);
2095 if (postmaster_pid
== INVALID_PID
)
2097 fprintf(stderr
, _("\n%s: could not spawn postmaster: %s\n"),
2098 progname
, strerror(errno
));
2103 * Wait till postmaster is able to accept connections (normally only a
2104 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2107 snprintf(buf
, sizeof(buf
),
2108 SYSTEMQUOTE
"\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE
,
2109 bindir
, DEVNULL
, DEVNULL
);
2110 for (i
= 0; i
< 60; i
++)
2112 /* Done if psql succeeds */
2113 if (system(buf
) == 0)
2117 * Fail immediately if postmaster has exited
2120 if (kill(postmaster_pid
, 0) != 0)
2122 if (WaitForSingleObject(postmaster_pid
, 0) == WAIT_OBJECT_0
)
2125 fprintf(stderr
, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname
, outputdir
);
2129 pg_usleep(1000000L);
2133 fprintf(stderr
, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname
, outputdir
);
2136 * If we get here, the postmaster is probably wedged somewhere in
2137 * startup. Try to kill it ungracefully rather than leaving a
2138 * stuck postmaster that might interfere with subsequent test
2142 if (kill(postmaster_pid
, SIGKILL
) != 0 &&
2144 fprintf(stderr
, _("\n%s: could not kill failed postmaster: %s\n"),
2145 progname
, strerror(errno
));
2147 if (TerminateProcess(postmaster_pid
, 255) == 0)
2148 fprintf(stderr
, _("\n%s: could not kill failed postmaster: %lu\n"),
2149 progname
, GetLastError());
2155 postmaster_running
= true;
2157 printf(_("running on port %d with pid %lu\n"),
2158 temp_port
, (unsigned long) postmaster_pid
);
2163 * Using an existing installation, so may need to get rid of
2164 * pre-existing database(s) and role(s)
2166 for (sl
= dblist
; sl
; sl
= sl
->next
)
2167 drop_database_if_exists(sl
->str
);
2168 for (sl
= extraroles
; sl
; sl
= sl
->next
)
2169 drop_role_if_exists(sl
->str
);
2173 * Create the test database(s) and role(s)
2175 for (sl
= dblist
; sl
; sl
= sl
->next
)
2176 create_database(sl
->str
);
2177 for (sl
= extraroles
; sl
; sl
= sl
->next
)
2178 create_role(sl
->str
, dblist
);
2181 * Ready to run the tests
2183 header(_("running regression test queries"));
2185 for (sl
= schedulelist
; sl
!= NULL
; sl
= sl
->next
)
2187 run_schedule(sl
->str
, tfunc
);
2190 for (sl
= extra_tests
; sl
!= NULL
; sl
= sl
->next
)
2192 run_single_test(sl
->str
, tfunc
);
2196 * Shut down temp installation's postmaster
2200 header(_("shutting down postmaster"));
2207 * Emit nice-looking summary message
2209 if (fail_count
== 0 && fail_ignore_count
== 0)
2210 snprintf(buf
, sizeof(buf
),
2211 _(" All %d tests passed. "),
2213 else if (fail_count
== 0) /* fail_count=0, fail_ignore_count>0 */
2214 snprintf(buf
, sizeof(buf
),
2215 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2217 success_count
+ fail_ignore_count
,
2219 else if (fail_ignore_count
== 0) /* fail_count>0 && fail_ignore_count=0 */
2220 snprintf(buf
, sizeof(buf
),
2221 _(" %d of %d tests failed. "),
2223 success_count
+ fail_count
);
2225 /* fail_count>0 && fail_ignore_count>0 */
2226 snprintf(buf
, sizeof(buf
),
2227 _(" %d of %d tests failed, %d of these failures ignored. "),
2228 fail_count
+ fail_ignore_count
,
2229 success_count
+ fail_count
+ fail_ignore_count
,
2233 for (i
= strlen(buf
); i
> 0; i
--)
2235 printf("\n%s\n", buf
);
2236 for (i
= strlen(buf
); i
> 0; i
--)
2241 if (file_size(difffilename
) > 0)
2243 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2244 "file \"%s\". A copy of the test summary that you see\n"
2245 "above is saved in the file \"%s\".\n\n"),
2246 difffilename
, logfilename
);
2250 unlink(difffilename
);
2251 unlink(logfilename
);
2254 if (fail_count
!= 0)