Add test case for CREATE CAST.
[PostgreSQL.git] / src / test / regress / pg_regress.c
blob324c3c085925197ce8e581e729fa9b1f545c7dd3
1 /*-------------------------------------------------------------------------
3 * pg_regress --- regression test driver
5 * This is a C implementation of the previous shell script for running
6 * the regression tests, and should be mostly compatible with it.
7 * Initial author of C translation: Magnus Hagander
9 * This code is released under the terms of the PostgreSQL License.
11 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * $PostgreSQL$
16 *-------------------------------------------------------------------------
19 #include "pg_regress.h"
21 #include <ctype.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25 #include <unistd.h>
27 #ifdef HAVE_SYS_RESOURCE_H
28 #include <sys/time.h>
29 #include <sys/resource.h>
30 #endif
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
38 char *test;
39 char *type;
40 char *resultfile;
41 struct _resultmap *next;
42 } _resultmap;
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;
62 #endif
64 #ifndef WIN32 /* not used in WIN32 case */
65 static char *shellprog = SHELLPROG;
66 #endif
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;
74 bool debug = false;
75 char *inputdir = ".";
76 char *outputdir = ".";
77 char *psqldir = PGBINDIR;
78 static _stringlist *loadlanguage = NULL;
79 static int max_connections = 0;
80 static char *encoding = NULL;
81 static _stringlist *schedulelist = NULL;
82 static _stringlist *extra_tests = NULL;
83 static char *temp_install = NULL;
84 static char *temp_config = NULL;
85 static char *top_builddir = NULL;
86 static int temp_port = 65432;
87 static bool nolocale = false;
88 static char *hostname = NULL;
89 static int port = -1;
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;
97 static FILE *logfile;
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);
112 static void
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)));
117 static void
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)));
122 static void
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)));
128 #ifdef WIN32
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
133 #endif
136 * allow core files if possible.
138 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
139 static void
140 unlimit_core_size(void)
142 struct rlimit lim;
144 getrlimit(RLIMIT_CORE, &lim);
145 if (lim.rlim_max == 0)
147 fprintf(stderr,
148 _("%s: could not set core size: disallowed by hard limit\n"),
149 progname);
150 return;
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);
158 #endif
162 * Add an item at the end of a stringlist.
164 void
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;
174 else
176 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
177 /* skip */ ;
178 oldentry->next = newentry;
183 * Free a stringlist.
185 static void
186 free_stringlist(_stringlist ** listhead)
188 if (listhead == NULL || *listhead == NULL)
189 return;
190 if ((*listhead)->next != NULL)
191 free_stringlist(&((*listhead)->next));
192 free((*listhead)->str);
193 free(*listhead);
194 *listhead = NULL;
198 * Split a delimited string into a stringlist
200 static void
201 split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
203 char *sc = strdup(s);
204 char *token = strtok(sc, delim);
206 while (token)
208 add_stringlist_item(listhead, token);
209 token = strtok(NULL, delim);
211 free(sc);
215 * Print a progress banner on stdout.
217 static void
218 header(const char *fmt,...)
220 char tmp[64];
221 va_list ap;
223 va_start(ap, fmt);
224 vsnprintf(tmp, sizeof(tmp), fmt, ap);
225 va_end(ap);
227 fprintf(stdout, "============== %-38s ==============\n", tmp);
228 fflush(stdout);
232 * Print "doing something ..." --- supplied text should not end with newline
234 static void
235 status(const char *fmt,...)
237 va_list ap;
239 va_start(ap, fmt);
240 vfprintf(stdout, fmt, ap);
241 fflush(stdout);
242 va_end(ap);
244 if (logfile)
246 va_start(ap, fmt);
247 vfprintf(logfile, fmt, ap);
248 va_end(ap);
253 * Done "doing something ..."
255 static void
256 status_end(void)
258 fprintf(stdout, "\n");
259 fflush(stdout);
260 if (logfile)
261 fprintf(logfile, "\n");
265 * shut down temp postmaster
267 static void
268 stop_postmaster(void)
270 if (postmaster_running)
272 /* We use pg_ctl to issue the kill and wait for stop */
273 char buf[MAXPGPATH * 2];
275 /* On Windows, system() seems not to force fflush, so... */
276 fflush(stdout);
277 fflush(stderr);
279 snprintf(buf, sizeof(buf),
280 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
281 bindir, temp_install);
282 system(buf); /* ignore exit status */
283 postmaster_running = false;
288 * Always exit through here, not through plain exit(), to ensure we make
289 * an effort to shut down a temp postmaster
291 void
292 exit_nicely(int code)
294 stop_postmaster();
295 exit(code);
299 * Check whether string matches pattern
301 * In the original shell script, this function was implemented using expr(1),
302 * which provides basic regular expressions restricted to match starting at
303 * the string start (in conventional regex terms, there's an implicit "^"
304 * at the start of the pattern --- but no implicit "$" at the end).
306 * For now, we only support "." and ".*" as non-literal metacharacters,
307 * because that's all that anyone has found use for in resultmap. This
308 * code could be extended if more functionality is needed.
310 static bool
311 string_matches_pattern(const char *str, const char *pattern)
313 while (*str && *pattern)
315 if (*pattern == '.' && pattern[1] == '*')
317 pattern += 2;
318 /* Trailing .* matches everything. */
319 if (*pattern == '\0')
320 return true;
323 * Otherwise, scan for a text position at which we can match the
324 * rest of the pattern.
326 while (*str)
329 * Optimization to prevent most recursion: don't recurse
330 * unless first pattern char might match this text char.
332 if (*str == *pattern || *pattern == '.')
334 if (string_matches_pattern(str, pattern))
335 return true;
338 str++;
342 * End of text with no match.
344 return false;
346 else if (*pattern != '.' && *str != *pattern)
349 * Not the single-character wildcard and no explicit match? Then
350 * time to quit...
352 return false;
355 str++;
356 pattern++;
359 if (*pattern == '\0')
360 return true; /* end of pattern, so declare match */
362 /* End of input string. Do we have matching pattern remaining? */
363 while (*pattern == '.' && pattern[1] == '*')
364 pattern += 2;
365 if (*pattern == '\0')
366 return true; /* end of pattern, so declare match */
368 return false;
372 * Replace all occurances of a string in a string with a different string.
373 * NOTE: Assumes there is enough room in the target buffer!
375 void
376 replace_string(char *string, char *replace, char *replacement)
378 char *ptr;
380 while ((ptr = strstr(string, replace)) != NULL)
382 char *dup = strdup(string);
384 strlcpy(string, dup, ptr - string + 1);
385 strcat(string, replacement);
386 strcat(string, dup + (ptr - string) + strlen(replace));
387 free(dup);
392 * Convert *.source found in the "source" directory, replacing certain tokens
393 * in the file contents with their intended values, and put the resulting files
394 * in the "dest" directory, replacing the ".source" prefix in their names with
395 * the given suffix.
397 static void
398 convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
400 char testtablespace[MAXPGPATH];
401 char indir[MAXPGPATH];
402 struct stat st;
403 int ret;
404 char **name;
405 char **names;
406 int count = 0;
408 snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
410 /* Check that indir actually exists and is a directory */
411 ret = stat(indir, &st);
412 if (ret != 0 || !S_ISDIR(st.st_mode))
415 * No warning, to avoid noise in tests that do not have
416 * these directories; for example, ecpg, contrib and src/pl.
418 return;
421 names = pgfnames(indir);
422 if (!names)
423 /* Error logged in pgfnames */
424 exit_nicely(2);
426 snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
428 #ifdef WIN32
430 * On Windows only, clean out the test tablespace dir, or create it if it
431 * doesn't exist. On other platforms we expect the Makefile to take
432 * care of that. (We don't migrate that functionality in here because
433 * it'd be harder to cope with platform-specific issues such as SELinux.)
435 * XXX it would be better if pg_regress.c had nothing at all to do with
436 * testtablespace, and this were handled by a .BAT file or similar on
437 * Windows. See pgsql-hackers discussion of 2008-01-18.
439 if (directory_exists(testtablespace))
440 rmtree(testtablespace, true);
441 make_directory(testtablespace);
442 #endif
444 /* finally loop on each file and do the replacement */
445 for (name = names; *name; name++)
447 char srcfile[MAXPGPATH];
448 char destfile[MAXPGPATH];
449 char prefix[MAXPGPATH];
450 FILE *infile,
451 *outfile;
452 char line[1024];
454 /* reject filenames not finishing in ".source" */
455 if (strlen(*name) < 8)
456 continue;
457 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
458 continue;
460 count++;
462 /* build the full actual paths to open */
463 snprintf(prefix, strlen(*name) - 6, "%s", *name);
464 snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
465 snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest_subdir, prefix, suffix);
467 infile = fopen(srcfile, "r");
468 if (!infile)
470 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
471 progname, srcfile, strerror(errno));
472 exit_nicely(2);
474 outfile = fopen(destfile, "w");
475 if (!outfile)
477 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
478 progname, destfile, strerror(errno));
479 exit_nicely(2);
481 while (fgets(line, sizeof(line), infile))
483 replace_string(line, "@abs_srcdir@", inputdir);
484 replace_string(line, "@abs_builddir@", outputdir);
485 replace_string(line, "@testtablespace@", testtablespace);
486 replace_string(line, "@libdir@", dlpath);
487 replace_string(line, "@DLSUFFIX@", DLSUFFIX);
488 fputs(line, outfile);
490 fclose(infile);
491 fclose(outfile);
495 * If we didn't process any files, complain because it probably means
496 * somebody neglected to pass the needed --inputdir argument.
498 if (count <= 0)
500 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
501 progname, indir);
502 exit_nicely(2);
505 pgfnames_cleanup(names);
508 /* Create the .sql and .out files from the .source files, if any */
509 static void
510 convert_sourcefiles(void)
512 convert_sourcefiles_in("input", "sql", "sql");
513 convert_sourcefiles_in("output", "expected", "out");
517 * Scan resultmap file to find which platform-specific expected files to use.
519 * The format of each line of the file is
520 * testname/hostplatformpattern=substitutefile
521 * where the hostplatformpattern is evaluated per the rules of expr(1),
522 * namely, it is a standard regular expression with an implicit ^ at the start.
523 * (We currently support only a very limited subset of regular expressions,
524 * see string_matches_pattern() above.) What hostplatformpattern will be
525 * matched against is the config.guess output. (In the shell-script version,
526 * we also provided an indication of whether gcc or another compiler was in
527 * use, but that facility isn't used anymore.)
529 static void
530 load_resultmap(void)
532 char buf[MAXPGPATH];
533 FILE *f;
535 /* scan the file ... */
536 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
537 f = fopen(buf, "r");
538 if (!f)
540 /* OK if it doesn't exist, else complain */
541 if (errno == ENOENT)
542 return;
543 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
544 progname, buf, strerror(errno));
545 exit_nicely(2);
548 while (fgets(buf, sizeof(buf), f))
550 char *platform;
551 char *file_type;
552 char *expected;
553 int i;
555 /* strip trailing whitespace, especially the newline */
556 i = strlen(buf);
557 while (i > 0 && isspace((unsigned char) buf[i - 1]))
558 buf[--i] = '\0';
560 /* parse out the line fields */
561 file_type = strchr(buf, ':');
562 if (!file_type)
564 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
565 buf);
566 exit_nicely(2);
568 *file_type++ = '\0';
570 platform = strchr(file_type, ':');
571 if (!platform)
573 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
574 buf);
575 exit_nicely(2);
577 *platform++ = '\0';
578 expected = strchr(platform, '=');
579 if (!expected)
581 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
582 buf);
583 exit_nicely(2);
585 *expected++ = '\0';
588 * if it's for current platform, save it in resultmap list. Note: by
589 * adding at the front of the list, we ensure that in ambiguous cases,
590 * the last match in the resultmap file is used. This mimics the
591 * behavior of the old shell script.
593 if (string_matches_pattern(host_platform, platform))
595 _resultmap *entry = malloc(sizeof(_resultmap));
597 entry->test = strdup(buf);
598 entry->type = strdup(file_type);
599 entry->resultfile = strdup(expected);
600 entry->next = resultmap;
601 resultmap = entry;
604 fclose(f);
608 * Check in resultmap if we should be looking at a different file
610 static
611 const char *
612 get_expectfile(const char *testname, const char *file)
614 char *file_type;
615 _resultmap *rm;
618 * Determine the file type from the file name. This is just what is
619 * following the last dot in the file name.
621 if (!file || !(file_type = strrchr(file, '.')))
622 return NULL;
624 file_type++;
626 for (rm = resultmap; rm != NULL; rm = rm->next)
628 if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
630 return rm->resultfile;
634 return NULL;
638 * Handy subroutine for setting an environment variable "var" to "val"
640 static void
641 doputenv(const char *var, const char *val)
643 char *s = malloc(strlen(var) + strlen(val) + 2);
645 sprintf(s, "%s=%s", var, val);
646 putenv(s);
650 * Set the environment variable "pathname", prepending "addval" to its
651 * old value (if any).
653 static void
654 add_to_path(const char *pathname, char separator, const char *addval)
656 char *oldval = getenv(pathname);
657 char *newval;
659 if (!oldval || !oldval[0])
661 /* no previous value */
662 newval = malloc(strlen(pathname) + strlen(addval) + 2);
663 sprintf(newval, "%s=%s", pathname, addval);
665 else
667 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
668 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
670 putenv(newval);
674 * Prepare environment variables for running regression tests
676 static void
677 initialize_environment(void)
679 char *tmp;
682 * Clear out any non-C locale settings
684 unsetenv("LC_COLLATE");
685 unsetenv("LC_CTYPE");
686 unsetenv("LC_MONETARY");
687 unsetenv("LC_MESSAGES");
688 unsetenv("LC_NUMERIC");
689 unsetenv("LC_TIME");
690 unsetenv("LC_ALL");
691 unsetenv("LANG");
692 unsetenv("LANGUAGE");
693 /* On Windows the default locale cannot be English, so force it */
694 #if defined(WIN32) || defined(__CYGWIN__)
695 putenv("LANG=en");
696 #endif
699 * Set multibyte as requested
701 if (encoding)
702 doputenv("PGCLIENTENCODING", encoding);
703 else
704 unsetenv("PGCLIENTENCODING");
707 * Set timezone and datestyle for datetime-related tests
709 putenv("PGTZ=PST8PDT");
710 putenv("PGDATESTYLE=Postgres, MDY");
712 if (temp_install)
715 * Clear out any environment vars that might cause psql to connect to
716 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
717 * we also use psql's -X switch consistently, so that ~/.psqlrc files
718 * won't mess things up.) Also, set PGPORT to the temp port, and set
719 * or unset PGHOST depending on whether we are using TCP or Unix
720 * sockets.
722 unsetenv("PGDATABASE");
723 unsetenv("PGUSER");
724 unsetenv("PGSERVICE");
725 unsetenv("PGSSLMODE");
726 unsetenv("PGREQUIRESSL");
727 unsetenv("PGCONNECT_TIMEOUT");
728 unsetenv("PGDATA");
729 if (hostname != NULL)
730 doputenv("PGHOST", hostname);
731 else
732 unsetenv("PGHOST");
733 unsetenv("PGHOSTADDR");
734 if (port != -1)
736 char s[16];
738 sprintf(s, "%d", port);
739 doputenv("PGPORT", s);
743 * Adjust path variables to point into the temp-install tree
745 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
746 sprintf(tmp, "%s/install/%s", temp_install, bindir);
747 bindir = tmp;
749 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
750 sprintf(tmp, "%s/install/%s", temp_install, libdir);
751 libdir = tmp;
753 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
754 sprintf(tmp, "%s/install/%s", temp_install, datadir);
755 datadir = tmp;
757 /* psql will be installed into temp-install bindir */
758 psqldir = bindir;
761 * Set up shared library paths to include the temp install.
763 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
764 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
765 * Windows needs shared libraries in PATH (only those linked into
766 * executables, not dlopen'ed ones). Feel free to account for others
767 * as well.
769 add_to_path("LD_LIBRARY_PATH", ':', libdir);
770 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
771 add_to_path("LIBPATH", ':', libdir);
772 #if defined(WIN32) || defined(__CYGWIN__)
773 add_to_path("PATH", ';', libdir);
774 #endif
776 else
778 const char *pghost;
779 const char *pgport;
782 * When testing an existing install, we honor existing environment
783 * variables, except if they're overridden by command line options.
785 if (hostname != NULL)
787 doputenv("PGHOST", hostname);
788 unsetenv("PGHOSTADDR");
790 if (port != -1)
792 char s[16];
794 sprintf(s, "%d", port);
795 doputenv("PGPORT", s);
797 if (user != NULL)
798 doputenv("PGUSER", user);
801 * Report what we're connecting to
803 pghost = getenv("PGHOST");
804 pgport = getenv("PGPORT");
805 #ifndef HAVE_UNIX_SOCKETS
806 if (!pghost)
807 pghost = "localhost";
808 #endif
810 if (pghost && pgport)
811 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
812 if (pghost && !pgport)
813 printf(_("(using postmaster on %s, default port)\n"), pghost);
814 if (!pghost && pgport)
815 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
816 if (!pghost && !pgport)
817 printf(_("(using postmaster on Unix socket, default port)\n"));
820 convert_sourcefiles();
821 load_resultmap();
825 * Issue a command via psql, connecting to the specified database
827 * Since we use system(), this doesn't return until the operation finishes
829 static void
830 psql_command(const char *database, const char *query,...)
832 char query_formatted[1024];
833 char query_escaped[2048];
834 char psql_cmd[MAXPGPATH + 2048];
835 va_list args;
836 char *s;
837 char *d;
839 /* Generate the query with insertion of sprintf arguments */
840 va_start(args, query);
841 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
842 va_end(args);
844 /* Now escape any shell double-quote metacharacters */
845 d = query_escaped;
846 for (s = query_formatted; *s; s++)
848 if (strchr("\\\"$`", *s))
849 *d++ = '\\';
850 *d++ = *s;
852 *d = '\0';
854 /* And now we can build and execute the shell command */
855 snprintf(psql_cmd, sizeof(psql_cmd),
856 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
857 psqldir ? psqldir : "",
858 psqldir ? "/" : "",
859 query_escaped,
860 database);
862 if (system(psql_cmd) != 0)
864 /* psql probably already reported the error */
865 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
866 exit_nicely(2);
871 * Spawn a process to execute the given shell command; don't wait for it
873 * Returns the process ID (or HANDLE) so we can wait for it later
875 PID_TYPE
876 spawn_process(const char *cmdline)
878 #ifndef WIN32
879 pid_t pid;
882 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
883 * ... does anyone still care about systems where that doesn't work?
885 fflush(stdout);
886 fflush(stderr);
887 if (logfile)
888 fflush(logfile);
890 pid = fork();
891 if (pid == -1)
893 fprintf(stderr, _("%s: could not fork: %s\n"),
894 progname, strerror(errno));
895 exit_nicely(2);
897 if (pid == 0)
900 * In child
902 * Instead of using system(), exec the shell directly, and tell it to
903 * "exec" the command too. This saves two useless processes per
904 * parallel test case.
906 char *cmdline2 = malloc(strlen(cmdline) + 6);
908 sprintf(cmdline2, "exec %s", cmdline);
909 execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
910 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
911 progname, shellprog, strerror(errno));
912 exit(1); /* not exit_nicely here... */
914 /* in parent */
915 return pid;
916 #else
917 char *cmdline2;
918 BOOL b;
919 STARTUPINFO si;
920 PROCESS_INFORMATION pi;
921 HANDLE origToken;
922 HANDLE restrictedToken;
923 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
924 SID_AND_ATTRIBUTES dropSids[2];
925 __CreateRestrictedToken _CreateRestrictedToken = NULL;
926 HANDLE Advapi32Handle;
928 ZeroMemory(&si, sizeof(si));
929 si.cb = sizeof(si);
931 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
932 if (Advapi32Handle != NULL)
934 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
937 if (_CreateRestrictedToken == NULL)
939 if (Advapi32Handle != NULL)
940 FreeLibrary(Advapi32Handle);
941 fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
942 progname);
943 exit_nicely(2);
946 /* Open the current token to use as base for the restricted one */
947 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
949 fprintf(stderr, _("could not open process token: %lu\n"),
950 GetLastError());
951 exit_nicely(2);
954 /* Allocate list of SIDs to remove */
955 ZeroMemory(&dropSids, sizeof(dropSids));
956 if (!AllocateAndInitializeSid(&NtAuthority, 2,
957 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
958 !AllocateAndInitializeSid(&NtAuthority, 2,
959 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
961 fprintf(stderr, _("could not allocate SIDs: %lu\n"), GetLastError());
962 exit_nicely(2);
965 b = _CreateRestrictedToken(origToken,
966 DISABLE_MAX_PRIVILEGE,
967 sizeof(dropSids) / sizeof(dropSids[0]),
968 dropSids,
969 0, NULL,
970 0, NULL,
971 &restrictedToken);
973 FreeSid(dropSids[1].Sid);
974 FreeSid(dropSids[0].Sid);
975 CloseHandle(origToken);
976 FreeLibrary(Advapi32Handle);
978 if (!b)
980 fprintf(stderr, _("could not create restricted token: %lu\n"),
981 GetLastError());
982 exit_nicely(2);
985 cmdline2 = malloc(strlen(cmdline) + 8);
986 sprintf(cmdline2, "cmd /c %s", cmdline);
988 if (!CreateProcessAsUser(restrictedToken,
989 NULL,
990 cmdline2,
991 NULL,
992 NULL,
993 TRUE,
994 CREATE_SUSPENDED,
995 NULL,
996 NULL,
997 &si,
998 &pi))
1000 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
1001 cmdline2, GetLastError());
1002 exit_nicely(2);
1005 #ifndef __CYGWIN__
1006 AddUserToDacl(pi.hProcess);
1007 #endif
1009 free(cmdline2);
1011 ResumeThread(pi.hThread);
1012 CloseHandle(pi.hThread);
1013 return pi.hProcess;
1014 #endif
1018 * Count bytes in file
1020 static long
1021 file_size(const char *file)
1023 long r;
1024 FILE *f = fopen(file, "r");
1026 if (!f)
1028 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1029 progname, file, strerror(errno));
1030 return -1;
1032 fseek(f, 0, SEEK_END);
1033 r = ftell(f);
1034 fclose(f);
1035 return r;
1039 * Count lines in file
1041 static int
1042 file_line_count(const char *file)
1044 int c;
1045 int l = 0;
1046 FILE *f = fopen(file, "r");
1048 if (!f)
1050 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1051 progname, file, strerror(errno));
1052 return -1;
1054 while ((c = fgetc(f)) != EOF)
1056 if (c == '\n')
1057 l++;
1059 fclose(f);
1060 return l;
1063 bool
1064 file_exists(const char *file)
1066 FILE *f = fopen(file, "r");
1068 if (!f)
1069 return false;
1070 fclose(f);
1071 return true;
1074 static bool
1075 directory_exists(const char *dir)
1077 struct stat st;
1079 if (stat(dir, &st) != 0)
1080 return false;
1081 if (S_ISDIR(st.st_mode))
1082 return true;
1083 return false;
1086 /* Create a directory */
1087 static void
1088 make_directory(const char *dir)
1090 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1092 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1093 progname, dir, strerror(errno));
1094 exit_nicely(2);
1099 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1101 static char *
1102 get_alternative_expectfile(const char *expectfile, int i)
1104 char *last_dot;
1105 int ssize = strlen(expectfile) + 2 + 1;
1106 char *tmp = (char *) malloc(ssize);
1107 char *s = (char *) malloc(ssize);
1109 strcpy(tmp, expectfile);
1110 last_dot = strrchr(tmp, '.');
1111 if (!last_dot)
1112 return NULL;
1113 *last_dot = '\0';
1114 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1115 free(tmp);
1116 return s;
1120 * Run a "diff" command and also check that it didn't crash
1122 static int
1123 run_diff(const char *cmd, const char *filename)
1125 int r;
1127 r = system(cmd);
1128 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1130 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1131 exit_nicely(2);
1133 #ifdef WIN32
1136 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1137 * but produces nothing to stdout, so we check for that here.
1139 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1141 fprintf(stderr, _("diff command not found: %s\n"), cmd);
1142 exit_nicely(2);
1144 #endif
1146 return WEXITSTATUS(r);
1150 * Check the actual result file for the given test against expected results
1152 * Returns true if different (failure), false if correct match found.
1153 * In the true case, the diff is appended to the diffs file.
1155 static bool
1156 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1158 char expectfile[MAXPGPATH];
1159 char diff[MAXPGPATH];
1160 char cmd[MAXPGPATH * 3];
1161 char best_expect_file[MAXPGPATH];
1162 FILE *difffile;
1163 int best_line_count;
1164 int i;
1165 int l;
1166 const char *platform_expectfile;
1169 * We can pass either the resultsfile or the expectfile, they should have
1170 * the same type (filename.type) anyway.
1172 platform_expectfile = get_expectfile(testname, resultsfile);
1174 strcpy(expectfile, default_expectfile);
1175 if (platform_expectfile)
1178 * Replace everything afer the last slash in expectfile with what the
1179 * platform_expectfile contains.
1181 char *p = strrchr(expectfile, '/');
1183 if (p)
1184 strcpy(++p, platform_expectfile);
1187 /* Name to use for temporary diff file */
1188 snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1190 /* OK, run the diff */
1191 snprintf(cmd, sizeof(cmd),
1192 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1193 basic_diff_opts, expectfile, resultsfile, diff);
1195 /* Is the diff file empty? */
1196 if (run_diff(cmd, diff) == 0)
1198 unlink(diff);
1199 return false;
1202 /* There may be secondary comparison files that match better */
1203 best_line_count = file_line_count(diff);
1204 strcpy(best_expect_file, expectfile);
1206 for (i = 0; i <= 9; i++)
1208 char *alt_expectfile;
1210 alt_expectfile = get_alternative_expectfile(expectfile, i);
1211 if (!file_exists(alt_expectfile))
1212 continue;
1214 snprintf(cmd, sizeof(cmd),
1215 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1216 basic_diff_opts, alt_expectfile, resultsfile, diff);
1218 if (run_diff(cmd, diff) == 0)
1220 unlink(diff);
1221 return false;
1224 l = file_line_count(diff);
1225 if (l < best_line_count)
1227 /* This diff was a better match than the last one */
1228 best_line_count = l;
1229 strcpy(best_expect_file, alt_expectfile);
1231 free(alt_expectfile);
1235 * fall back on the canonical results file if we haven't tried it yet and
1236 * haven't found a complete match yet.
1239 if (platform_expectfile)
1241 snprintf(cmd, sizeof(cmd),
1242 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1243 basic_diff_opts, default_expectfile, resultsfile, diff);
1245 if (run_diff(cmd, diff) == 0)
1247 /* No diff = no changes = good */
1248 unlink(diff);
1249 return false;
1252 l = file_line_count(diff);
1253 if (l < best_line_count)
1255 /* This diff was a better match than the last one */
1256 best_line_count = l;
1257 strcpy(best_expect_file, default_expectfile);
1262 * Use the best comparison file to generate the "pretty" diff, which we
1263 * append to the diffs summary file.
1265 snprintf(cmd, sizeof(cmd),
1266 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
1267 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1268 run_diff(cmd, difffilename);
1270 /* And append a separator */
1271 difffile = fopen(difffilename, "a");
1272 if (difffile)
1274 fprintf(difffile,
1275 "\n======================================================================\n\n");
1276 fclose(difffile);
1279 unlink(diff);
1280 return true;
1284 * Wait for specified subprocesses to finish, and return their exit
1285 * statuses into statuses[]
1287 * If names isn't NULL, print each subprocess's name as it finishes
1289 * Note: it's OK to scribble on the pids array, but not on the names array
1291 static void
1292 wait_for_tests(PID_TYPE *pids, int *statuses, char **names, int num_tests)
1294 int tests_left;
1295 int i;
1297 #ifdef WIN32
1298 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1300 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1301 #endif
1303 tests_left = num_tests;
1304 while (tests_left > 0)
1306 PID_TYPE p;
1307 int exit_status;
1309 #ifndef WIN32
1310 p = wait(&exit_status);
1312 if (p == INVALID_PID)
1314 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1315 strerror(errno));
1316 exit_nicely(2);
1318 #else
1319 int r;
1321 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1322 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1324 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
1325 GetLastError());
1326 exit_nicely(2);
1328 p = active_pids[r - WAIT_OBJECT_0];
1329 /* compact the active_pids array */
1330 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1331 #endif /* WIN32 */
1333 for (i = 0; i < num_tests; i++)
1335 if (p == pids[i])
1337 #ifdef WIN32
1338 GetExitCodeProcess(pids[i], &exit_status);
1339 CloseHandle(pids[i]);
1340 #endif
1341 pids[i] = INVALID_PID;
1342 statuses[i] = exit_status;
1343 if (names)
1344 status(" %s", names[i]);
1345 tests_left--;
1346 break;
1351 #ifdef WIN32
1352 free(active_pids);
1353 #endif
1357 * report nonzero exit code from a test process
1359 static void
1360 log_child_failure(int exitstatus)
1362 if (WIFEXITED(exitstatus))
1363 status(_(" (test process exited with exit code %d)"),
1364 WEXITSTATUS(exitstatus));
1365 else if (WIFSIGNALED(exitstatus))
1367 #if defined(WIN32)
1368 status(_(" (test process was terminated by exception 0x%X)"),
1369 WTERMSIG(exitstatus));
1370 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1371 status(_(" (test process was terminated by signal %d: %s)"),
1372 WTERMSIG(exitstatus),
1373 WTERMSIG(exitstatus) < NSIG ?
1374 sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
1375 #else
1376 status(_(" (test process was terminated by signal %d)"),
1377 WTERMSIG(exitstatus));
1378 #endif
1380 else
1381 status(_(" (test process exited with unrecognized status %d)"),
1382 exitstatus);
1386 * Run all the tests specified in one schedule file
1388 static void
1389 run_schedule(const char *schedule, test_function tfunc)
1391 #define MAX_PARALLEL_TESTS 100
1392 char *tests[MAX_PARALLEL_TESTS];
1393 _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1394 _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1395 _stringlist *tags[MAX_PARALLEL_TESTS];
1396 PID_TYPE pids[MAX_PARALLEL_TESTS];
1397 int statuses[MAX_PARALLEL_TESTS];
1398 _stringlist *ignorelist = NULL;
1399 char scbuf[1024];
1400 FILE *scf;
1401 int line_num = 0;
1403 memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1404 memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1405 memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1407 scf = fopen(schedule, "r");
1408 if (!scf)
1410 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1411 progname, schedule, strerror(errno));
1412 exit_nicely(2);
1415 while (fgets(scbuf, sizeof(scbuf), scf))
1417 char *test = NULL;
1418 char *c;
1419 int num_tests;
1420 bool inword;
1421 int i;
1423 line_num++;
1425 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1427 if (resultfiles[i] == NULL)
1428 break;
1429 free_stringlist(&resultfiles[i]);
1430 free_stringlist(&expectfiles[i]);
1431 free_stringlist(&tags[i]);
1434 /* strip trailing whitespace, especially the newline */
1435 i = strlen(scbuf);
1436 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1437 scbuf[--i] = '\0';
1439 if (scbuf[0] == '\0' || scbuf[0] == '#')
1440 continue;
1441 if (strncmp(scbuf, "test: ", 6) == 0)
1442 test = scbuf + 6;
1443 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1445 c = scbuf + 8;
1446 while (*c && isspace((unsigned char) *c))
1447 c++;
1448 add_stringlist_item(&ignorelist, c);
1451 * Note: ignore: lines do not run the test, they just say that
1452 * failure of this test when run later on is to be ignored. A bit
1453 * odd but that's how the shell-script version did it.
1455 continue;
1457 else
1459 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1460 schedule, line_num, scbuf);
1461 exit_nicely(2);
1464 num_tests = 0;
1465 inword = false;
1466 for (c = test; *c; c++)
1468 if (isspace((unsigned char) *c))
1470 *c = '\0';
1471 inword = false;
1473 else if (!inword)
1475 if (num_tests >= MAX_PARALLEL_TESTS)
1477 /* can't print scbuf here, it's already been trashed */
1478 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1479 schedule, line_num);
1480 exit_nicely(2);
1482 tests[num_tests] = c;
1483 num_tests++;
1484 inword = true;
1488 if (num_tests == 0)
1490 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1491 schedule, line_num, scbuf);
1492 exit_nicely(2);
1495 if (num_tests == 1)
1497 status(_("test %-20s ... "), tests[0]);
1498 pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1499 wait_for_tests(pids, statuses, NULL, 1);
1500 /* status line is finished below */
1502 else if (max_connections > 0 && max_connections < num_tests)
1504 int oldest = 0;
1506 status(_("parallel group (%d tests, in groups of %d): "),
1507 num_tests, max_connections);
1508 for (i = 0; i < num_tests; i++)
1510 if (i - oldest >= max_connections)
1512 wait_for_tests(pids + oldest, statuses + oldest,
1513 tests + oldest, i - oldest);
1514 oldest = i;
1516 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1518 wait_for_tests(pids + oldest, statuses + oldest,
1519 tests + oldest, i - oldest);
1520 status_end();
1522 else
1524 status(_("parallel group (%d tests): "), num_tests);
1525 for (i = 0; i < num_tests; i++)
1527 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1529 wait_for_tests(pids, statuses, tests, num_tests);
1530 status_end();
1533 /* Check results for all tests */
1534 for (i = 0; i < num_tests; i++)
1536 _stringlist *rl,
1537 *el,
1538 *tl;
1539 bool differ = false;
1541 if (num_tests > 1)
1542 status(_(" %-20s ... "), tests[i]);
1545 * Advance over all three lists simultaneously.
1547 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1548 * optional but if there are tags, the tag list has the same
1549 * length as the other two lists.
1551 for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1552 rl != NULL; /* rl and el have the same length */
1553 rl = rl->next, el = el->next)
1555 bool newdiff;
1557 if (tl)
1558 tl = tl->next; /* tl has the same length as rl and el
1559 * if it exists */
1561 newdiff = results_differ(tests[i], rl->str, el->str);
1562 if (newdiff && tl)
1564 printf("%s ", tl->str);
1566 differ |= newdiff;
1569 if (differ)
1571 bool ignore = false;
1572 _stringlist *sl;
1574 for (sl = ignorelist; sl != NULL; sl = sl->next)
1576 if (strcmp(tests[i], sl->str) == 0)
1578 ignore = true;
1579 break;
1582 if (ignore)
1584 status(_("failed (ignored)"));
1585 fail_ignore_count++;
1587 else
1589 status(_("FAILED"));
1590 fail_count++;
1593 else
1595 status(_("ok"));
1596 success_count++;
1599 if (statuses[i] != 0)
1600 log_child_failure(statuses[i]);
1602 status_end();
1606 fclose(scf);
1610 * Run a single test
1612 static void
1613 run_single_test(const char *test, test_function tfunc)
1615 PID_TYPE pid;
1616 int exit_status;
1617 _stringlist *resultfiles = NULL;
1618 _stringlist *expectfiles = NULL;
1619 _stringlist *tags = NULL;
1620 _stringlist *rl,
1621 *el,
1622 *tl;
1623 bool differ = false;
1625 status(_("test %-20s ... "), test);
1626 pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
1627 wait_for_tests(&pid, &exit_status, NULL, 1);
1630 * Advance over all three lists simultaneously.
1632 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1633 * but if there are tags, the tag list has the same length as the other
1634 * two lists.
1636 for (rl = resultfiles, el = expectfiles, tl = tags;
1637 rl != NULL; /* rl and el have the same length */
1638 rl = rl->next, el = el->next)
1640 bool newdiff;
1642 if (tl)
1643 tl = tl->next; /* tl has the same length as rl and el if it
1644 * exists */
1646 newdiff = results_differ(test, rl->str, el->str);
1647 if (newdiff && tl)
1649 printf("%s ", tl->str);
1651 differ |= newdiff;
1654 if (differ)
1656 status(_("FAILED"));
1657 fail_count++;
1659 else
1661 status(_("ok"));
1662 success_count++;
1665 if (exit_status != 0)
1666 log_child_failure(exit_status);
1668 status_end();
1672 * Create the summary-output files (making them empty if already existing)
1674 static void
1675 open_result_files(void)
1677 char file[MAXPGPATH];
1678 FILE *difffile;
1680 /* create the log file (copy of running status output) */
1681 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1682 logfilename = strdup(file);
1683 logfile = fopen(logfilename, "w");
1684 if (!logfile)
1686 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1687 progname, logfilename, strerror(errno));
1688 exit_nicely(2);
1691 /* create the diffs file as empty */
1692 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1693 difffilename = strdup(file);
1694 difffile = fopen(difffilename, "w");
1695 if (!difffile)
1697 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1698 progname, difffilename, strerror(errno));
1699 exit_nicely(2);
1701 /* we don't keep the diffs file open continuously */
1702 fclose(difffile);
1704 /* also create the output directory if not present */
1705 snprintf(file, sizeof(file), "%s/results", outputdir);
1706 if (!directory_exists(file))
1707 make_directory(file);
1710 static void
1711 drop_database_if_exists(const char *dbname)
1713 header(_("dropping database \"%s\""), dbname);
1714 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1717 static void
1718 create_database(const char *dbname)
1720 _stringlist *sl;
1723 * We use template0 so that any installation-local cruft in template1 will
1724 * not mess up the tests.
1726 header(_("creating database \"%s\""), dbname);
1727 if (encoding)
1728 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname, encoding);
1729 else
1730 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0", dbname);
1731 psql_command(dbname,
1732 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1733 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1734 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1735 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1736 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1737 dbname, dbname, dbname, dbname, dbname);
1740 * Install any requested procedural languages
1742 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1744 header(_("installing %s"), sl->str);
1745 psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
1749 static void
1750 drop_role_if_exists(const char *rolename)
1752 header(_("dropping role \"%s\""), rolename);
1753 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1756 static void
1757 create_role(const char *rolename, const _stringlist * granted_dbs)
1759 header(_("creating role \"%s\""), rolename);
1760 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
1761 for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
1763 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1764 granted_dbs->str, rolename);
1768 static char *
1769 make_absolute_path(const char *in)
1771 char *result;
1773 if (is_absolute_path(in))
1774 result = strdup(in);
1775 else
1777 static char cwdbuf[MAXPGPATH];
1779 if (!cwdbuf[0])
1781 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1783 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1784 exit_nicely(2);
1788 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1789 sprintf(result, "%s/%s", cwdbuf, in);
1792 canonicalize_path(result);
1793 return result;
1796 static void
1797 help(void)
1799 printf(_("PostgreSQL regression test driver\n"));
1800 printf(_("\n"));
1801 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1802 printf(_("\n"));
1803 printf(_("Options:\n"));
1804 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1805 printf(_(" --debug turn on debug mode in programs that are run\n"));
1806 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1807 printf(_(" --load-language=lang load the named language before running the\n"));
1808 printf(_(" tests; can appear multiple times\n"));
1809 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1810 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1811 printf(_(" (default is 0 meaning unlimited)\n"));
1812 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1813 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1814 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1815 printf(_(" (can be used multiple times to concatenate)\n"));
1816 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1817 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1818 printf(_("\n"));
1819 printf(_("Options for \"temp-install\" mode:\n"));
1820 printf(_(" --no-locale use C locale\n"));
1821 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1822 printf(_(" --temp-port=PORT port number to start temp postmaster on\n"));
1823 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1824 printf(_("\n"));
1825 printf(_("Options for using an existing installation:\n"));
1826 printf(_(" --host=HOST use postmaster running on HOST\n"));
1827 printf(_(" --port=PORT use postmaster running at PORT\n"));
1828 printf(_(" --user=USER connect as USER\n"));
1829 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1830 printf(_("\n"));
1831 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1832 printf(_("if the tests could not be run for some reason.\n"));
1833 printf(_("\n"));
1834 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1838 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1840 _stringlist *sl;
1841 int c;
1842 int i;
1843 int option_index;
1844 char buf[MAXPGPATH * 4];
1846 static struct option long_options[] = {
1847 {"help", no_argument, NULL, 'h'},
1848 {"version", no_argument, NULL, 'V'},
1849 {"dbname", required_argument, NULL, 1},
1850 {"debug", no_argument, NULL, 2},
1851 {"inputdir", required_argument, NULL, 3},
1852 {"load-language", required_argument, NULL, 4},
1853 {"max-connections", required_argument, NULL, 5},
1854 {"multibyte", required_argument, NULL, 6},
1855 {"outputdir", required_argument, NULL, 7},
1856 {"schedule", required_argument, NULL, 8},
1857 {"temp-install", required_argument, NULL, 9},
1858 {"no-locale", no_argument, NULL, 10},
1859 {"top-builddir", required_argument, NULL, 11},
1860 {"temp-port", required_argument, NULL, 12},
1861 {"host", required_argument, NULL, 13},
1862 {"port", required_argument, NULL, 14},
1863 {"user", required_argument, NULL, 15},
1864 {"psqldir", required_argument, NULL, 16},
1865 {"dlpath", required_argument, NULL, 17},
1866 {"create-role", required_argument, NULL, 18},
1867 {"temp-config", required_argument, NULL, 19},
1868 {NULL, 0, NULL, 0}
1871 progname = get_progname(argv[0]);
1872 set_pglocale_pgservice(argv[0], "pg_regress");
1874 #ifndef HAVE_UNIX_SOCKETS
1875 /* no unix domain sockets available, so change default */
1876 hostname = "localhost";
1877 #endif
1880 * We call the initialization function here because that way we can set
1881 * default parameters and let them be overwritten by the commandline.
1883 ifunc();
1885 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1887 switch (c)
1889 case 'h':
1890 help();
1891 exit_nicely(0);
1892 case 'V':
1893 puts("pg_regress (PostgreSQL) " PG_VERSION);
1894 exit_nicely(0);
1895 case 1:
1898 * If a default database was specified, we need to remove it
1899 * before we add the specified one.
1901 free_stringlist(&dblist);
1902 split_to_stringlist(strdup(optarg), ", ", &dblist);
1903 break;
1904 case 2:
1905 debug = true;
1906 break;
1907 case 3:
1908 inputdir = strdup(optarg);
1909 break;
1910 case 4:
1911 add_stringlist_item(&loadlanguage, optarg);
1912 break;
1913 case 5:
1914 max_connections = atoi(optarg);
1915 break;
1916 case 6:
1917 encoding = strdup(optarg);
1918 break;
1919 case 7:
1920 outputdir = strdup(optarg);
1921 break;
1922 case 8:
1923 add_stringlist_item(&schedulelist, optarg);
1924 break;
1925 case 9:
1926 temp_install = make_absolute_path(optarg);
1927 break;
1928 case 10:
1929 nolocale = true;
1930 break;
1931 case 11:
1932 top_builddir = strdup(optarg);
1933 break;
1934 case 12:
1936 int p = atoi(optarg);
1938 /* Since Makefile isn't very bright, check port range */
1939 if (p >= 1024 && p <= 65535)
1940 temp_port = p;
1942 break;
1943 case 13:
1944 hostname = strdup(optarg);
1945 break;
1946 case 14:
1947 port = atoi(optarg);
1948 break;
1949 case 15:
1950 user = strdup(optarg);
1951 break;
1952 case 16:
1953 /* "--psqldir=" should mean to use PATH */
1954 if (strlen(optarg))
1955 psqldir = strdup(optarg);
1956 break;
1957 case 17:
1958 dlpath = strdup(optarg);
1959 break;
1960 case 18:
1961 split_to_stringlist(strdup(optarg), ", ", &extraroles);
1962 break;
1963 case 19:
1964 temp_config = strdup(optarg);
1965 break;
1966 default:
1967 /* getopt_long already emitted a complaint */
1968 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
1969 progname);
1970 exit_nicely(2);
1975 * if we still have arguments, they are extra tests to run
1977 while (argc - optind >= 1)
1979 add_stringlist_item(&extra_tests, argv[optind]);
1980 optind++;
1983 if (temp_install)
1984 port = temp_port;
1986 inputdir = make_absolute_path(inputdir);
1987 outputdir = make_absolute_path(outputdir);
1988 dlpath = make_absolute_path(dlpath);
1991 * Initialization
1993 open_result_files();
1995 initialize_environment();
1997 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
1998 unlimit_core_size();
1999 #endif
2001 if (temp_install)
2004 * Prepare the temp installation
2006 if (!top_builddir)
2008 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2009 exit_nicely(2);
2012 if (directory_exists(temp_install))
2014 header(_("removing existing temp installation"));
2015 rmtree(temp_install, true);
2018 header(_("creating temporary installation"));
2020 /* make the temp install top directory */
2021 make_directory(temp_install);
2023 /* and a directory for log files */
2024 snprintf(buf, sizeof(buf), "%s/log", outputdir);
2025 if (!directory_exists(buf))
2026 make_directory(buf);
2028 /* "make install" */
2029 #ifndef WIN32_ONLY_COMPILER
2030 snprintf(buf, sizeof(buf),
2031 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2032 makeprog, top_builddir, temp_install, outputdir);
2033 #else
2034 snprintf(buf, sizeof(buf),
2035 SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2036 top_builddir, temp_install, outputdir);
2037 #endif
2038 if (system(buf))
2040 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2041 exit_nicely(2);
2044 /* initdb */
2045 header(_("initializing database system"));
2046 snprintf(buf, sizeof(buf),
2047 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
2048 bindir, temp_install, datadir,
2049 debug ? " --debug" : "",
2050 nolocale ? " --no-locale" : "",
2051 outputdir);
2052 if (system(buf))
2054 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2055 exit_nicely(2);
2058 /* add any extra config specified to the postgresql.conf */
2059 if (temp_config != NULL)
2061 FILE *extra_conf;
2062 FILE *pg_conf;
2063 char line_buf[1024];
2065 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
2066 pg_conf = fopen(buf, "a");
2067 if (pg_conf == NULL)
2069 fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2070 exit_nicely(2);
2072 extra_conf = fopen(temp_config, "r");
2073 if (extra_conf == NULL)
2075 fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2076 exit_nicely(2);
2078 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2079 fputs(line_buf, pg_conf);
2080 fclose(extra_conf);
2081 fclose(pg_conf);
2085 * Start the temp postmaster
2087 header(_("starting postmaster"));
2088 snprintf(buf, sizeof(buf),
2089 SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
2090 bindir, temp_install,
2091 debug ? " -d 5" : "",
2092 hostname ? hostname : "",
2093 outputdir);
2094 postmaster_pid = spawn_process(buf);
2095 if (postmaster_pid == INVALID_PID)
2097 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2098 progname, strerror(errno));
2099 exit_nicely(2);
2103 * Wait till postmaster is able to accept connections (normally only a
2104 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2105 * forever, however.
2107 snprintf(buf, sizeof(buf),
2108 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
2109 bindir, DEVNULL, DEVNULL);
2110 for (i = 0; i < 60; i++)
2112 /* Done if psql succeeds */
2113 if (system(buf) == 0)
2114 break;
2117 * Fail immediately if postmaster has exited
2119 #ifndef WIN32
2120 if (kill(postmaster_pid, 0) != 0)
2121 #else
2122 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2123 #endif
2125 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2126 exit_nicely(2);
2129 pg_usleep(1000000L);
2131 if (i >= 60)
2133 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2136 * If we get here, the postmaster is probably wedged somewhere in
2137 * startup. Try to kill it ungracefully rather than leaving a
2138 * stuck postmaster that might interfere with subsequent test
2139 * attempts.
2141 #ifndef WIN32
2142 if (kill(postmaster_pid, SIGKILL) != 0 &&
2143 errno != ESRCH)
2144 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2145 progname, strerror(errno));
2146 #else
2147 if (TerminateProcess(postmaster_pid, 255) == 0)
2148 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
2149 progname, GetLastError());
2150 #endif
2152 exit_nicely(2);
2155 postmaster_running = true;
2157 printf(_("running on port %d with pid %lu\n"),
2158 temp_port, (unsigned long) postmaster_pid);
2160 else
2163 * Using an existing installation, so may need to get rid of
2164 * pre-existing database(s) and role(s)
2166 for (sl = dblist; sl; sl = sl->next)
2167 drop_database_if_exists(sl->str);
2168 for (sl = extraroles; sl; sl = sl->next)
2169 drop_role_if_exists(sl->str);
2173 * Create the test database(s) and role(s)
2175 for (sl = dblist; sl; sl = sl->next)
2176 create_database(sl->str);
2177 for (sl = extraroles; sl; sl = sl->next)
2178 create_role(sl->str, dblist);
2181 * Ready to run the tests
2183 header(_("running regression test queries"));
2185 for (sl = schedulelist; sl != NULL; sl = sl->next)
2187 run_schedule(sl->str, tfunc);
2190 for (sl = extra_tests; sl != NULL; sl = sl->next)
2192 run_single_test(sl->str, tfunc);
2196 * Shut down temp installation's postmaster
2198 if (temp_install)
2200 header(_("shutting down postmaster"));
2201 stop_postmaster();
2204 fclose(logfile);
2207 * Emit nice-looking summary message
2209 if (fail_count == 0 && fail_ignore_count == 0)
2210 snprintf(buf, sizeof(buf),
2211 _(" All %d tests passed. "),
2212 success_count);
2213 else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2214 snprintf(buf, sizeof(buf),
2215 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2216 success_count,
2217 success_count + fail_ignore_count,
2218 fail_ignore_count);
2219 else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2220 snprintf(buf, sizeof(buf),
2221 _(" %d of %d tests failed. "),
2222 fail_count,
2223 success_count + fail_count);
2224 else
2225 /* fail_count>0 && fail_ignore_count>0 */
2226 snprintf(buf, sizeof(buf),
2227 _(" %d of %d tests failed, %d of these failures ignored. "),
2228 fail_count + fail_ignore_count,
2229 success_count + fail_count + fail_ignore_count,
2230 fail_ignore_count);
2232 putchar('\n');
2233 for (i = strlen(buf); i > 0; i--)
2234 putchar('=');
2235 printf("\n%s\n", buf);
2236 for (i = strlen(buf); i > 0; i--)
2237 putchar('=');
2238 putchar('\n');
2239 putchar('\n');
2241 if (file_size(difffilename) > 0)
2243 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2244 "file \"%s\". A copy of the test summary that you see\n"
2245 "above is saved in the file \"%s\".\n\n"),
2246 difffilename, logfilename);
2248 else
2250 unlink(difffilename);
2251 unlink(logfilename);
2254 if (fail_count != 0)
2255 exit_nicely(1);
2257 return 0;