Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / test / regress / pg_regress.c
blob0a588400ec33db6841df73a0b928e71159f73258
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
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 bool nolocale = false;
87 static char *hostname = NULL;
88 static int port = -1;
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;
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];
274 int r;
276 /* On Windows, system() seems not to force fflush, so... */
277 fflush(stdout);
278 fflush(stderr);
280 snprintf(buf, sizeof(buf),
281 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
282 bindir, temp_install);
283 r = system(buf);
284 if (r != 0)
286 fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
287 progname, r);
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
299 void
300 exit_nicely(int code)
302 stop_postmaster();
303 exit(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.
318 static bool
319 string_matches_pattern(const char *str, const char *pattern)
321 while (*str && *pattern)
323 if (*pattern == '.' && pattern[1] == '*')
325 pattern += 2;
326 /* Trailing .* matches everything. */
327 if (*pattern == '\0')
328 return true;
331 * Otherwise, scan for a text position at which we can match the
332 * rest of the pattern.
334 while (*str)
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))
343 return true;
346 str++;
350 * End of text with no match.
352 return false;
354 else if (*pattern != '.' && *str != *pattern)
357 * Not the single-character wildcard and no explicit match? Then
358 * time to quit...
360 return false;
363 str++;
364 pattern++;
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] == '*')
372 pattern += 2;
373 if (*pattern == '\0')
374 return true; /* end of pattern, so declare match */
376 return false;
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!
383 void
384 replace_string(char *string, char *replace, char *replacement)
386 char *ptr;
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));
395 free(dup);
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
403 * the given suffix.
405 static void
406 convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
408 char testtablespace[MAXPGPATH];
409 char indir[MAXPGPATH];
410 struct stat st;
411 int ret;
412 char **name;
413 char **names;
414 int count = 0;
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.
426 return;
429 names = pgfnames(indir);
430 if (!names)
431 /* Error logged in pgfnames */
432 exit_nicely(2);
434 snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
436 #ifdef WIN32
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);
451 #endif
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];
459 FILE *infile,
460 *outfile;
461 char line[1024];
463 /* reject filenames not finishing in ".source" */
464 if (strlen(*name) < 8)
465 continue;
466 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
467 continue;
469 count++;
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");
477 if (!infile)
479 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
480 progname, srcfile, strerror(errno));
481 exit_nicely(2);
483 outfile = fopen(destfile, "w");
484 if (!outfile)
486 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
487 progname, destfile, strerror(errno));
488 exit_nicely(2);
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);
499 fclose(infile);
500 fclose(outfile);
504 * If we didn't process any files, complain because it probably means
505 * somebody neglected to pass the needed --inputdir argument.
507 if (count <= 0)
509 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
510 progname, indir);
511 exit_nicely(2);
514 pgfnames_cleanup(names);
517 /* Create the .sql and .out files from the .source files, if any */
518 static void
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.)
538 static void
539 load_resultmap(void)
541 char buf[MAXPGPATH];
542 FILE *f;
544 /* scan the file ... */
545 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
546 f = fopen(buf, "r");
547 if (!f)
549 /* OK if it doesn't exist, else complain */
550 if (errno == ENOENT)
551 return;
552 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
553 progname, buf, strerror(errno));
554 exit_nicely(2);
557 while (fgets(buf, sizeof(buf), f))
559 char *platform;
560 char *file_type;
561 char *expected;
562 int i;
564 /* strip trailing whitespace, especially the newline */
565 i = strlen(buf);
566 while (i > 0 && isspace((unsigned char) buf[i - 1]))
567 buf[--i] = '\0';
569 /* parse out the line fields */
570 file_type = strchr(buf, ':');
571 if (!file_type)
573 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
574 buf);
575 exit_nicely(2);
577 *file_type++ = '\0';
579 platform = strchr(file_type, ':');
580 if (!platform)
582 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
583 buf);
584 exit_nicely(2);
586 *platform++ = '\0';
587 expected = strchr(platform, '=');
588 if (!expected)
590 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
591 buf);
592 exit_nicely(2);
594 *expected++ = '\0';
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;
610 resultmap = entry;
613 fclose(f);
617 * Check in resultmap if we should be looking at a different file
619 static
620 const char *
621 get_expectfile(const char *testname, const char *file)
623 char *file_type;
624 _resultmap *rm;
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, '.')))
631 return NULL;
633 file_type++;
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;
643 return NULL;
647 * Handy subroutine for setting an environment variable "var" to "val"
649 static void
650 doputenv(const char *var, const char *val)
652 char *s = malloc(strlen(var) + strlen(val) + 2);
654 sprintf(s, "%s=%s", var, val);
655 putenv(s);
659 * Set the environment variable "pathname", prepending "addval" to its
660 * old value (if any).
662 static void
663 add_to_path(const char *pathname, char separator, const char *addval)
665 char *oldval = getenv(pathname);
666 char *newval;
668 if (!oldval || !oldval[0])
670 /* no previous value */
671 newval = malloc(strlen(pathname) + strlen(addval) + 2);
672 sprintf(newval, "%s=%s", pathname, addval);
674 else
676 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
677 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
679 putenv(newval);
683 * Prepare environment variables for running regression tests
685 static void
686 initialize_environment(void)
688 char *tmp;
690 if (nolocale)
693 * Clear out any non-C locale settings
695 unsetenv("LC_COLLATE");
696 unsetenv("LC_CTYPE");
697 unsetenv("LC_MONETARY");
698 unsetenv("LC_NUMERIC");
699 unsetenv("LC_TIME");
700 unsetenv("LANG");
701 /* On Windows the default locale cannot be English, so force it */
702 #if defined(WIN32) || defined(__CYGWIN__)
703 putenv("LANG=en");
704 #endif
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");
714 unsetenv("LC_ALL");
715 putenv("LC_MESSAGES=C");
718 * Set multibyte as requested
720 if (encoding)
721 doputenv("PGCLIENTENCODING", encoding);
722 else
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");
739 char *new_pgoptions;
741 if (!old_pgoptions)
742 old_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);
748 if (temp_install)
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
756 * sockets.
758 unsetenv("PGDATABASE");
759 unsetenv("PGUSER");
760 unsetenv("PGSERVICE");
761 unsetenv("PGSSLMODE");
762 unsetenv("PGREQUIRESSL");
763 unsetenv("PGCONNECT_TIMEOUT");
764 unsetenv("PGDATA");
765 if (hostname != NULL)
766 doputenv("PGHOST", hostname);
767 else
768 unsetenv("PGHOST");
769 unsetenv("PGHOSTADDR");
770 if (port != -1)
772 char s[16];
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);
783 bindir = tmp;
785 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
786 sprintf(tmp, "%s/install/%s", temp_install, libdir);
787 libdir = tmp;
789 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
790 sprintf(tmp, "%s/install/%s", temp_install, datadir);
791 datadir = tmp;
793 /* psql will be installed into temp-install bindir */
794 psqldir = 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
803 * as well.
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);
810 #endif
812 else
814 const char *pghost;
815 const char *pgport;
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");
826 if (port != -1)
828 char s[16];
830 sprintf(s, "%d", port);
831 doputenv("PGPORT", s);
833 if (user != NULL)
834 doputenv("PGUSER", user);
837 * Report what we're connecting to
839 pghost = getenv("PGHOST");
840 pgport = getenv("PGPORT");
841 #ifndef HAVE_UNIX_SOCKETS
842 if (!pghost)
843 pghost = "localhost";
844 #endif
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();
857 load_resultmap();
861 * Issue a command via psql, connecting to the specified database
863 * Since we use system(), this doesn't return until the operation finishes
865 static void
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];
871 va_list args;
872 char *s;
873 char *d;
875 /* Generate the query with insertion of sprintf arguments */
876 va_start(args, query);
877 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
878 va_end(args);
880 /* Now escape any shell double-quote metacharacters */
881 d = query_escaped;
882 for (s = query_formatted; *s; s++)
884 if (strchr("\\\"$`", *s))
885 *d++ = '\\';
886 *d++ = *s;
888 *d = '\0';
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 : "",
894 psqldir ? "/" : "",
895 query_escaped,
896 database);
898 if (system(psql_cmd) != 0)
900 /* psql probably already reported the error */
901 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
902 exit_nicely(2);
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
911 PID_TYPE
912 spawn_process(const char *cmdline)
914 #ifndef WIN32
915 pid_t pid;
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?
921 fflush(stdout);
922 fflush(stderr);
923 if (logfile)
924 fflush(logfile);
926 pid = fork();
927 if (pid == -1)
929 fprintf(stderr, _("%s: could not fork: %s\n"),
930 progname, strerror(errno));
931 exit_nicely(2);
933 if (pid == 0)
936 * In child
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... */
950 /* in parent */
951 return pid;
952 #else
953 char *cmdline2;
954 BOOL b;
955 STARTUPINFO si;
956 PROCESS_INFORMATION pi;
957 HANDLE origToken;
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));
965 si.cb = 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"),
978 progname);
979 exit_nicely(2);
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"),
986 GetLastError());
987 exit_nicely(2);
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());
998 exit_nicely(2);
1001 b = _CreateRestrictedToken(origToken,
1002 DISABLE_MAX_PRIVILEGE,
1003 sizeof(dropSids) / sizeof(dropSids[0]),
1004 dropSids,
1005 0, NULL,
1006 0, NULL,
1007 &restrictedToken);
1009 FreeSid(dropSids[1].Sid);
1010 FreeSid(dropSids[0].Sid);
1011 CloseHandle(origToken);
1012 FreeLibrary(Advapi32Handle);
1014 if (!b)
1016 fprintf(stderr, _("could not create restricted token: %lu\n"),
1017 GetLastError());
1018 exit_nicely(2);
1021 cmdline2 = malloc(strlen(cmdline) + 8);
1022 sprintf(cmdline2, "cmd /c %s", cmdline);
1024 if (!CreateProcessAsUser(restrictedToken,
1025 NULL,
1026 cmdline2,
1027 NULL,
1028 NULL,
1029 TRUE,
1030 CREATE_SUSPENDED,
1031 NULL,
1032 NULL,
1033 &si,
1034 &pi))
1036 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
1037 cmdline2, GetLastError());
1038 exit_nicely(2);
1041 #ifndef __CYGWIN__
1042 AddUserToDacl(pi.hProcess);
1043 #endif
1045 free(cmdline2);
1047 ResumeThread(pi.hThread);
1048 CloseHandle(pi.hThread);
1049 return pi.hProcess;
1050 #endif
1054 * Count bytes in file
1056 static long
1057 file_size(const char *file)
1059 long r;
1060 FILE *f = fopen(file, "r");
1062 if (!f)
1064 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1065 progname, file, strerror(errno));
1066 return -1;
1068 fseek(f, 0, SEEK_END);
1069 r = ftell(f);
1070 fclose(f);
1071 return r;
1075 * Count lines in file
1077 static int
1078 file_line_count(const char *file)
1080 int c;
1081 int l = 0;
1082 FILE *f = fopen(file, "r");
1084 if (!f)
1086 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1087 progname, file, strerror(errno));
1088 return -1;
1090 while ((c = fgetc(f)) != EOF)
1092 if (c == '\n')
1093 l++;
1095 fclose(f);
1096 return l;
1099 bool
1100 file_exists(const char *file)
1102 FILE *f = fopen(file, "r");
1104 if (!f)
1105 return false;
1106 fclose(f);
1107 return true;
1110 static bool
1111 directory_exists(const char *dir)
1113 struct stat st;
1115 if (stat(dir, &st) != 0)
1116 return false;
1117 if (S_ISDIR(st.st_mode))
1118 return true;
1119 return false;
1122 /* Create a directory */
1123 static void
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));
1130 exit_nicely(2);
1135 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1137 static char *
1138 get_alternative_expectfile(const char *expectfile, int i)
1140 char *last_dot;
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, '.');
1147 if (!last_dot)
1149 free(tmp);
1150 free(s);
1151 return NULL;
1153 *last_dot = '\0';
1154 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1155 free(tmp);
1156 return s;
1160 * Run a "diff" command and also check that it didn't crash
1162 static int
1163 run_diff(const char *cmd, const char *filename)
1165 int r;
1167 r = system(cmd);
1168 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1170 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1171 exit_nicely(2);
1173 #ifdef WIN32
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);
1182 exit_nicely(2);
1184 #endif
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.
1195 static bool
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];
1202 FILE *difffile;
1203 int best_line_count;
1204 int i;
1205 int l;
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, '/');
1223 if (p)
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)
1238 unlink(diff);
1239 return false;
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))
1252 continue;
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)
1260 unlink(diff);
1261 return false;
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 */
1288 unlink(diff);
1289 return false;
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");
1312 if (difffile)
1314 fprintf(difffile,
1315 "\n======================================================================\n\n");
1316 fclose(difffile);
1319 unlink(diff);
1320 return true;
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
1331 static void
1332 wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
1334 int tests_left;
1335 int i;
1337 #ifdef WIN32
1338 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1340 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1341 #endif
1343 tests_left = num_tests;
1344 while (tests_left > 0)
1346 PID_TYPE p;
1348 #ifndef WIN32
1349 int exit_status;
1351 p = wait(&exit_status);
1353 if (p == INVALID_PID)
1355 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1356 strerror(errno));
1357 exit_nicely(2);
1359 #else
1360 DWORD exit_status;
1361 int r;
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"),
1367 GetLastError());
1368 exit_nicely(2);
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];
1373 #endif /* WIN32 */
1375 for (i = 0; i < num_tests; i++)
1377 if (p == pids[i])
1379 #ifdef WIN32
1380 GetExitCodeProcess(pids[i], &exit_status);
1381 CloseHandle(pids[i]);
1382 #endif
1383 pids[i] = INVALID_PID;
1384 statuses[i] = (int) exit_status;
1385 if (names)
1386 status(" %s", names[i]);
1387 tests_left--;
1388 break;
1393 #ifdef WIN32
1394 free(active_pids);
1395 #endif
1399 * report nonzero exit code from a test process
1401 static void
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))
1409 #if defined(WIN32)
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))");
1417 #else
1418 status(_(" (test process was terminated by signal %d)"),
1419 WTERMSIG(exitstatus));
1420 #endif
1422 else
1423 status(_(" (test process exited with unrecognized status %d)"),
1424 exitstatus);
1428 * Run all the tests specified in one schedule file
1430 static void
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;
1441 char scbuf[1024];
1442 FILE *scf;
1443 int line_num = 0;
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");
1450 if (!scf)
1452 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1453 progname, schedule, strerror(errno));
1454 exit_nicely(2);
1457 while (fgets(scbuf, sizeof(scbuf), scf))
1459 char *test = NULL;
1460 char *c;
1461 int num_tests;
1462 bool inword;
1463 int i;
1465 line_num++;
1467 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1469 if (resultfiles[i] == NULL)
1470 break;
1471 free_stringlist(&resultfiles[i]);
1472 free_stringlist(&expectfiles[i]);
1473 free_stringlist(&tags[i]);
1476 /* strip trailing whitespace, especially the newline */
1477 i = strlen(scbuf);
1478 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1479 scbuf[--i] = '\0';
1481 if (scbuf[0] == '\0' || scbuf[0] == '#')
1482 continue;
1483 if (strncmp(scbuf, "test: ", 6) == 0)
1484 test = scbuf + 6;
1485 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1487 c = scbuf + 8;
1488 while (*c && isspace((unsigned char) *c))
1489 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.
1497 continue;
1499 else
1501 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1502 schedule, line_num, scbuf);
1503 exit_nicely(2);
1506 num_tests = 0;
1507 inword = false;
1508 for (c = test; *c; c++)
1510 if (isspace((unsigned char) *c))
1512 *c = '\0';
1513 inword = false;
1515 else if (!inword)
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);
1522 exit_nicely(2);
1524 tests[num_tests] = c;
1525 num_tests++;
1526 inword = true;
1530 if (num_tests == 0)
1532 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1533 schedule, line_num, scbuf);
1534 exit_nicely(2);
1537 if (num_tests == 1)
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)
1546 int oldest = 0;
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);
1556 oldest = i;
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);
1562 status_end();
1564 else
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);
1572 status_end();
1575 /* Check results for all tests */
1576 for (i = 0; i < num_tests; i++)
1578 _stringlist *rl,
1579 *el,
1580 *tl;
1581 bool differ = false;
1583 if (num_tests > 1)
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)
1597 bool newdiff;
1599 if (tl)
1600 tl = tl->next; /* tl has the same length as rl and el
1601 * if it exists */
1603 newdiff = results_differ(tests[i], rl->str, el->str);
1604 if (newdiff && tl)
1606 printf("%s ", tl->str);
1608 differ |= newdiff;
1611 if (differ)
1613 bool ignore = false;
1614 _stringlist *sl;
1616 for (sl = ignorelist; sl != NULL; sl = sl->next)
1618 if (strcmp(tests[i], sl->str) == 0)
1620 ignore = true;
1621 break;
1624 if (ignore)
1626 status(_("failed (ignored)"));
1627 fail_ignore_count++;
1629 else
1631 status(_("FAILED"));
1632 fail_count++;
1635 else
1637 status(_("ok"));
1638 success_count++;
1641 if (statuses[i] != 0)
1642 log_child_failure(statuses[i]);
1644 status_end();
1648 fclose(scf);
1652 * Run a single test
1654 static void
1655 run_single_test(const char *test, test_function tfunc)
1657 PID_TYPE pid;
1658 int exit_status;
1659 _stringlist *resultfiles = NULL;
1660 _stringlist *expectfiles = NULL;
1661 _stringlist *tags = NULL;
1662 _stringlist *rl,
1663 *el,
1664 *tl;
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
1676 * two lists.
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)
1682 bool newdiff;
1684 if (tl)
1685 tl = tl->next; /* tl has the same length as rl and el if it
1686 * exists */
1688 newdiff = results_differ(test, rl->str, el->str);
1689 if (newdiff && tl)
1691 printf("%s ", tl->str);
1693 differ |= newdiff;
1696 if (differ)
1698 status(_("FAILED"));
1699 fail_count++;
1701 else
1703 status(_("ok"));
1704 success_count++;
1707 if (exit_status != 0)
1708 log_child_failure(exit_status);
1710 status_end();
1714 * Create the summary-output files (making them empty if already existing)
1716 static void
1717 open_result_files(void)
1719 char file[MAXPGPATH];
1720 FILE *difffile;
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");
1726 if (!logfile)
1728 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1729 progname, logfilename, strerror(errno));
1730 exit_nicely(2);
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");
1737 if (!difffile)
1739 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1740 progname, difffilename, strerror(errno));
1741 exit_nicely(2);
1743 /* we don't keep the diffs file open continuously */
1744 fclose(difffile);
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);
1752 static void
1753 drop_database_if_exists(const char *dbname)
1755 header(_("dropping database \"%s\""), dbname);
1756 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1759 static void
1760 create_database(const char *dbname)
1762 _stringlist *sl;
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);
1769 if (encoding)
1770 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname, encoding);
1771 else
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);
1791 static void
1792 drop_role_if_exists(const char *rolename)
1794 header(_("dropping role \"%s\""), rolename);
1795 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1798 static void
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);
1810 static char *
1811 make_absolute_path(const char *in)
1813 char *result;
1815 if (is_absolute_path(in))
1816 result = strdup(in);
1817 else
1819 static char cwdbuf[MAXPGPATH];
1821 if (!cwdbuf[0])
1823 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1825 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1826 exit_nicely(2);
1830 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1831 sprintf(result, "%s/%s", cwdbuf, in);
1834 canonicalize_path(result);
1835 return result;
1838 static void
1839 help(void)
1841 printf(_("PostgreSQL regression test driver\n"));
1842 printf(_("\n"));
1843 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1844 printf(_("\n"));
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"));
1860 printf(_("\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"));
1866 printf(_("\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"));
1872 printf(_("\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"));
1875 printf(_("\n"));
1876 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1880 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1882 _stringlist *sl;
1883 int c;
1884 int i;
1885 int option_index;
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},
1910 {NULL, 0, NULL, 0}
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";
1919 #endif
1922 * We call the initialization function here because that way we can set
1923 * default parameters and let them be overwritten by the commandline.
1925 ifunc();
1927 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1929 switch (c)
1931 case 'h':
1932 help();
1933 exit_nicely(0);
1934 case 'V':
1935 puts("pg_regress (PostgreSQL) " PG_VERSION);
1936 exit_nicely(0);
1937 case 1:
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);
1945 break;
1946 case 2:
1947 debug = true;
1948 break;
1949 case 3:
1950 inputdir = strdup(optarg);
1951 break;
1952 case 4:
1953 add_stringlist_item(&loadlanguage, optarg);
1954 break;
1955 case 5:
1956 max_connections = atoi(optarg);
1957 break;
1958 case 6:
1959 encoding = strdup(optarg);
1960 break;
1961 case 7:
1962 outputdir = strdup(optarg);
1963 break;
1964 case 8:
1965 add_stringlist_item(&schedulelist, optarg);
1966 break;
1967 case 9:
1968 temp_install = make_absolute_path(optarg);
1969 break;
1970 case 10:
1971 nolocale = true;
1972 break;
1973 case 11:
1974 top_builddir = strdup(optarg);
1975 break;
1976 case 13:
1977 hostname = strdup(optarg);
1978 break;
1979 case 14:
1980 port = atoi(optarg);
1981 port_specified_by_user = true;
1982 break;
1983 case 15:
1984 user = strdup(optarg);
1985 break;
1986 case 16:
1987 /* "--psqldir=" should mean to use PATH */
1988 if (strlen(optarg))
1989 psqldir = strdup(optarg);
1990 break;
1991 case 17:
1992 dlpath = strdup(optarg);
1993 break;
1994 case 18:
1995 split_to_stringlist(strdup(optarg), ", ", &extraroles);
1996 break;
1997 case 19:
1998 temp_config = strdup(optarg);
1999 break;
2000 default:
2001 /* getopt_long already emitted a complaint */
2002 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2003 progname);
2004 exit_nicely(2);
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]);
2014 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);
2031 * Initialization
2033 open_result_files();
2035 initialize_environment();
2037 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2038 unlimit_core_size();
2039 #endif
2041 if (temp_install)
2043 FILE *pg_conf;
2046 * Prepare the temp installation
2048 if (!top_builddir)
2050 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2051 exit_nicely(2);
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);
2075 #else
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);
2079 #endif
2080 if (system(buf))
2082 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2083 exit_nicely(2);
2086 /* initdb */
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" : "",
2093 outputdir);
2094 if (system(buf))
2096 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2097 exit_nicely(2);
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));
2113 exit_nicely(2);
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)
2120 FILE *extra_conf;
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));
2127 exit_nicely(2);
2129 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2130 fputs(line_buf, pg_conf);
2131 fclose(extra_conf);
2134 fclose(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)
2147 char s[16];
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"));
2155 exit_nicely(2);
2158 fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2159 port++;
2160 sprintf(s, "%d", port);
2161 doputenv("PGPORT", s);
2163 else
2164 break;
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 : "",
2176 outputdir);
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));
2182 exit_nicely(2);
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
2188 * forever, however.
2190 for (i = 0; i < 60; i++)
2192 /* Done if psql succeeds */
2193 if (system(buf2) == 0)
2194 break;
2197 * Fail immediately if postmaster has exited
2199 #ifndef WIN32
2200 if (kill(postmaster_pid, 0) != 0)
2201 #else
2202 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2203 #endif
2205 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2206 exit_nicely(2);
2209 pg_usleep(1000000L);
2211 if (i >= 60)
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
2219 * attempts.
2221 #ifndef WIN32
2222 if (kill(postmaster_pid, SIGKILL) != 0 &&
2223 errno != ESRCH)
2224 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2225 progname, strerror(errno));
2226 #else
2227 if (TerminateProcess(postmaster_pid, 255) == 0)
2228 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
2229 progname, GetLastError());
2230 #endif
2232 exit_nicely(2);
2235 postmaster_running = true;
2237 printf(_("running on port %d with pid %lu\n"),
2238 port, (unsigned long) postmaster_pid);
2240 else
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
2278 if (temp_install)
2280 header(_("shutting down postmaster"));
2281 stop_postmaster();
2284 fclose(logfile);
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. "),
2292 success_count);
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. "),
2296 success_count,
2297 success_count + fail_ignore_count,
2298 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. "),
2302 fail_count,
2303 success_count + fail_count);
2304 else
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,
2310 fail_ignore_count);
2312 putchar('\n');
2313 for (i = strlen(buf); i > 0; i--)
2314 putchar('=');
2315 printf("\n%s\n", buf);
2316 for (i = strlen(buf); i > 0; i--)
2317 putchar('=');
2318 putchar('\n');
2319 putchar('\n');
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);
2328 else
2330 unlink(difffilename);
2331 unlink(logfilename);
2334 if (fail_count != 0)
2335 exit_nicely(1);
2337 return 0;