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-2013, PostgreSQL Global Development Group
12
* Portions Copyright (c) 1994, Regents of the University of California
14
* src/test/regress/pg_regress.c
16
*-------------------------------------------------------------------------
19
#include "pg_regress.h"
27
#ifdef HAVE_SYS_RESOURCE_H
29
#include <sys/resource.h>
32
#include "getopt_long.h"
33
#include "pg_config_paths.h"
35
/* for resultmap we need a list of pairs of strings */
36
typedef struct _resultmap
41
struct _resultmap *next;
45
* Values obtained from pg_config_paths.h and Makefile. The PG installation
46
* paths are only used in temp_install mode: we use these strings to find
47
* out where "make install" will put stuff under the temp_install directory.
48
* In non-temp_install mode, the only thing we need is the location of psql,
49
* which we expect to find in psqldir, or in the PATH if psqldir isn't given.
51
* XXX Because pg_regress is not installed in bindir, we can't support
52
* this for relocatable trees as it is. --psqldir would need to be
53
* specified in those cases.
55
char *bindir = PGBINDIR;
56
char *libdir = LIBDIR;
57
char *datadir = PGSHAREDIR;
58
char *host_platform = HOST_TUPLE;
60
#ifndef WIN32_ONLY_COMPILER
61
static char *makeprog = MAKEPROG;
64
#ifndef WIN32 /* not used in WIN32 case */
65
static char *shellprog = SHELLPROG;
69
* On Windows we use -w in diff switches to avoid problems with inconsistent
70
* newline representation. The actual result files will generally have
71
* Windows-style newlines, but the comparison files might or might not.
74
const char *basic_diff_opts = "";
75
const char *pretty_diff_opts = "-C3";
77
const char *basic_diff_opts = "-w";
78
const char *pretty_diff_opts = "-w -C3";
81
/* options settable from command line */
82
_stringlist *dblist = NULL;
85
char *outputdir = ".";
86
char *psqldir = PGBINDIR;
87
char *launcher = NULL;
88
static _stringlist *loadlanguage = NULL;
89
static _stringlist *loadextension = NULL;
90
static int max_connections = 0;
91
static char *encoding = NULL;
92
static _stringlist *schedulelist = NULL;
93
static _stringlist *extra_tests = NULL;
94
static char *temp_install = NULL;
95
static char *temp_config = NULL;
96
static char *top_builddir = NULL;
97
static bool nolocale = false;
98
static bool use_existing = false;
99
static char *hostname = NULL;
100
static int port = -1;
101
static bool port_specified_by_user = false;
102
static char *dlpath = PKGLIBDIR;
103
static char *user = NULL;
104
static _stringlist *extraroles = NULL;
105
static _stringlist *extra_install = NULL;
107
/* internal variables */
108
static const char *progname;
109
static char *logfilename;
110
static FILE *logfile;
111
static char *difffilename;
113
static _resultmap *resultmap = NULL;
115
static PID_TYPE postmaster_pid = INVALID_PID;
116
static bool postmaster_running = false;
118
static int success_count = 0;
119
static int fail_count = 0;
120
static int fail_ignore_count = 0;
122
static bool directory_exists(const char *dir);
123
static void make_directory(const char *dir);
126
header(const char *fmt,...)
127
/* This extension allows gcc to check the format string for consistency with
128
the supplied arguments. */
129
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
131
status(const char *fmt,...)
132
/* This extension allows gcc to check the format string for consistency with
133
the supplied arguments. */
134
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
136
psql_command(const char *database, const char *query,...)
137
/* This extension allows gcc to check the format string for consistency with
138
the supplied arguments. */
139
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
142
typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
144
/* Windows API define missing from some versions of MingW headers */
145
#ifndef DISABLE_MAX_PRIVILEGE
146
#define DISABLE_MAX_PRIVILEGE 0x1
151
* allow core files if possible.
153
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
155
unlimit_core_size(void)
159
getrlimit(RLIMIT_CORE, &lim);
160
if (lim.rlim_max == 0)
163
_("%s: could not set core size: disallowed by hard limit\n"),
167
else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
169
lim.rlim_cur = lim.rlim_max;
170
setrlimit(RLIMIT_CORE, &lim);
177
* Add an item at the end of a stringlist.
180
add_stringlist_item(_stringlist ** listhead, const char *str)
182
_stringlist *newentry = malloc(sizeof(_stringlist));
183
_stringlist *oldentry;
185
newentry->str = strdup(str);
186
newentry->next = NULL;
187
if (*listhead == NULL)
188
*listhead = newentry;
191
for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
193
oldentry->next = newentry;
201
free_stringlist(_stringlist ** listhead)
203
if (listhead == NULL || *listhead == NULL)
205
if ((*listhead)->next != NULL)
206
free_stringlist(&((*listhead)->next));
207
free((*listhead)->str);
213
* Split a delimited string into a stringlist
216
split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
218
char *sc = strdup(s);
219
char *token = strtok(sc, delim);
223
add_stringlist_item(listhead, token);
224
token = strtok(NULL, delim);
230
* Print a progress banner on stdout.
233
header(const char *fmt,...)
239
vsnprintf(tmp, sizeof(tmp), fmt, ap);
242
fprintf(stdout, "============== %-38s ==============\n", tmp);
247
* Print "doing something ..." --- supplied text should not end with newline
250
status(const char *fmt,...)
255
vfprintf(stdout, fmt, ap);
262
vfprintf(logfile, fmt, ap);
268
* Done "doing something ..."
273
fprintf(stdout, "\n");
276
fprintf(logfile, "\n");
280
* shut down temp postmaster
283
stop_postmaster(void)
285
if (postmaster_running)
287
/* We use pg_ctl to issue the kill and wait for stop */
288
char buf[MAXPGPATH * 2];
291
/* On Windows, system() seems not to force fflush, so... */
295
snprintf(buf, sizeof(buf),
296
SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
297
bindir, temp_install);
301
fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
303
_exit(2); /* not exit(), that could be recursive */
306
postmaster_running = false;
311
* Check whether string matches pattern
313
* In the original shell script, this function was implemented using expr(1),
314
* which provides basic regular expressions restricted to match starting at
315
* the string start (in conventional regex terms, there's an implicit "^"
316
* at the start of the pattern --- but no implicit "$" at the end).
318
* For now, we only support "." and ".*" as non-literal metacharacters,
319
* because that's all that anyone has found use for in resultmap. This
320
* code could be extended if more functionality is needed.
323
string_matches_pattern(const char *str, const char *pattern)
325
while (*str && *pattern)
327
if (*pattern == '.' && pattern[1] == '*')
330
/* Trailing .* matches everything. */
331
if (*pattern == '\0')
335
* Otherwise, scan for a text position at which we can match the
336
* rest of the pattern.
341
* Optimization to prevent most recursion: don't recurse
342
* unless first pattern char might match this text char.
344
if (*str == *pattern || *pattern == '.')
346
if (string_matches_pattern(str, pattern))
354
* End of text with no match.
358
else if (*pattern != '.' && *str != *pattern)
361
* Not the single-character wildcard and no explicit match? Then
371
if (*pattern == '\0')
372
return true; /* end of pattern, so declare match */
374
/* End of input string. Do we have matching pattern remaining? */
375
while (*pattern == '.' && pattern[1] == '*')
377
if (*pattern == '\0')
378
return true; /* end of pattern, so declare match */
384
* Replace all occurrences of a string in a string with a different string.
385
* NOTE: Assumes there is enough room in the target buffer!
388
replace_string(char *string, char *replace, char *replacement)
392
while ((ptr = strstr(string, replace)) != NULL)
394
char *dup = strdup(string);
396
strlcpy(string, dup, ptr - string + 1);
397
strcat(string, replacement);
398
strcat(string, dup + (ptr - string) + strlen(replace));
404
* Convert *.source found in the "source" directory, replacing certain tokens
405
* in the file contents with their intended values, and put the resulting files
406
* in the "dest" directory, replacing the ".source" prefix in their names with
410
convert_sourcefiles_in(char *source_subdir, char *dest_dir, char *dest_subdir, char *suffix)
412
char testtablespace[MAXPGPATH];
413
char indir[MAXPGPATH];
420
snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
422
/* Check that indir actually exists and is a directory */
423
ret = stat(indir, &st);
424
if (ret != 0 || !S_ISDIR(st.st_mode))
427
* No warning, to avoid noise in tests that do not have these
428
* directories; for example, ecpg, contrib and src/pl.
433
names = pgfnames(indir);
435
/* Error logged in pgfnames */
438
snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
443
* On Windows only, clean out the test tablespace dir, or create it if it
444
* doesn't exist. On other platforms we expect the Makefile to take care
445
* of that. (We don't migrate that functionality in here because it'd be
446
* harder to cope with platform-specific issues such as SELinux.)
448
* XXX it would be better if pg_regress.c had nothing at all to do with
449
* testtablespace, and this were handled by a .BAT file or similar on
450
* Windows. See pgsql-hackers discussion of 2008-01-18.
452
if (directory_exists(testtablespace))
453
rmtree(testtablespace, true);
454
make_directory(testtablespace);
457
/* finally loop on each file and do the replacement */
458
for (name = names; *name; name++)
460
char srcfile[MAXPGPATH];
461
char destfile[MAXPGPATH];
462
char prefix[MAXPGPATH];
467
/* reject filenames not finishing in ".source" */
468
if (strlen(*name) < 8)
470
if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
475
/* build the full actual paths to open */
476
snprintf(prefix, strlen(*name) - 6, "%s", *name);
477
snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
478
snprintf(destfile, MAXPGPATH, "%s/%s/%s.%s", dest_dir, dest_subdir,
481
infile = fopen(srcfile, "r");
484
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
485
progname, srcfile, strerror(errno));
488
outfile = fopen(destfile, "w");
491
fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
492
progname, destfile, strerror(errno));
495
while (fgets(line, sizeof(line), infile))
497
replace_string(line, "@abs_srcdir@", inputdir);
498
replace_string(line, "@abs_builddir@", outputdir);
499
replace_string(line, "@testtablespace@", testtablespace);
500
replace_string(line, "@libdir@", dlpath);
501
replace_string(line, "@DLSUFFIX@", DLSUFFIX);
502
fputs(line, outfile);
509
* If we didn't process any files, complain because it probably means
510
* somebody neglected to pass the needed --inputdir argument.
514
fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
519
pgfnames_cleanup(names);
522
/* Create the .sql and .out files from the .source files, if any */
524
convert_sourcefiles(void)
526
convert_sourcefiles_in("input", inputdir, "sql", "sql");
527
convert_sourcefiles_in("output", outputdir, "expected", "out");
531
* Scan resultmap file to find which platform-specific expected files to use.
533
* The format of each line of the file is
534
* testname/hostplatformpattern=substitutefile
535
* where the hostplatformpattern is evaluated per the rules of expr(1),
536
* namely, it is a standard regular expression with an implicit ^ at the start.
537
* (We currently support only a very limited subset of regular expressions,
538
* see string_matches_pattern() above.) What hostplatformpattern will be
539
* matched against is the config.guess output. (In the shell-script version,
540
* we also provided an indication of whether gcc or another compiler was in
541
* use, but that facility isn't used anymore.)
549
/* scan the file ... */
550
snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
554
/* OK if it doesn't exist, else complain */
557
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
558
progname, buf, strerror(errno));
562
while (fgets(buf, sizeof(buf), f))
569
/* strip trailing whitespace, especially the newline */
571
while (i > 0 && isspace((unsigned char) buf[i - 1]))
574
/* parse out the line fields */
575
file_type = strchr(buf, ':');
578
fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
584
platform = strchr(file_type, ':');
587
fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
592
expected = strchr(platform, '=');
595
fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
602
* if it's for current platform, save it in resultmap list. Note: by
603
* adding at the front of the list, we ensure that in ambiguous cases,
604
* the last match in the resultmap file is used. This mimics the
605
* behavior of the old shell script.
607
if (string_matches_pattern(host_platform, platform))
609
_resultmap *entry = malloc(sizeof(_resultmap));
611
entry->test = strdup(buf);
612
entry->type = strdup(file_type);
613
entry->resultfile = strdup(expected);
614
entry->next = resultmap;
622
* Check in resultmap if we should be looking at a different file
626
get_expectfile(const char *testname, const char *file)
632
* Determine the file type from the file name. This is just what is
633
* following the last dot in the file name.
635
if (!file || !(file_type = strrchr(file, '.')))
640
for (rm = resultmap; rm != NULL; rm = rm->next)
642
if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
644
return rm->resultfile;
652
* Handy subroutine for setting an environment variable "var" to "val"
655
doputenv(const char *var, const char *val)
657
char *s = malloc(strlen(var) + strlen(val) + 2);
659
sprintf(s, "%s=%s", var, val);
664
* Set the environment variable "pathname", prepending "addval" to its
665
* old value (if any).
668
add_to_path(const char *pathname, char separator, const char *addval)
670
char *oldval = getenv(pathname);
673
if (!oldval || !oldval[0])
675
/* no previous value */
676
newval = malloc(strlen(pathname) + strlen(addval) + 2);
677
sprintf(newval, "%s=%s", pathname, addval);
681
newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
682
sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
688
* Prepare environment variables for running regression tests
691
initialize_environment(void)
695
putenv("PGAPPNAME=pg_regress");
700
* Clear out any non-C locale settings
702
unsetenv("LC_COLLATE");
703
unsetenv("LC_CTYPE");
704
unsetenv("LC_MONETARY");
705
unsetenv("LC_NUMERIC");
708
/* On Windows the default locale cannot be English, so force it */
709
#if defined(WIN32) || defined(__CYGWIN__)
715
* Set translation-related settings to English; otherwise psql will
716
* produce translated messages and produce diffs. (XXX If we ever support
717
* translation of pg_regress, this needs to be moved elsewhere, where psql
718
* is actually called.)
720
unsetenv("LANGUAGE");
722
putenv("LC_MESSAGES=C");
725
* Set encoding as requested
728
doputenv("PGCLIENTENCODING", encoding);
730
unsetenv("PGCLIENTENCODING");
733
* Set timezone and datestyle for datetime-related tests
735
putenv("PGTZ=PST8PDT");
736
putenv("PGDATESTYLE=Postgres, MDY");
739
* Likewise set intervalstyle to ensure consistent results. This is a bit
740
* more painful because we must use PGOPTIONS, and we want to preserve the
741
* user's ability to set other variables through that.
744
const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
745
const char *old_pgoptions = getenv("PGOPTIONS");
750
new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
751
sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
752
putenv(new_pgoptions);
758
* Clear out any environment vars that might cause psql to connect to
759
* the wrong postmaster, or otherwise behave in nondefault ways. (Note
760
* we also use psql's -X switch consistently, so that ~/.psqlrc files
761
* won't mess things up.) Also, set PGPORT to the temp port, and set
762
* or unset PGHOST depending on whether we are using TCP or Unix
765
unsetenv("PGDATABASE");
767
unsetenv("PGSERVICE");
768
unsetenv("PGSSLMODE");
769
unsetenv("PGREQUIRESSL");
770
unsetenv("PGCONNECT_TIMEOUT");
772
if (hostname != NULL)
773
doputenv("PGHOST", hostname);
776
unsetenv("PGHOSTADDR");
781
sprintf(s, "%d", port);
782
doputenv("PGPORT", s);
786
* GNU make stores some flags in the MAKEFLAGS environment variable to
787
* pass arguments to its own children. If we are invoked by make,
788
* that causes the make invoked by us to think its part of the make
789
* task invoking us, and so it tries to communicate with the toplevel
792
* Unset the variable to protect against such problems. We also reset
793
* MAKELEVEL to be certain the child doesn't notice the make above us.
795
unsetenv("MAKEFLAGS");
796
unsetenv("MAKELEVEL");
799
* Adjust path variables to point into the temp-install tree
801
tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
802
sprintf(tmp, "%s/install/%s", temp_install, bindir);
805
tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
806
sprintf(tmp, "%s/install/%s", temp_install, libdir);
809
tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
810
sprintf(tmp, "%s/install/%s", temp_install, datadir);
813
/* psql will be installed into temp-install bindir */
817
* Set up shared library paths to include the temp install.
819
* LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
820
* Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
821
* Windows needs shared libraries in PATH (only those linked into
822
* executables, not dlopen'ed ones). Feel free to account for others
825
add_to_path("LD_LIBRARY_PATH", ':', libdir);
826
add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
827
add_to_path("LIBPATH", ':', libdir);
829
add_to_path("PATH", ';', libdir);
830
#elif defined(__CYGWIN__)
831
add_to_path("PATH", ':', libdir);
840
* When testing an existing install, we honor existing environment
841
* variables, except if they're overridden by command line options.
843
if (hostname != NULL)
845
doputenv("PGHOST", hostname);
846
unsetenv("PGHOSTADDR");
852
sprintf(s, "%d", port);
853
doputenv("PGPORT", s);
856
doputenv("PGUSER", user);
859
* Report what we're connecting to
861
pghost = getenv("PGHOST");
862
pgport = getenv("PGPORT");
863
#ifndef HAVE_UNIX_SOCKETS
865
pghost = "localhost";
868
if (pghost && pgport)
869
printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
870
if (pghost && !pgport)
871
printf(_("(using postmaster on %s, default port)\n"), pghost);
872
if (!pghost && pgport)
873
printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
874
if (!pghost && !pgport)
875
printf(_("(using postmaster on Unix socket, default port)\n"));
878
convert_sourcefiles();
883
* Issue a command via psql, connecting to the specified database
885
* Since we use system(), this doesn't return until the operation finishes
888
psql_command(const char *database, const char *query,...)
890
char query_formatted[1024];
891
char query_escaped[2048];
892
char psql_cmd[MAXPGPATH + 2048];
897
/* Generate the query with insertion of sprintf arguments */
898
va_start(args, query);
899
vsnprintf(query_formatted, sizeof(query_formatted), query, args);
902
/* Now escape any shell double-quote metacharacters */
904
for (s = query_formatted; *s; s++)
906
if (strchr("\\\"$`", *s))
912
/* And now we can build and execute the shell command */
913
snprintf(psql_cmd, sizeof(psql_cmd),
914
SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
915
psqldir ? psqldir : "",
920
if (system(psql_cmd) != 0)
922
/* psql probably already reported the error */
923
fprintf(stderr, _("command failed: %s\n"), psql_cmd);
929
* Spawn a process to execute the given shell command; don't wait for it
931
* Returns the process ID (or HANDLE) so we can wait for it later
934
spawn_process(const char *cmdline)
940
* Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
941
* ... does anyone still care about systems where that doesn't work?
951
fprintf(stderr, _("%s: could not fork: %s\n"),
952
progname, strerror(errno));
960
* Instead of using system(), exec the shell directly, and tell it to
961
* "exec" the command too. This saves two useless processes per
962
* parallel test case.
964
char *cmdline2 = malloc(strlen(cmdline) + 6);
966
sprintf(cmdline2, "exec %s", cmdline);
967
execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
968
fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
969
progname, shellprog, strerror(errno));
970
_exit(1); /* not exit() here... */
978
PROCESS_INFORMATION pi;
980
HANDLE restrictedToken;
981
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
982
SID_AND_ATTRIBUTES dropSids[2];
983
__CreateRestrictedToken _CreateRestrictedToken = NULL;
984
HANDLE Advapi32Handle;
986
ZeroMemory(&si, sizeof(si));
989
Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
990
if (Advapi32Handle != NULL)
992
_CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
995
if (_CreateRestrictedToken == NULL)
997
if (Advapi32Handle != NULL)
998
FreeLibrary(Advapi32Handle);
999
fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
1004
/* Open the current token to use as base for the restricted one */
1005
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
1007
fprintf(stderr, _("could not open process token: error code %lu\n"),
1012
/* Allocate list of SIDs to remove */
1013
ZeroMemory(&dropSids, sizeof(dropSids));
1014
if (!AllocateAndInitializeSid(&NtAuthority, 2,
1015
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
1016
!AllocateAndInitializeSid(&NtAuthority, 2,
1017
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
1019
fprintf(stderr, _("could not allocate SIDs: error code %lu\n"), GetLastError());
1023
b = _CreateRestrictedToken(origToken,
1024
DISABLE_MAX_PRIVILEGE,
1025
sizeof(dropSids) / sizeof(dropSids[0]),
1031
FreeSid(dropSids[1].Sid);
1032
FreeSid(dropSids[0].Sid);
1033
CloseHandle(origToken);
1034
FreeLibrary(Advapi32Handle);
1038
fprintf(stderr, _("could not create restricted token: error code %lu\n"),
1043
cmdline2 = malloc(strlen(cmdline) + 8);
1044
sprintf(cmdline2, "cmd /c %s", cmdline);
1047
AddUserToTokenDacl(restrictedToken);
1050
if (!CreateProcessAsUser(restrictedToken,
1062
fprintf(stderr, _("could not start process for \"%s\": error code %lu\n"),
1063
cmdline2, GetLastError());
1069
ResumeThread(pi.hThread);
1070
CloseHandle(pi.hThread);
1076
* Count bytes in file
1079
file_size(const char *file)
1082
FILE *f = fopen(file, "r");
1086
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1087
progname, file, strerror(errno));
1090
fseek(f, 0, SEEK_END);
1097
* Count lines in file
1100
file_line_count(const char *file)
1104
FILE *f = fopen(file, "r");
1108
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1109
progname, file, strerror(errno));
1112
while ((c = fgetc(f)) != EOF)
1122
file_exists(const char *file)
1124
FILE *f = fopen(file, "r");
1133
directory_exists(const char *dir)
1137
if (stat(dir, &st) != 0)
1139
if (S_ISDIR(st.st_mode))
1144
/* Create a directory */
1146
make_directory(const char *dir)
1148
if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1150
fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1151
progname, dir, strerror(errno));
1157
* In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1160
get_alternative_expectfile(const char *expectfile, int i)
1163
int ssize = strlen(expectfile) + 2 + 1;
1164
char *tmp = (char *) malloc(ssize);
1165
char *s = (char *) malloc(ssize);
1167
strcpy(tmp, expectfile);
1168
last_dot = strrchr(tmp, '.');
1176
snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1182
* Run a "diff" command and also check that it didn't crash
1185
run_diff(const char *cmd, const char *filename)
1190
if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1192
fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1198
* On WIN32, if the 'diff' command cannot be found, system() returns 1,
1199
* but produces nothing to stdout, so we check for that here.
1201
if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1203
fprintf(stderr, _("diff command not found: %s\n"), cmd);
1208
return WEXITSTATUS(r);
1212
* Check the actual result file for the given test against expected results
1214
* Returns true if different (failure), false if correct match found.
1215
* In the true case, the diff is appended to the diffs file.
1218
results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1220
char expectfile[MAXPGPATH];
1221
char diff[MAXPGPATH];
1222
char cmd[MAXPGPATH * 3];
1223
char best_expect_file[MAXPGPATH];
1225
int best_line_count;
1228
const char *platform_expectfile;
1231
* We can pass either the resultsfile or the expectfile, they should have
1232
* the same type (filename.type) anyway.
1234
platform_expectfile = get_expectfile(testname, resultsfile);
1236
strlcpy(expectfile, default_expectfile, sizeof(expectfile));
1237
if (platform_expectfile)
1240
* Replace everything afer the last slash in expectfile with what the
1241
* platform_expectfile contains.
1243
char *p = strrchr(expectfile, '/');
1246
strcpy(++p, platform_expectfile);
1249
/* Name to use for temporary diff file */
1250
snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1252
/* OK, run the diff */
1253
snprintf(cmd, sizeof(cmd),
1254
SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1255
basic_diff_opts, expectfile, resultsfile, diff);
1257
/* Is the diff file empty? */
1258
if (run_diff(cmd, diff) == 0)
1264
/* There may be secondary comparison files that match better */
1265
best_line_count = file_line_count(diff);
1266
strcpy(best_expect_file, expectfile);
1268
for (i = 0; i <= 9; i++)
1270
char *alt_expectfile;
1272
alt_expectfile = get_alternative_expectfile(expectfile, i);
1273
if (!file_exists(alt_expectfile))
1276
snprintf(cmd, sizeof(cmd),
1277
SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1278
basic_diff_opts, alt_expectfile, resultsfile, diff);
1280
if (run_diff(cmd, diff) == 0)
1286
l = file_line_count(diff);
1287
if (l < best_line_count)
1289
/* This diff was a better match than the last one */
1290
best_line_count = l;
1291
strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
1293
free(alt_expectfile);
1297
* fall back on the canonical results file if we haven't tried it yet and
1298
* haven't found a complete match yet.
1301
if (platform_expectfile)
1303
snprintf(cmd, sizeof(cmd),
1304
SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1305
basic_diff_opts, default_expectfile, resultsfile, diff);
1307
if (run_diff(cmd, diff) == 0)
1309
/* No diff = no changes = good */
1314
l = file_line_count(diff);
1315
if (l < best_line_count)
1317
/* This diff was a better match than the last one */
1318
best_line_count = l;
1319
strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
1324
* Use the best comparison file to generate the "pretty" diff, which we
1325
* append to the diffs summary file.
1327
snprintf(cmd, sizeof(cmd),
1328
SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
1329
pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1330
run_diff(cmd, difffilename);
1332
/* And append a separator */
1333
difffile = fopen(difffilename, "a");
1337
"\n======================================================================\n\n");
1346
* Wait for specified subprocesses to finish, and return their exit
1347
* statuses into statuses[]
1349
* If names isn't NULL, print each subprocess's name as it finishes
1351
* Note: it's OK to scribble on the pids array, but not on the names array
1354
wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
1360
PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1362
memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1365
tests_left = num_tests;
1366
while (tests_left > 0)
1373
p = wait(&exit_status);
1375
if (p == INVALID_PID)
1377
fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1385
r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1386
if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1388
fprintf(stderr, _("failed to wait for subprocesses: error code %lu\n"),
1392
p = active_pids[r - WAIT_OBJECT_0];
1393
/* compact the active_pids array */
1394
active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1397
for (i = 0; i < num_tests; i++)
1402
GetExitCodeProcess(pids[i], &exit_status);
1403
CloseHandle(pids[i]);
1405
pids[i] = INVALID_PID;
1406
statuses[i] = (int) exit_status;
1408
status(" %s", names[i]);
1421
* report nonzero exit code from a test process
1424
log_child_failure(int exitstatus)
1426
if (WIFEXITED(exitstatus))
1427
status(_(" (test process exited with exit code %d)"),
1428
WEXITSTATUS(exitstatus));
1429
else if (WIFSIGNALED(exitstatus))
1432
status(_(" (test process was terminated by exception 0x%X)"),
1433
WTERMSIG(exitstatus));
1434
#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1435
status(_(" (test process was terminated by signal %d: %s)"),
1436
WTERMSIG(exitstatus),
1437
WTERMSIG(exitstatus) < NSIG ?
1438
sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
1440
status(_(" (test process was terminated by signal %d)"),
1441
WTERMSIG(exitstatus));
1445
status(_(" (test process exited with unrecognized status %d)"),
1450
* Run all the tests specified in one schedule file
1453
run_schedule(const char *schedule, test_function tfunc)
1455
#define MAX_PARALLEL_TESTS 100
1456
char *tests[MAX_PARALLEL_TESTS];
1457
_stringlist *resultfiles[MAX_PARALLEL_TESTS];
1458
_stringlist *expectfiles[MAX_PARALLEL_TESTS];
1459
_stringlist *tags[MAX_PARALLEL_TESTS];
1460
PID_TYPE pids[MAX_PARALLEL_TESTS];
1461
int statuses[MAX_PARALLEL_TESTS];
1462
_stringlist *ignorelist = NULL;
1467
memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1468
memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1469
memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1471
scf = fopen(schedule, "r");
1474
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1475
progname, schedule, strerror(errno));
1479
while (fgets(scbuf, sizeof(scbuf), scf))
1489
for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1491
if (resultfiles[i] == NULL)
1493
free_stringlist(&resultfiles[i]);
1494
free_stringlist(&expectfiles[i]);
1495
free_stringlist(&tags[i]);
1498
/* strip trailing whitespace, especially the newline */
1500
while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1503
if (scbuf[0] == '\0' || scbuf[0] == '#')
1505
if (strncmp(scbuf, "test: ", 6) == 0)
1507
else if (strncmp(scbuf, "ignore: ", 8) == 0)
1510
while (*c && isspace((unsigned char) *c))
1512
add_stringlist_item(&ignorelist, c);
1515
* Note: ignore: lines do not run the test, they just say that
1516
* failure of this test when run later on is to be ignored. A bit
1517
* odd but that's how the shell-script version did it.
1523
fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1524
schedule, line_num, scbuf);
1530
for (c = test; *c; c++)
1532
if (isspace((unsigned char) *c))
1539
if (num_tests >= MAX_PARALLEL_TESTS)
1541
/* can't print scbuf here, it's already been trashed */
1542
fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1543
schedule, line_num);
1546
tests[num_tests] = c;
1554
fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1555
schedule, line_num, scbuf);
1561
status(_("test %-24s ... "), tests[0]);
1562
pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1563
wait_for_tests(pids, statuses, NULL, 1);
1564
/* status line is finished below */
1566
else if (max_connections > 0 && max_connections < num_tests)
1570
status(_("parallel group (%d tests, in groups of %d): "),
1571
num_tests, max_connections);
1572
for (i = 0; i < num_tests; i++)
1574
if (i - oldest >= max_connections)
1576
wait_for_tests(pids + oldest, statuses + oldest,
1577
tests + oldest, i - oldest);
1580
pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1582
wait_for_tests(pids + oldest, statuses + oldest,
1583
tests + oldest, i - oldest);
1588
status(_("parallel group (%d tests): "), num_tests);
1589
for (i = 0; i < num_tests; i++)
1591
pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1593
wait_for_tests(pids, statuses, tests, num_tests);
1597
/* Check results for all tests */
1598
for (i = 0; i < num_tests; i++)
1603
bool differ = false;
1606
status(_(" %-24s ... "), tests[i]);
1609
* Advance over all three lists simultaneously.
1611
* Compare resultfiles[j] with expectfiles[j] always. Tags are
1612
* optional but if there are tags, the tag list has the same
1613
* length as the other two lists.
1615
for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1616
rl != NULL; /* rl and el have the same length */
1617
rl = rl->next, el = el->next)
1622
tl = tl->next; /* tl has the same length as rl and el
1625
newdiff = results_differ(tests[i], rl->str, el->str);
1628
printf("%s ", tl->str);
1635
bool ignore = false;
1638
for (sl = ignorelist; sl != NULL; sl = sl->next)
1640
if (strcmp(tests[i], sl->str) == 0)
1648
status(_("failed (ignored)"));
1649
fail_ignore_count++;
1653
status(_("FAILED"));
1663
if (statuses[i] != 0)
1664
log_child_failure(statuses[i]);
1677
run_single_test(const char *test, test_function tfunc)
1681
_stringlist *resultfiles = NULL;
1682
_stringlist *expectfiles = NULL;
1683
_stringlist *tags = NULL;
1687
bool differ = false;
1689
status(_("test %-24s ... "), test);
1690
pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
1691
wait_for_tests(&pid, &exit_status, NULL, 1);
1694
* Advance over all three lists simultaneously.
1696
* Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1697
* but if there are tags, the tag list has the same length as the other
1700
for (rl = resultfiles, el = expectfiles, tl = tags;
1701
rl != NULL; /* rl and el have the same length */
1702
rl = rl->next, el = el->next)
1707
tl = tl->next; /* tl has the same length as rl and el if it
1710
newdiff = results_differ(test, rl->str, el->str);
1713
printf("%s ", tl->str);
1720
status(_("FAILED"));
1729
if (exit_status != 0)
1730
log_child_failure(exit_status);
1736
* Create the summary-output files (making them empty if already existing)
1739
open_result_files(void)
1741
char file[MAXPGPATH];
1744
/* create the log file (copy of running status output) */
1745
snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1746
logfilename = strdup(file);
1747
logfile = fopen(logfilename, "w");
1750
fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1751
progname, logfilename, strerror(errno));
1755
/* create the diffs file as empty */
1756
snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1757
difffilename = strdup(file);
1758
difffile = fopen(difffilename, "w");
1761
fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1762
progname, difffilename, strerror(errno));
1765
/* we don't keep the diffs file open continuously */
1768
/* also create the output directory if not present */
1769
snprintf(file, sizeof(file), "%s/results", outputdir);
1770
if (!directory_exists(file))
1771
make_directory(file);
1775
drop_database_if_exists(const char *dbname)
1777
header(_("dropping database \"%s\""), dbname);
1778
psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1782
create_database(const char *dbname)
1787
* We use template0 so that any installation-local cruft in template1 will
1788
* not mess up the tests.
1790
header(_("creating database \"%s\""), dbname);
1792
psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
1793
(nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1795
psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
1796
(nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
1797
psql_command(dbname,
1798
"ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1799
"ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1800
"ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1801
"ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1802
"ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1803
dbname, dbname, dbname, dbname, dbname);
1806
* Install any requested procedural languages. We use CREATE OR REPLACE
1807
* so that this will work whether or not the language is preinstalled.
1809
for (sl = loadlanguage; sl != NULL; sl = sl->next)
1811
header(_("installing %s"), sl->str);
1812
psql_command(dbname, "CREATE OR REPLACE LANGUAGE \"%s\"", sl->str);
1816
* Install any requested extensions. We use CREATE IF NOT EXISTS so that
1817
* this will work whether or not the extension is preinstalled.
1819
for (sl = loadextension; sl != NULL; sl = sl->next)
1821
header(_("installing %s"), sl->str);
1822
psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
1827
drop_role_if_exists(const char *rolename)
1829
header(_("dropping role \"%s\""), rolename);
1830
psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1834
create_role(const char *rolename, const _stringlist * granted_dbs)
1836
header(_("creating role \"%s\""), rolename);
1837
psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
1838
for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
1840
psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1841
granted_dbs->str, rolename);
1846
make_absolute_path(const char *in)
1850
if (is_absolute_path(in))
1851
result = strdup(in);
1854
static char cwdbuf[MAXPGPATH];
1858
if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1860
fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1865
result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1866
sprintf(result, "%s/%s", cwdbuf, in);
1869
canonicalize_path(result);
1876
printf(_("PostgreSQL regression test driver\n"));
1878
printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
1880
printf(_("Options:\n"));
1881
printf(_(" --create-role=ROLE create the specified role before testing\n"));
1882
printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1883
printf(_(" --debug turn on debug mode in programs that are run\n"));
1884
printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1885
printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
1886
printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1887
printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
1888
printf(_(" --load-extension=EXT load the named extension before running the\n"));
1889
printf(_(" tests; can appear multiple times\n"));
1890
printf(_(" --load-language=LANG load the named language before running the\n"));
1891
printf(_(" tests; can appear multiple times\n"));
1892
printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1893
printf(_(" (default is 0, meaning unlimited)\n"));
1894
printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1895
printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1896
printf(_(" (can be used multiple times to concatenate)\n"));
1897
printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1898
printf(_(" --use-existing use an existing installation\n"));
1900
printf(_("Options for \"temp-install\" mode:\n"));
1901
printf(_(" --extra-install=DIR additional directory to install (e.g., contrib)\n"));
1902
printf(_(" --no-locale use C locale\n"));
1903
printf(_(" --port=PORT start postmaster on PORT\n"));
1904
printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
1905
printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1907
printf(_("Options for using an existing installation:\n"));
1908
printf(_(" --host=HOST use postmaster running on HOST\n"));
1909
printf(_(" --port=PORT use postmaster running at PORT\n"));
1910
printf(_(" --user=USER connect as USER\n"));
1911
printf(_(" --psqldir=DIR use psql in DIR (default: configured bindir)\n"));
1913
printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1914
printf(_("if the tests could not be run for some reason.\n"));
1916
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1920
regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1922
static struct option long_options[] = {
1923
{"help", no_argument, NULL, 'h'},
1924
{"version", no_argument, NULL, 'V'},
1925
{"dbname", required_argument, NULL, 1},
1926
{"debug", no_argument, NULL, 2},
1927
{"inputdir", required_argument, NULL, 3},
1928
{"load-language", required_argument, NULL, 4},
1929
{"max-connections", required_argument, NULL, 5},
1930
{"encoding", required_argument, NULL, 6},
1931
{"outputdir", required_argument, NULL, 7},
1932
{"schedule", required_argument, NULL, 8},
1933
{"temp-install", required_argument, NULL, 9},
1934
{"no-locale", no_argument, NULL, 10},
1935
{"top-builddir", required_argument, NULL, 11},
1936
{"host", required_argument, NULL, 13},
1937
{"port", required_argument, NULL, 14},
1938
{"user", required_argument, NULL, 15},
1939
{"psqldir", required_argument, NULL, 16},
1940
{"dlpath", required_argument, NULL, 17},
1941
{"create-role", required_argument, NULL, 18},
1942
{"temp-config", required_argument, NULL, 19},
1943
{"use-existing", no_argument, NULL, 20},
1944
{"launcher", required_argument, NULL, 21},
1945
{"load-extension", required_argument, NULL, 22},
1946
{"extra-install", required_argument, NULL, 23},
1954
char buf[MAXPGPATH * 4];
1955
char buf2[MAXPGPATH * 4];
1957
progname = get_progname(argv[0]);
1958
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
1960
atexit(stop_postmaster);
1962
#ifndef HAVE_UNIX_SOCKETS
1963
/* no unix domain sockets available, so change default */
1964
hostname = "localhost";
1968
* We call the initialization function here because that way we can set
1969
* default parameters and let them be overwritten by the commandline.
1973
if (getenv("PG_REGRESS_DIFF_OPTS"))
1974
pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
1976
while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1984
puts("pg_regress (PostgreSQL) " PG_VERSION);
1989
* If a default database was specified, we need to remove it
1990
* before we add the specified one.
1992
free_stringlist(&dblist);
1993
split_to_stringlist(strdup(optarg), ", ", &dblist);
1999
inputdir = strdup(optarg);
2002
add_stringlist_item(&loadlanguage, optarg);
2005
max_connections = atoi(optarg);
2008
encoding = strdup(optarg);
2011
outputdir = strdup(optarg);
2014
add_stringlist_item(&schedulelist, optarg);
2017
temp_install = make_absolute_path(optarg);
2023
top_builddir = strdup(optarg);
2026
hostname = strdup(optarg);
2029
port = atoi(optarg);
2030
port_specified_by_user = true;
2033
user = strdup(optarg);
2036
/* "--psqldir=" should mean to use PATH */
2038
psqldir = strdup(optarg);
2041
dlpath = strdup(optarg);
2044
split_to_stringlist(strdup(optarg), ", ", &extraroles);
2047
temp_config = strdup(optarg);
2050
use_existing = true;
2053
launcher = strdup(optarg);
2056
add_stringlist_item(&loadextension, optarg);
2059
add_stringlist_item(&extra_install, optarg);
2062
/* getopt_long already emitted a complaint */
2063
fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2070
* if we still have arguments, they are extra tests to run
2072
while (argc - optind >= 1)
2074
add_stringlist_item(&extra_tests, argv[optind]);
2078
if (temp_install && !port_specified_by_user)
2081
* To reduce chances of interference with parallel installations, use
2082
* a port number starting in the private range (49152-65535)
2083
* calculated from the version number.
2085
port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2087
inputdir = make_absolute_path(inputdir);
2088
outputdir = make_absolute_path(outputdir);
2089
dlpath = make_absolute_path(dlpath);
2094
open_result_files();
2096
initialize_environment();
2098
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2099
unlimit_core_size();
2108
* Prepare the temp installation
2112
fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2116
if (directory_exists(temp_install))
2118
header(_("removing existing temp installation"));
2119
rmtree(temp_install, true);
2122
header(_("creating temporary installation"));
2124
/* make the temp install top directory */
2125
make_directory(temp_install);
2127
/* and a directory for log files */
2128
snprintf(buf, sizeof(buf), "%s/log", outputdir);
2129
if (!directory_exists(buf))
2130
make_directory(buf);
2132
/* "make install" */
2133
#ifndef WIN32_ONLY_COMPILER
2134
snprintf(buf, sizeof(buf),
2135
SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2136
makeprog, top_builddir, temp_install, outputdir);
2138
snprintf(buf, sizeof(buf),
2139
SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2140
top_builddir, temp_install, outputdir);
2144
fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2148
for (sl = extra_install; sl != NULL; sl = sl->next)
2150
#ifndef WIN32_ONLY_COMPILER
2151
snprintf(buf, sizeof(buf),
2152
SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2153
makeprog, top_builddir, sl->str, temp_install, outputdir);
2155
fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
2161
fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2167
header(_("initializing database system"));
2168
snprintf(buf, sizeof(buf),
2169
SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
2170
bindir, temp_install, datadir,
2171
debug ? " --debug" : "",
2172
nolocale ? " --no-locale" : "",
2176
fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2181
* Adjust the default postgresql.conf as needed for regression
2182
* testing. The user can specify a file to be appended; in any case we
2183
* set max_prepared_transactions to enable testing of prepared xacts.
2184
* (Note: to reduce the probability of unexpected shmmax failures,
2185
* don't set max_prepared_transactions any higher than actually needed
2186
* by the prepared_xacts regression test.)
2188
snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
2189
pg_conf = fopen(buf, "a");
2190
if (pg_conf == NULL)
2192
fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2195
fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2196
fputs("max_prepared_transactions = 2\n", pg_conf);
2198
if (temp_config != NULL)
2201
char line_buf[1024];
2203
extra_conf = fopen(temp_config, "r");
2204
if (extra_conf == NULL)
2206
fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2209
while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2210
fputs(line_buf, pg_conf);
2217
* Check if there is a postmaster running already.
2219
snprintf(buf2, sizeof(buf2),
2220
SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
2221
bindir, DEVNULL, DEVNULL);
2223
for (i = 0; i < 16; i++)
2225
if (system(buf2) == 0)
2229
if (port_specified_by_user || i == 15)
2231
fprintf(stderr, _("port %d apparently in use\n"), port);
2232
if (!port_specified_by_user)
2233
fprintf(stderr, _("%s: could not determine an available port\n"), progname);
2234
fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2238
fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2240
sprintf(s, "%d", port);
2241
doputenv("PGPORT", s);
2248
* Start the temp postmaster
2250
header(_("starting postmaster"));
2251
snprintf(buf, sizeof(buf),
2252
SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
2253
bindir, temp_install,
2254
debug ? " -d 5" : "",
2255
hostname ? hostname : "",
2257
postmaster_pid = spawn_process(buf);
2258
if (postmaster_pid == INVALID_PID)
2260
fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2261
progname, strerror(errno));
2266
* Wait till postmaster is able to accept connections (normally only a
2267
* second or so, but Cygwin is reportedly *much* slower). Don't wait
2270
for (i = 0; i < 60; i++)
2272
/* Done if psql succeeds */
2273
if (system(buf2) == 0)
2277
* Fail immediately if postmaster has exited
2280
if (kill(postmaster_pid, 0) != 0)
2282
if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2285
fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2289
pg_usleep(1000000L);
2293
fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2296
* If we get here, the postmaster is probably wedged somewhere in
2297
* startup. Try to kill it ungracefully rather than leaving a
2298
* stuck postmaster that might interfere with subsequent test
2302
if (kill(postmaster_pid, SIGKILL) != 0 &&
2304
fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2305
progname, strerror(errno));
2307
if (TerminateProcess(postmaster_pid, 255) == 0)
2308
fprintf(stderr, _("\n%s: could not kill failed postmaster: error code %lu\n"),
2309
progname, GetLastError());
2315
postmaster_running = true;
2318
/* need a series of two casts to convert HANDLE without compiler warning */
2319
#define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2321
#define ULONGPID(x) (unsigned long) (x)
2323
printf(_("running on port %d with PID %lu\n"),
2324
port, ULONGPID(postmaster_pid));
2329
* Using an existing installation, so may need to get rid of
2330
* pre-existing database(s) and role(s)
2334
for (sl = dblist; sl; sl = sl->next)
2335
drop_database_if_exists(sl->str);
2336
for (sl = extraroles; sl; sl = sl->next)
2337
drop_role_if_exists(sl->str);
2342
* Create the test database(s) and role(s)
2346
for (sl = dblist; sl; sl = sl->next)
2347
create_database(sl->str);
2348
for (sl = extraroles; sl; sl = sl->next)
2349
create_role(sl->str, dblist);
2353
* Ready to run the tests
2355
header(_("running regression test queries"));
2357
for (sl = schedulelist; sl != NULL; sl = sl->next)
2359
run_schedule(sl->str, tfunc);
2362
for (sl = extra_tests; sl != NULL; sl = sl->next)
2364
run_single_test(sl->str, tfunc);
2368
* Shut down temp installation's postmaster
2372
header(_("shutting down postmaster"));
2379
* Emit nice-looking summary message
2381
if (fail_count == 0 && fail_ignore_count == 0)
2382
snprintf(buf, sizeof(buf),
2383
_(" All %d tests passed. "),
2385
else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2386
snprintf(buf, sizeof(buf),
2387
_(" %d of %d tests passed, %d failed test(s) ignored. "),
2389
success_count + fail_ignore_count,
2391
else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2392
snprintf(buf, sizeof(buf),
2393
_(" %d of %d tests failed. "),
2395
success_count + fail_count);
2397
/* fail_count>0 && fail_ignore_count>0 */
2398
snprintf(buf, sizeof(buf),
2399
_(" %d of %d tests failed, %d of these failures ignored. "),
2400
fail_count + fail_ignore_count,
2401
success_count + fail_count + fail_ignore_count,
2405
for (i = strlen(buf); i > 0; i--)
2407
printf("\n%s\n", buf);
2408
for (i = strlen(buf); i > 0; i--)
2413
if (file_size(difffilename) > 0)
2415
printf(_("The differences that caused some tests to fail can be viewed in the\n"
2416
"file \"%s\". A copy of the test summary that you see\n"
2417
"above is saved in the file \"%s\".\n\n"),
2418
difffilename, logfilename);
2422
unlink(difffilename);
2423
unlink(logfilename);
2426
if (fail_count != 0)