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-2009, 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 bool nolocale
= false;
87 static char *hostname
= NULL
;
89 static bool port_specified_by_user
= false;
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];
276 /* On Windows, system() seems not to force fflush, so... */
280 snprintf(buf
, sizeof(buf
),
281 SYSTEMQUOTE
"\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE
,
282 bindir
, temp_install
);
286 fprintf(stderr
, _("\n%s: could not stop postmaster: exit code was %d\n"),
288 exit(2); /* not exit_nicely(), that would be recursive */
291 postmaster_running
= false;
296 * Always exit through here, not through plain exit(), to ensure we make
297 * an effort to shut down a temp postmaster
300 exit_nicely(int code
)
307 * Check whether string matches pattern
309 * In the original shell script, this function was implemented using expr(1),
310 * which provides basic regular expressions restricted to match starting at
311 * the string start (in conventional regex terms, there's an implicit "^"
312 * at the start of the pattern --- but no implicit "$" at the end).
314 * For now, we only support "." and ".*" as non-literal metacharacters,
315 * because that's all that anyone has found use for in resultmap. This
316 * code could be extended if more functionality is needed.
319 string_matches_pattern(const char *str
, const char *pattern
)
321 while (*str
&& *pattern
)
323 if (*pattern
== '.' && pattern
[1] == '*')
326 /* Trailing .* matches everything. */
327 if (*pattern
== '\0')
331 * Otherwise, scan for a text position at which we can match the
332 * rest of the pattern.
337 * Optimization to prevent most recursion: don't recurse
338 * unless first pattern char might match this text char.
340 if (*str
== *pattern
|| *pattern
== '.')
342 if (string_matches_pattern(str
, pattern
))
350 * End of text with no match.
354 else if (*pattern
!= '.' && *str
!= *pattern
)
357 * Not the single-character wildcard and no explicit match? Then
367 if (*pattern
== '\0')
368 return true; /* end of pattern, so declare match */
370 /* End of input string. Do we have matching pattern remaining? */
371 while (*pattern
== '.' && pattern
[1] == '*')
373 if (*pattern
== '\0')
374 return true; /* end of pattern, so declare match */
380 * Replace all occurances of a string in a string with a different string.
381 * NOTE: Assumes there is enough room in the target buffer!
384 replace_string(char *string
, char *replace
, char *replacement
)
388 while ((ptr
= strstr(string
, replace
)) != NULL
)
390 char *dup
= strdup(string
);
392 strlcpy(string
, dup
, ptr
- string
+ 1);
393 strcat(string
, replacement
);
394 strcat(string
, dup
+ (ptr
- string
) + strlen(replace
));
400 * Convert *.source found in the "source" directory, replacing certain tokens
401 * in the file contents with their intended values, and put the resulting files
402 * in the "dest" directory, replacing the ".source" prefix in their names with
406 convert_sourcefiles_in(char *source_subdir
, char *dest_subdir
, char *suffix
)
408 char testtablespace
[MAXPGPATH
];
409 char indir
[MAXPGPATH
];
416 snprintf(indir
, MAXPGPATH
, "%s/%s", inputdir
, source_subdir
);
418 /* Check that indir actually exists and is a directory */
419 ret
= stat(indir
, &st
);
420 if (ret
!= 0 || !S_ISDIR(st
.st_mode
))
423 * No warning, to avoid noise in tests that do not have these
424 * directories; for example, ecpg, contrib and src/pl.
429 names
= pgfnames(indir
);
431 /* Error logged in pgfnames */
434 snprintf(testtablespace
, MAXPGPATH
, "%s/testtablespace", outputdir
);
439 * On Windows only, clean out the test tablespace dir, or create it if it
440 * doesn't exist. On other platforms we expect the Makefile to take care
441 * of that. (We don't migrate that functionality in here because it'd be
442 * harder to cope with platform-specific issues such as SELinux.)
444 * XXX it would be better if pg_regress.c had nothing at all to do with
445 * testtablespace, and this were handled by a .BAT file or similar on
446 * Windows. See pgsql-hackers discussion of 2008-01-18.
448 if (directory_exists(testtablespace
))
449 rmtree(testtablespace
, true);
450 make_directory(testtablespace
);
453 /* finally loop on each file and do the replacement */
454 for (name
= names
; *name
; name
++)
456 char srcfile
[MAXPGPATH
];
457 char destfile
[MAXPGPATH
];
458 char prefix
[MAXPGPATH
];
463 /* reject filenames not finishing in ".source" */
464 if (strlen(*name
) < 8)
466 if (strcmp(*name
+ strlen(*name
) - 7, ".source") != 0)
471 /* build the full actual paths to open */
472 snprintf(prefix
, strlen(*name
) - 6, "%s", *name
);
473 snprintf(srcfile
, MAXPGPATH
, "%s/%s", indir
, *name
);
474 snprintf(destfile
, MAXPGPATH
, "%s/%s.%s", dest_subdir
, prefix
, suffix
);
476 infile
= fopen(srcfile
, "r");
479 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
480 progname
, srcfile
, strerror(errno
));
483 outfile
= fopen(destfile
, "w");
486 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
487 progname
, destfile
, strerror(errno
));
490 while (fgets(line
, sizeof(line
), infile
))
492 replace_string(line
, "@abs_srcdir@", inputdir
);
493 replace_string(line
, "@abs_builddir@", outputdir
);
494 replace_string(line
, "@testtablespace@", testtablespace
);
495 replace_string(line
, "@libdir@", dlpath
);
496 replace_string(line
, "@DLSUFFIX@", DLSUFFIX
);
497 fputs(line
, outfile
);
504 * If we didn't process any files, complain because it probably means
505 * somebody neglected to pass the needed --inputdir argument.
509 fprintf(stderr
, _("%s: no *.source files found in \"%s\"\n"),
514 pgfnames_cleanup(names
);
517 /* Create the .sql and .out files from the .source files, if any */
519 convert_sourcefiles(void)
521 convert_sourcefiles_in("input", "sql", "sql");
522 convert_sourcefiles_in("output", "expected", "out");
526 * Scan resultmap file to find which platform-specific expected files to use.
528 * The format of each line of the file is
529 * testname/hostplatformpattern=substitutefile
530 * where the hostplatformpattern is evaluated per the rules of expr(1),
531 * namely, it is a standard regular expression with an implicit ^ at the start.
532 * (We currently support only a very limited subset of regular expressions,
533 * see string_matches_pattern() above.) What hostplatformpattern will be
534 * matched against is the config.guess output. (In the shell-script version,
535 * we also provided an indication of whether gcc or another compiler was in
536 * use, but that facility isn't used anymore.)
544 /* scan the file ... */
545 snprintf(buf
, sizeof(buf
), "%s/resultmap", inputdir
);
549 /* OK if it doesn't exist, else complain */
552 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
553 progname
, buf
, strerror(errno
));
557 while (fgets(buf
, sizeof(buf
), f
))
564 /* strip trailing whitespace, especially the newline */
566 while (i
> 0 && isspace((unsigned char) buf
[i
- 1]))
569 /* parse out the line fields */
570 file_type
= strchr(buf
, ':');
573 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
579 platform
= strchr(file_type
, ':');
582 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
587 expected
= strchr(platform
, '=');
590 fprintf(stderr
, _("incorrectly formatted resultmap entry: %s\n"),
597 * if it's for current platform, save it in resultmap list. Note: by
598 * adding at the front of the list, we ensure that in ambiguous cases,
599 * the last match in the resultmap file is used. This mimics the
600 * behavior of the old shell script.
602 if (string_matches_pattern(host_platform
, platform
))
604 _resultmap
*entry
= malloc(sizeof(_resultmap
));
606 entry
->test
= strdup(buf
);
607 entry
->type
= strdup(file_type
);
608 entry
->resultfile
= strdup(expected
);
609 entry
->next
= resultmap
;
617 * Check in resultmap if we should be looking at a different file
621 get_expectfile(const char *testname
, const char *file
)
627 * Determine the file type from the file name. This is just what is
628 * following the last dot in the file name.
630 if (!file
|| !(file_type
= strrchr(file
, '.')))
635 for (rm
= resultmap
; rm
!= NULL
; rm
= rm
->next
)
637 if (strcmp(testname
, rm
->test
) == 0 && strcmp(file_type
, rm
->type
) == 0)
639 return rm
->resultfile
;
647 * Handy subroutine for setting an environment variable "var" to "val"
650 doputenv(const char *var
, const char *val
)
652 char *s
= malloc(strlen(var
) + strlen(val
) + 2);
654 sprintf(s
, "%s=%s", var
, val
);
659 * Set the environment variable "pathname", prepending "addval" to its
660 * old value (if any).
663 add_to_path(const char *pathname
, char separator
, const char *addval
)
665 char *oldval
= getenv(pathname
);
668 if (!oldval
|| !oldval
[0])
670 /* no previous value */
671 newval
= malloc(strlen(pathname
) + strlen(addval
) + 2);
672 sprintf(newval
, "%s=%s", pathname
, addval
);
676 newval
= malloc(strlen(pathname
) + strlen(addval
) + strlen(oldval
) + 3);
677 sprintf(newval
, "%s=%s%c%s", pathname
, addval
, separator
, oldval
);
683 * Prepare environment variables for running regression tests
686 initialize_environment(void)
693 * Clear out any non-C locale settings
695 unsetenv("LC_COLLATE");
696 unsetenv("LC_CTYPE");
697 unsetenv("LC_MONETARY");
698 unsetenv("LC_NUMERIC");
701 /* On Windows the default locale cannot be English, so force it */
702 #if defined(WIN32) || defined(__CYGWIN__)
708 * Set translation-related settings to English; otherwise psql will
709 * produce translated messages and produce diffs. (XXX If we ever support
710 * translation of pg_regress, this needs to be moved elsewhere, where psql
711 * is actually called.)
713 unsetenv("LANGUAGE");
715 putenv("LC_MESSAGES=C");
718 * Set multibyte as requested
721 doputenv("PGCLIENTENCODING", encoding
);
723 unsetenv("PGCLIENTENCODING");
726 * Set timezone and datestyle for datetime-related tests
728 putenv("PGTZ=PST8PDT");
729 putenv("PGDATESTYLE=Postgres, MDY");
732 * Likewise set intervalstyle to ensure consistent results. This is a bit
733 * more painful because we must use PGOPTIONS, and we want to preserve the
734 * user's ability to set other variables through that.
737 const char *my_pgoptions
= "-c intervalstyle=postgres_verbose";
738 const char *old_pgoptions
= getenv("PGOPTIONS");
743 new_pgoptions
= malloc(strlen(old_pgoptions
) + strlen(my_pgoptions
) + 12);
744 sprintf(new_pgoptions
, "PGOPTIONS=%s %s", old_pgoptions
, my_pgoptions
);
745 putenv(new_pgoptions
);
751 * Clear out any environment vars that might cause psql to connect to
752 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
753 * we also use psql's -X switch consistently, so that ~/.psqlrc files
754 * won't mess things up.) Also, set PGPORT to the temp port, and set
755 * or unset PGHOST depending on whether we are using TCP or Unix
758 unsetenv("PGDATABASE");
760 unsetenv("PGSERVICE");
761 unsetenv("PGSSLMODE");
762 unsetenv("PGREQUIRESSL");
763 unsetenv("PGCONNECT_TIMEOUT");
765 if (hostname
!= NULL
)
766 doputenv("PGHOST", hostname
);
769 unsetenv("PGHOSTADDR");
774 sprintf(s
, "%d", port
);
775 doputenv("PGPORT", s
);
779 * Adjust path variables to point into the temp-install tree
781 tmp
= malloc(strlen(temp_install
) + 32 + strlen(bindir
));
782 sprintf(tmp
, "%s/install/%s", temp_install
, bindir
);
785 tmp
= malloc(strlen(temp_install
) + 32 + strlen(libdir
));
786 sprintf(tmp
, "%s/install/%s", temp_install
, libdir
);
789 tmp
= malloc(strlen(temp_install
) + 32 + strlen(datadir
));
790 sprintf(tmp
, "%s/install/%s", temp_install
, datadir
);
793 /* psql will be installed into temp-install bindir */
797 * Set up shared library paths to include the temp install.
799 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
800 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
801 * Windows needs shared libraries in PATH (only those linked into
802 * executables, not dlopen'ed ones). Feel free to account for others
805 add_to_path("LD_LIBRARY_PATH", ':', libdir
);
806 add_to_path("DYLD_LIBRARY_PATH", ':', libdir
);
807 add_to_path("LIBPATH", ':', libdir
);
808 #if defined(WIN32) || defined(__CYGWIN__)
809 add_to_path("PATH", ';', libdir
);
818 * When testing an existing install, we honor existing environment
819 * variables, except if they're overridden by command line options.
821 if (hostname
!= NULL
)
823 doputenv("PGHOST", hostname
);
824 unsetenv("PGHOSTADDR");
830 sprintf(s
, "%d", port
);
831 doputenv("PGPORT", s
);
834 doputenv("PGUSER", user
);
837 * Report what we're connecting to
839 pghost
= getenv("PGHOST");
840 pgport
= getenv("PGPORT");
841 #ifndef HAVE_UNIX_SOCKETS
843 pghost
= "localhost";
846 if (pghost
&& pgport
)
847 printf(_("(using postmaster on %s, port %s)\n"), pghost
, pgport
);
848 if (pghost
&& !pgport
)
849 printf(_("(using postmaster on %s, default port)\n"), pghost
);
850 if (!pghost
&& pgport
)
851 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport
);
852 if (!pghost
&& !pgport
)
853 printf(_("(using postmaster on Unix socket, default port)\n"));
856 convert_sourcefiles();
861 * Issue a command via psql, connecting to the specified database
863 * Since we use system(), this doesn't return until the operation finishes
866 psql_command(const char *database
, const char *query
,...)
868 char query_formatted
[1024];
869 char query_escaped
[2048];
870 char psql_cmd
[MAXPGPATH
+ 2048];
875 /* Generate the query with insertion of sprintf arguments */
876 va_start(args
, query
);
877 vsnprintf(query_formatted
, sizeof(query_formatted
), query
, args
);
880 /* Now escape any shell double-quote metacharacters */
882 for (s
= query_formatted
; *s
; s
++)
884 if (strchr("\\\"$`", *s
))
890 /* And now we can build and execute the shell command */
891 snprintf(psql_cmd
, sizeof(psql_cmd
),
892 SYSTEMQUOTE
"\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE
,
893 psqldir
? psqldir
: "",
898 if (system(psql_cmd
) != 0)
900 /* psql probably already reported the error */
901 fprintf(stderr
, _("command failed: %s\n"), psql_cmd
);
907 * Spawn a process to execute the given shell command; don't wait for it
909 * Returns the process ID (or HANDLE) so we can wait for it later
912 spawn_process(const char *cmdline
)
918 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
919 * ... does anyone still care about systems where that doesn't work?
929 fprintf(stderr
, _("%s: could not fork: %s\n"),
930 progname
, strerror(errno
));
938 * Instead of using system(), exec the shell directly, and tell it to
939 * "exec" the command too. This saves two useless processes per
940 * parallel test case.
942 char *cmdline2
= malloc(strlen(cmdline
) + 6);
944 sprintf(cmdline2
, "exec %s", cmdline
);
945 execl(shellprog
, shellprog
, "-c", cmdline2
, (char *) NULL
);
946 fprintf(stderr
, _("%s: could not exec \"%s\": %s\n"),
947 progname
, shellprog
, strerror(errno
));
948 exit(1); /* not exit_nicely here... */
956 PROCESS_INFORMATION pi
;
958 HANDLE restrictedToken
;
959 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
960 SID_AND_ATTRIBUTES dropSids
[2];
961 __CreateRestrictedToken _CreateRestrictedToken
= NULL
;
962 HANDLE Advapi32Handle
;
964 ZeroMemory(&si
, sizeof(si
));
967 Advapi32Handle
= LoadLibrary("ADVAPI32.DLL");
968 if (Advapi32Handle
!= NULL
)
970 _CreateRestrictedToken
= (__CreateRestrictedToken
) GetProcAddress(Advapi32Handle
, "CreateRestrictedToken");
973 if (_CreateRestrictedToken
== NULL
)
975 if (Advapi32Handle
!= NULL
)
976 FreeLibrary(Advapi32Handle
);
977 fprintf(stderr
, _("%s: cannot create restricted tokens on this platform\n"),
982 /* Open the current token to use as base for the restricted one */
983 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS
, &origToken
))
985 fprintf(stderr
, _("could not open process token: %lu\n"),
990 /* Allocate list of SIDs to remove */
991 ZeroMemory(&dropSids
, sizeof(dropSids
));
992 if (!AllocateAndInitializeSid(&NtAuthority
, 2,
993 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &dropSids
[0].Sid
) ||
994 !AllocateAndInitializeSid(&NtAuthority
, 2,
995 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_POWER_USERS
, 0, 0, 0, 0, 0, 0, &dropSids
[1].Sid
))
997 fprintf(stderr
, _("could not allocate SIDs: %lu\n"), GetLastError());
1001 b
= _CreateRestrictedToken(origToken
,
1002 DISABLE_MAX_PRIVILEGE
,
1003 sizeof(dropSids
) / sizeof(dropSids
[0]),
1009 FreeSid(dropSids
[1].Sid
);
1010 FreeSid(dropSids
[0].Sid
);
1011 CloseHandle(origToken
);
1012 FreeLibrary(Advapi32Handle
);
1016 fprintf(stderr
, _("could not create restricted token: %lu\n"),
1021 cmdline2
= malloc(strlen(cmdline
) + 8);
1022 sprintf(cmdline2
, "cmd /c %s", cmdline
);
1024 if (!CreateProcessAsUser(restrictedToken
,
1036 fprintf(stderr
, _("could not start process for \"%s\": %lu\n"),
1037 cmdline2
, GetLastError());
1042 AddUserToDacl(pi
.hProcess
);
1047 ResumeThread(pi
.hThread
);
1048 CloseHandle(pi
.hThread
);
1054 * Count bytes in file
1057 file_size(const char *file
)
1060 FILE *f
= fopen(file
, "r");
1064 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
1065 progname
, file
, strerror(errno
));
1068 fseek(f
, 0, SEEK_END
);
1075 * Count lines in file
1078 file_line_count(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 while ((c
= fgetc(f
)) != EOF
)
1100 file_exists(const char *file
)
1102 FILE *f
= fopen(file
, "r");
1111 directory_exists(const char *dir
)
1115 if (stat(dir
, &st
) != 0)
1117 if (S_ISDIR(st
.st_mode
))
1122 /* Create a directory */
1124 make_directory(const char *dir
)
1126 if (mkdir(dir
, S_IRWXU
| S_IRWXG
| S_IRWXO
) < 0)
1128 fprintf(stderr
, _("%s: could not create directory \"%s\": %s\n"),
1129 progname
, dir
, strerror(errno
));
1135 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1138 get_alternative_expectfile(const char *expectfile
, int i
)
1141 int ssize
= strlen(expectfile
) + 2 + 1;
1142 char *tmp
= (char *) malloc(ssize
);
1143 char *s
= (char *) malloc(ssize
);
1145 strcpy(tmp
, expectfile
);
1146 last_dot
= strrchr(tmp
, '.');
1154 snprintf(s
, ssize
, "%s_%d.%s", tmp
, i
, last_dot
+ 1);
1160 * Run a "diff" command and also check that it didn't crash
1163 run_diff(const char *cmd
, const char *filename
)
1168 if (!WIFEXITED(r
) || WEXITSTATUS(r
) > 1)
1170 fprintf(stderr
, _("diff command failed with status %d: %s\n"), r
, cmd
);
1176 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1177 * but produces nothing to stdout, so we check for that here.
1179 if (WEXITSTATUS(r
) == 1 && file_size(filename
) <= 0)
1181 fprintf(stderr
, _("diff command not found: %s\n"), cmd
);
1186 return WEXITSTATUS(r
);
1190 * Check the actual result file for the given test against expected results
1192 * Returns true if different (failure), false if correct match found.
1193 * In the true case, the diff is appended to the diffs file.
1196 results_differ(const char *testname
, const char *resultsfile
, const char *default_expectfile
)
1198 char expectfile
[MAXPGPATH
];
1199 char diff
[MAXPGPATH
];
1200 char cmd
[MAXPGPATH
* 3];
1201 char best_expect_file
[MAXPGPATH
];
1203 int best_line_count
;
1206 const char *platform_expectfile
;
1209 * We can pass either the resultsfile or the expectfile, they should have
1210 * the same type (filename.type) anyway.
1212 platform_expectfile
= get_expectfile(testname
, resultsfile
);
1214 strcpy(expectfile
, default_expectfile
);
1215 if (platform_expectfile
)
1218 * Replace everything afer the last slash in expectfile with what the
1219 * platform_expectfile contains.
1221 char *p
= strrchr(expectfile
, '/');
1224 strcpy(++p
, platform_expectfile
);
1227 /* Name to use for temporary diff file */
1228 snprintf(diff
, sizeof(diff
), "%s.diff", resultsfile
);
1230 /* OK, run the diff */
1231 snprintf(cmd
, sizeof(cmd
),
1232 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1233 basic_diff_opts
, expectfile
, resultsfile
, diff
);
1235 /* Is the diff file empty? */
1236 if (run_diff(cmd
, diff
) == 0)
1242 /* There may be secondary comparison files that match better */
1243 best_line_count
= file_line_count(diff
);
1244 strcpy(best_expect_file
, expectfile
);
1246 for (i
= 0; i
<= 9; i
++)
1248 char *alt_expectfile
;
1250 alt_expectfile
= get_alternative_expectfile(expectfile
, i
);
1251 if (!file_exists(alt_expectfile
))
1254 snprintf(cmd
, sizeof(cmd
),
1255 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1256 basic_diff_opts
, alt_expectfile
, resultsfile
, diff
);
1258 if (run_diff(cmd
, diff
) == 0)
1264 l
= file_line_count(diff
);
1265 if (l
< best_line_count
)
1267 /* This diff was a better match than the last one */
1268 best_line_count
= l
;
1269 strcpy(best_expect_file
, alt_expectfile
);
1271 free(alt_expectfile
);
1275 * fall back on the canonical results file if we haven't tried it yet and
1276 * haven't found a complete match yet.
1279 if (platform_expectfile
)
1281 snprintf(cmd
, sizeof(cmd
),
1282 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE
,
1283 basic_diff_opts
, default_expectfile
, resultsfile
, diff
);
1285 if (run_diff(cmd
, diff
) == 0)
1287 /* No diff = no changes = good */
1292 l
= file_line_count(diff
);
1293 if (l
< best_line_count
)
1295 /* This diff was a better match than the last one */
1296 best_line_count
= l
;
1297 strcpy(best_expect_file
, default_expectfile
);
1302 * Use the best comparison file to generate the "pretty" diff, which we
1303 * append to the diffs summary file.
1305 snprintf(cmd
, sizeof(cmd
),
1306 SYSTEMQUOTE
"diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE
,
1307 pretty_diff_opts
, best_expect_file
, resultsfile
, difffilename
);
1308 run_diff(cmd
, difffilename
);
1310 /* And append a separator */
1311 difffile
= fopen(difffilename
, "a");
1315 "\n======================================================================\n\n");
1324 * Wait for specified subprocesses to finish, and return their exit
1325 * statuses into statuses[]
1327 * If names isn't NULL, print each subprocess's name as it finishes
1329 * Note: it's OK to scribble on the pids array, but not on the names array
1332 wait_for_tests(PID_TYPE
* pids
, int *statuses
, char **names
, int num_tests
)
1338 PID_TYPE
*active_pids
= malloc(num_tests
* sizeof(PID_TYPE
));
1340 memcpy(active_pids
, pids
, num_tests
* sizeof(PID_TYPE
));
1343 tests_left
= num_tests
;
1344 while (tests_left
> 0)
1351 p
= wait(&exit_status
);
1353 if (p
== INVALID_PID
)
1355 fprintf(stderr
, _("failed to wait for subprocesses: %s\n"),
1363 r
= WaitForMultipleObjects(tests_left
, active_pids
, FALSE
, INFINITE
);
1364 if (r
< WAIT_OBJECT_0
|| r
>= WAIT_OBJECT_0
+ tests_left
)
1366 fprintf(stderr
, _("failed to wait for subprocesses: %lu\n"),
1370 p
= active_pids
[r
- WAIT_OBJECT_0
];
1371 /* compact the active_pids array */
1372 active_pids
[r
- WAIT_OBJECT_0
] = active_pids
[tests_left
- 1];
1375 for (i
= 0; i
< num_tests
; i
++)
1380 GetExitCodeProcess(pids
[i
], &exit_status
);
1381 CloseHandle(pids
[i
]);
1383 pids
[i
] = INVALID_PID
;
1384 statuses
[i
] = (int) exit_status
;
1386 status(" %s", names
[i
]);
1399 * report nonzero exit code from a test process
1402 log_child_failure(int exitstatus
)
1404 if (WIFEXITED(exitstatus
))
1405 status(_(" (test process exited with exit code %d)"),
1406 WEXITSTATUS(exitstatus
));
1407 else if (WIFSIGNALED(exitstatus
))
1410 status(_(" (test process was terminated by exception 0x%X)"),
1411 WTERMSIG(exitstatus
));
1412 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1413 status(_(" (test process was terminated by signal %d: %s)"),
1414 WTERMSIG(exitstatus
),
1415 WTERMSIG(exitstatus
) < NSIG
?
1416 sys_siglist
[WTERMSIG(exitstatus
)] : "(unknown))");
1418 status(_(" (test process was terminated by signal %d)"),
1419 WTERMSIG(exitstatus
));
1423 status(_(" (test process exited with unrecognized status %d)"),
1428 * Run all the tests specified in one schedule file
1431 run_schedule(const char *schedule
, test_function tfunc
)
1433 #define MAX_PARALLEL_TESTS 100
1434 char *tests
[MAX_PARALLEL_TESTS
];
1435 _stringlist
*resultfiles
[MAX_PARALLEL_TESTS
];
1436 _stringlist
*expectfiles
[MAX_PARALLEL_TESTS
];
1437 _stringlist
*tags
[MAX_PARALLEL_TESTS
];
1438 PID_TYPE pids
[MAX_PARALLEL_TESTS
];
1439 int statuses
[MAX_PARALLEL_TESTS
];
1440 _stringlist
*ignorelist
= NULL
;
1445 memset(resultfiles
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1446 memset(expectfiles
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1447 memset(tags
, 0, sizeof(_stringlist
*) * MAX_PARALLEL_TESTS
);
1449 scf
= fopen(schedule
, "r");
1452 fprintf(stderr
, _("%s: could not open file \"%s\" for reading: %s\n"),
1453 progname
, schedule
, strerror(errno
));
1457 while (fgets(scbuf
, sizeof(scbuf
), scf
))
1467 for (i
= 0; i
< MAX_PARALLEL_TESTS
; i
++)
1469 if (resultfiles
[i
] == NULL
)
1471 free_stringlist(&resultfiles
[i
]);
1472 free_stringlist(&expectfiles
[i
]);
1473 free_stringlist(&tags
[i
]);
1476 /* strip trailing whitespace, especially the newline */
1478 while (i
> 0 && isspace((unsigned char) scbuf
[i
- 1]))
1481 if (scbuf
[0] == '\0' || scbuf
[0] == '#')
1483 if (strncmp(scbuf
, "test: ", 6) == 0)
1485 else if (strncmp(scbuf
, "ignore: ", 8) == 0)
1488 while (*c
&& isspace((unsigned char) *c
))
1490 add_stringlist_item(&ignorelist
, c
);
1493 * Note: ignore: lines do not run the test, they just say that
1494 * failure of this test when run later on is to be ignored. A bit
1495 * odd but that's how the shell-script version did it.
1501 fprintf(stderr
, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1502 schedule
, line_num
, scbuf
);
1508 for (c
= test
; *c
; c
++)
1510 if (isspace((unsigned char) *c
))
1517 if (num_tests
>= MAX_PARALLEL_TESTS
)
1519 /* can't print scbuf here, it's already been trashed */
1520 fprintf(stderr
, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1521 schedule
, line_num
);
1524 tests
[num_tests
] = c
;
1532 fprintf(stderr
, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1533 schedule
, line_num
, scbuf
);
1539 status(_("test %-20s ... "), tests
[0]);
1540 pids
[0] = (tfunc
) (tests
[0], &resultfiles
[0], &expectfiles
[0], &tags
[0]);
1541 wait_for_tests(pids
, statuses
, NULL
, 1);
1542 /* status line is finished below */
1544 else if (max_connections
> 0 && max_connections
< num_tests
)
1548 status(_("parallel group (%d tests, in groups of %d): "),
1549 num_tests
, max_connections
);
1550 for (i
= 0; i
< num_tests
; i
++)
1552 if (i
- oldest
>= max_connections
)
1554 wait_for_tests(pids
+ oldest
, statuses
+ oldest
,
1555 tests
+ oldest
, i
- oldest
);
1558 pids
[i
] = (tfunc
) (tests
[i
], &resultfiles
[i
], &expectfiles
[i
], &tags
[i
]);
1560 wait_for_tests(pids
+ oldest
, statuses
+ oldest
,
1561 tests
+ oldest
, i
- oldest
);
1566 status(_("parallel group (%d tests): "), num_tests
);
1567 for (i
= 0; i
< num_tests
; i
++)
1569 pids
[i
] = (tfunc
) (tests
[i
], &resultfiles
[i
], &expectfiles
[i
], &tags
[i
]);
1571 wait_for_tests(pids
, statuses
, tests
, num_tests
);
1575 /* Check results for all tests */
1576 for (i
= 0; i
< num_tests
; i
++)
1581 bool differ
= false;
1584 status(_(" %-20s ... "), tests
[i
]);
1587 * Advance over all three lists simultaneously.
1589 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1590 * optional but if there are tags, the tag list has the same
1591 * length as the other two lists.
1593 for (rl
= resultfiles
[i
], el
= expectfiles
[i
], tl
= tags
[i
];
1594 rl
!= NULL
; /* rl and el have the same length */
1595 rl
= rl
->next
, el
= el
->next
)
1600 tl
= tl
->next
; /* tl has the same length as rl and el
1603 newdiff
= results_differ(tests
[i
], rl
->str
, el
->str
);
1606 printf("%s ", tl
->str
);
1613 bool ignore
= false;
1616 for (sl
= ignorelist
; sl
!= NULL
; sl
= sl
->next
)
1618 if (strcmp(tests
[i
], sl
->str
) == 0)
1626 status(_("failed (ignored)"));
1627 fail_ignore_count
++;
1631 status(_("FAILED"));
1641 if (statuses
[i
] != 0)
1642 log_child_failure(statuses
[i
]);
1655 run_single_test(const char *test
, test_function tfunc
)
1659 _stringlist
*resultfiles
= NULL
;
1660 _stringlist
*expectfiles
= NULL
;
1661 _stringlist
*tags
= NULL
;
1665 bool differ
= false;
1667 status(_("test %-20s ... "), test
);
1668 pid
= (tfunc
) (test
, &resultfiles
, &expectfiles
, &tags
);
1669 wait_for_tests(&pid
, &exit_status
, NULL
, 1);
1672 * Advance over all three lists simultaneously.
1674 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1675 * but if there are tags, the tag list has the same length as the other
1678 for (rl
= resultfiles
, el
= expectfiles
, tl
= tags
;
1679 rl
!= NULL
; /* rl and el have the same length */
1680 rl
= rl
->next
, el
= el
->next
)
1685 tl
= tl
->next
; /* tl has the same length as rl and el if it
1688 newdiff
= results_differ(test
, rl
->str
, el
->str
);
1691 printf("%s ", tl
->str
);
1698 status(_("FAILED"));
1707 if (exit_status
!= 0)
1708 log_child_failure(exit_status
);
1714 * Create the summary-output files (making them empty if already existing)
1717 open_result_files(void)
1719 char file
[MAXPGPATH
];
1722 /* create the log file (copy of running status output) */
1723 snprintf(file
, sizeof(file
), "%s/regression.out", outputdir
);
1724 logfilename
= strdup(file
);
1725 logfile
= fopen(logfilename
, "w");
1728 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
1729 progname
, logfilename
, strerror(errno
));
1733 /* create the diffs file as empty */
1734 snprintf(file
, sizeof(file
), "%s/regression.diffs", outputdir
);
1735 difffilename
= strdup(file
);
1736 difffile
= fopen(difffilename
, "w");
1739 fprintf(stderr
, _("%s: could not open file \"%s\" for writing: %s\n"),
1740 progname
, difffilename
, strerror(errno
));
1743 /* we don't keep the diffs file open continuously */
1746 /* also create the output directory if not present */
1747 snprintf(file
, sizeof(file
), "%s/results", outputdir
);
1748 if (!directory_exists(file
))
1749 make_directory(file
);
1753 drop_database_if_exists(const char *dbname
)
1755 header(_("dropping database \"%s\""), dbname
);
1756 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname
);
1760 create_database(const char *dbname
)
1765 * We use template0 so that any installation-local cruft in template1 will
1766 * not mess up the tests.
1768 header(_("creating database \"%s\""), dbname
);
1770 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname
, encoding
);
1772 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0", dbname
);
1773 psql_command(dbname
,
1774 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1775 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1776 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1777 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1778 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1779 dbname
, dbname
, dbname
, dbname
, dbname
);
1782 * Install any requested procedural languages
1784 for (sl
= loadlanguage
; sl
!= NULL
; sl
= sl
->next
)
1786 header(_("installing %s"), sl
->str
);
1787 psql_command(dbname
, "CREATE LANGUAGE \"%s\"", sl
->str
);
1792 drop_role_if_exists(const char *rolename
)
1794 header(_("dropping role \"%s\""), rolename
);
1795 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename
);
1799 create_role(const char *rolename
, const _stringlist
* granted_dbs
)
1801 header(_("creating role \"%s\""), rolename
);
1802 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename
);
1803 for (; granted_dbs
!= NULL
; granted_dbs
= granted_dbs
->next
)
1805 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1806 granted_dbs
->str
, rolename
);
1811 make_absolute_path(const char *in
)
1815 if (is_absolute_path(in
))
1816 result
= strdup(in
);
1819 static char cwdbuf
[MAXPGPATH
];
1823 if (!getcwd(cwdbuf
, sizeof(cwdbuf
)))
1825 fprintf(stderr
, _("could not get current working directory: %s\n"), strerror(errno
));
1830 result
= malloc(strlen(cwdbuf
) + strlen(in
) + 2);
1831 sprintf(result
, "%s/%s", cwdbuf
, in
);
1834 canonicalize_path(result
);
1841 printf(_("PostgreSQL regression test driver\n"));
1843 printf(_("Usage: %s [options...] [extra tests...]\n"), progname
);
1845 printf(_("Options:\n"));
1846 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1847 printf(_(" --debug turn on debug mode in programs that are run\n"));
1848 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1849 printf(_(" --load-language=lang load the named language before running the\n"));
1850 printf(_(" tests; can appear multiple times\n"));
1851 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1852 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1853 printf(_(" (default is 0 meaning unlimited)\n"));
1854 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1855 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1856 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1857 printf(_(" (can be used multiple times to concatenate)\n"));
1858 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1859 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1861 printf(_("Options for \"temp-install\" mode:\n"));
1862 printf(_(" --no-locale use C locale\n"));
1863 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1864 printf(_(" --port=PORT start postmaster on PORT\n"));
1865 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1867 printf(_("Options for using an existing installation:\n"));
1868 printf(_(" --host=HOST use postmaster running on HOST\n"));
1869 printf(_(" --port=PORT use postmaster running at PORT\n"));
1870 printf(_(" --user=USER connect as USER\n"));
1871 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1873 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1874 printf(_("if the tests could not be run for some reason.\n"));
1876 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1880 regression_main(int argc
, char *argv
[], init_function ifunc
, test_function tfunc
)
1886 char buf
[MAXPGPATH
* 4];
1887 char buf2
[MAXPGPATH
* 4];
1889 static struct option long_options
[] = {
1890 {"help", no_argument
, NULL
, 'h'},
1891 {"version", no_argument
, NULL
, 'V'},
1892 {"dbname", required_argument
, NULL
, 1},
1893 {"debug", no_argument
, NULL
, 2},
1894 {"inputdir", required_argument
, NULL
, 3},
1895 {"load-language", required_argument
, NULL
, 4},
1896 {"max-connections", required_argument
, NULL
, 5},
1897 {"multibyte", required_argument
, NULL
, 6},
1898 {"outputdir", required_argument
, NULL
, 7},
1899 {"schedule", required_argument
, NULL
, 8},
1900 {"temp-install", required_argument
, NULL
, 9},
1901 {"no-locale", no_argument
, NULL
, 10},
1902 {"top-builddir", required_argument
, NULL
, 11},
1903 {"host", required_argument
, NULL
, 13},
1904 {"port", required_argument
, NULL
, 14},
1905 {"user", required_argument
, NULL
, 15},
1906 {"psqldir", required_argument
, NULL
, 16},
1907 {"dlpath", required_argument
, NULL
, 17},
1908 {"create-role", required_argument
, NULL
, 18},
1909 {"temp-config", required_argument
, NULL
, 19},
1913 progname
= get_progname(argv
[0]);
1914 set_pglocale_pgservice(argv
[0], PG_TEXTDOMAIN("pg_regress"));
1916 #ifndef HAVE_UNIX_SOCKETS
1917 /* no unix domain sockets available, so change default */
1918 hostname
= "localhost";
1922 * We call the initialization function here because that way we can set
1923 * default parameters and let them be overwritten by the commandline.
1927 while ((c
= getopt_long(argc
, argv
, "hV", long_options
, &option_index
)) != -1)
1935 puts("pg_regress (PostgreSQL) " PG_VERSION
);
1940 * If a default database was specified, we need to remove it
1941 * before we add the specified one.
1943 free_stringlist(&dblist
);
1944 split_to_stringlist(strdup(optarg
), ", ", &dblist
);
1950 inputdir
= strdup(optarg
);
1953 add_stringlist_item(&loadlanguage
, optarg
);
1956 max_connections
= atoi(optarg
);
1959 encoding
= strdup(optarg
);
1962 outputdir
= strdup(optarg
);
1965 add_stringlist_item(&schedulelist
, optarg
);
1968 temp_install
= make_absolute_path(optarg
);
1974 top_builddir
= strdup(optarg
);
1977 hostname
= strdup(optarg
);
1980 port
= atoi(optarg
);
1981 port_specified_by_user
= true;
1984 user
= strdup(optarg
);
1987 /* "--psqldir=" should mean to use PATH */
1989 psqldir
= strdup(optarg
);
1992 dlpath
= strdup(optarg
);
1995 split_to_stringlist(strdup(optarg
), ", ", &extraroles
);
1998 temp_config
= strdup(optarg
);
2001 /* getopt_long already emitted a complaint */
2002 fprintf(stderr
, _("\nTry \"%s -h\" for more information.\n"),
2009 * if we still have arguments, they are extra tests to run
2011 while (argc
- optind
>= 1)
2013 add_stringlist_item(&extra_tests
, argv
[optind
]);
2017 if (temp_install
&& !port_specified_by_user
)
2020 * To reduce chances of interference with parallel installations, use
2021 * a port number starting in the private range (49152-65535)
2022 * calculated from the version number.
2024 port
= 0xC000 | (PG_VERSION_NUM
& 0x3FFF);
2026 inputdir
= make_absolute_path(inputdir
);
2027 outputdir
= make_absolute_path(outputdir
);
2028 dlpath
= make_absolute_path(dlpath
);
2033 open_result_files();
2035 initialize_environment();
2037 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2038 unlimit_core_size();
2046 * Prepare the temp installation
2050 fprintf(stderr
, _("--top-builddir must be specified when using --temp-install\n"));
2054 if (directory_exists(temp_install
))
2056 header(_("removing existing temp installation"));
2057 rmtree(temp_install
, true);
2060 header(_("creating temporary installation"));
2062 /* make the temp install top directory */
2063 make_directory(temp_install
);
2065 /* and a directory for log files */
2066 snprintf(buf
, sizeof(buf
), "%s/log", outputdir
);
2067 if (!directory_exists(buf
))
2068 make_directory(buf
);
2070 /* "make install" */
2071 #ifndef WIN32_ONLY_COMPILER
2072 snprintf(buf
, sizeof(buf
),
2073 SYSTEMQUOTE
"\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE
,
2074 makeprog
, top_builddir
, temp_install
, outputdir
);
2076 snprintf(buf
, sizeof(buf
),
2077 SYSTEMQUOTE
"perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE
,
2078 top_builddir
, temp_install
, outputdir
);
2082 fprintf(stderr
, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname
, outputdir
, buf
);
2087 header(_("initializing database system"));
2088 snprintf(buf
, sizeof(buf
),
2089 SYSTEMQUOTE
"\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE
,
2090 bindir
, temp_install
, datadir
,
2091 debug
? " --debug" : "",
2092 nolocale
? " --no-locale" : "",
2096 fprintf(stderr
, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname
, outputdir
, buf
);
2101 * Adjust the default postgresql.conf as needed for regression
2102 * testing. The user can specify a file to be appended; in any case we
2103 * set max_prepared_transactions to enable testing of prepared xacts.
2104 * (Note: to reduce the probability of unexpected shmmax failures,
2105 * don't set max_prepared_transactions any higher than actually needed
2106 * by the prepared_xacts regression test.)
2108 snprintf(buf
, sizeof(buf
), "%s/data/postgresql.conf", temp_install
);
2109 pg_conf
= fopen(buf
, "a");
2110 if (pg_conf
== NULL
)
2112 fprintf(stderr
, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname
, buf
, strerror(errno
));
2115 fputs("\n# Configuration added by pg_regress\n\n", pg_conf
);
2116 fputs("max_prepared_transactions = 2\n", pg_conf
);
2118 if (temp_config
!= NULL
)
2121 char line_buf
[1024];
2123 extra_conf
= fopen(temp_config
, "r");
2124 if (extra_conf
== NULL
)
2126 fprintf(stderr
, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname
, temp_config
, strerror(errno
));
2129 while (fgets(line_buf
, sizeof(line_buf
), extra_conf
) != NULL
)
2130 fputs(line_buf
, pg_conf
);
2137 * Check if there is a postmaster running already.
2139 snprintf(buf2
, sizeof(buf2
),
2140 SYSTEMQUOTE
"\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE
,
2141 bindir
, DEVNULL
, DEVNULL
);
2143 for (i
= 0; i
< 16; i
++)
2145 if (system(buf2
) == 0)
2149 if (port_specified_by_user
|| i
== 15)
2151 fprintf(stderr
, _("port %d apparently in use\n"), port
);
2152 if (!port_specified_by_user
)
2153 fprintf(stderr
, _("%s: could not determine an available port\n"), progname
);
2154 fprintf(stderr
, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2158 fprintf(stderr
, _("port %d apparently in use, trying %d\n"), port
, port
+ 1);
2160 sprintf(s
, "%d", port
);
2161 doputenv("PGPORT", s
);
2168 * Start the temp postmaster
2170 header(_("starting postmaster"));
2171 snprintf(buf
, sizeof(buf
),
2172 SYSTEMQUOTE
"\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE
,
2173 bindir
, temp_install
,
2174 debug
? " -d 5" : "",
2175 hostname
? hostname
: "",
2177 postmaster_pid
= spawn_process(buf
);
2178 if (postmaster_pid
== INVALID_PID
)
2180 fprintf(stderr
, _("\n%s: could not spawn postmaster: %s\n"),
2181 progname
, strerror(errno
));
2186 * Wait till postmaster is able to accept connections (normally only a
2187 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2190 for (i
= 0; i
< 60; i
++)
2192 /* Done if psql succeeds */
2193 if (system(buf2
) == 0)
2197 * Fail immediately if postmaster has exited
2200 if (kill(postmaster_pid
, 0) != 0)
2202 if (WaitForSingleObject(postmaster_pid
, 0) == WAIT_OBJECT_0
)
2205 fprintf(stderr
, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname
, outputdir
);
2209 pg_usleep(1000000L);
2213 fprintf(stderr
, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname
, outputdir
);
2216 * If we get here, the postmaster is probably wedged somewhere in
2217 * startup. Try to kill it ungracefully rather than leaving a
2218 * stuck postmaster that might interfere with subsequent test
2222 if (kill(postmaster_pid
, SIGKILL
) != 0 &&
2224 fprintf(stderr
, _("\n%s: could not kill failed postmaster: %s\n"),
2225 progname
, strerror(errno
));
2227 if (TerminateProcess(postmaster_pid
, 255) == 0)
2228 fprintf(stderr
, _("\n%s: could not kill failed postmaster: %lu\n"),
2229 progname
, GetLastError());
2235 postmaster_running
= true;
2237 printf(_("running on port %d with pid %lu\n"),
2238 port
, (unsigned long) postmaster_pid
);
2243 * Using an existing installation, so may need to get rid of
2244 * pre-existing database(s) and role(s)
2246 for (sl
= dblist
; sl
; sl
= sl
->next
)
2247 drop_database_if_exists(sl
->str
);
2248 for (sl
= extraroles
; sl
; sl
= sl
->next
)
2249 drop_role_if_exists(sl
->str
);
2253 * Create the test database(s) and role(s)
2255 for (sl
= dblist
; sl
; sl
= sl
->next
)
2256 create_database(sl
->str
);
2257 for (sl
= extraroles
; sl
; sl
= sl
->next
)
2258 create_role(sl
->str
, dblist
);
2261 * Ready to run the tests
2263 header(_("running regression test queries"));
2265 for (sl
= schedulelist
; sl
!= NULL
; sl
= sl
->next
)
2267 run_schedule(sl
->str
, tfunc
);
2270 for (sl
= extra_tests
; sl
!= NULL
; sl
= sl
->next
)
2272 run_single_test(sl
->str
, tfunc
);
2276 * Shut down temp installation's postmaster
2280 header(_("shutting down postmaster"));
2287 * Emit nice-looking summary message
2289 if (fail_count
== 0 && fail_ignore_count
== 0)
2290 snprintf(buf
, sizeof(buf
),
2291 _(" All %d tests passed. "),
2293 else if (fail_count
== 0) /* fail_count=0, fail_ignore_count>0 */
2294 snprintf(buf
, sizeof(buf
),
2295 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2297 success_count
+ fail_ignore_count
,
2299 else if (fail_ignore_count
== 0) /* fail_count>0 && fail_ignore_count=0 */
2300 snprintf(buf
, sizeof(buf
),
2301 _(" %d of %d tests failed. "),
2303 success_count
+ fail_count
);
2305 /* fail_count>0 && fail_ignore_count>0 */
2306 snprintf(buf
, sizeof(buf
),
2307 _(" %d of %d tests failed, %d of these failures ignored. "),
2308 fail_count
+ fail_ignore_count
,
2309 success_count
+ fail_count
+ fail_ignore_count
,
2313 for (i
= strlen(buf
); i
> 0; i
--)
2315 printf("\n%s\n", buf
);
2316 for (i
= strlen(buf
); i
> 0; i
--)
2321 if (file_size(difffilename
) > 0)
2323 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2324 "file \"%s\". A copy of the test summary that you see\n"
2325 "above is saved in the file \"%s\".\n\n"),
2326 difffilename
, logfilename
);
2330 unlink(difffilename
);
2331 unlink(logfilename
);
2334 if (fail_count
!= 0)