Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / test / regress / pg_regress.c
blobc5a564c89421bac383cbc5d0dc4fdafa1327978c
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];
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
424 * these 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
438 * On Windows only, clean out the test tablespace dir, or create it if it
439 * doesn't exist. On other platforms we expect the Makefile to take
440 * care of that. (We don't migrate that functionality in here because
441 * it'd be harder to cope with platform-specific issues such as SELinux.)
443 * XXX it would be better if pg_regress.c had nothing at all to do with
444 * testtablespace, and this were handled by a .BAT file or similar on
445 * Windows. See pgsql-hackers discussion of 2008-01-18.
447 if (directory_exists(testtablespace))
448 rmtree(testtablespace, true);
449 make_directory(testtablespace);
450 #endif
452 /* finally loop on each file and do the replacement */
453 for (name = names; *name; name++)
455 char srcfile[MAXPGPATH];
456 char destfile[MAXPGPATH];
457 char prefix[MAXPGPATH];
458 FILE *infile,
459 *outfile;
460 char line[1024];
462 /* reject filenames not finishing in ".source" */
463 if (strlen(*name) < 8)
464 continue;
465 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
466 continue;
468 count++;
470 /* build the full actual paths to open */
471 snprintf(prefix, strlen(*name) - 6, "%s", *name);
472 snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
473 snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest_subdir, prefix, suffix);
475 infile = fopen(srcfile, "r");
476 if (!infile)
478 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
479 progname, srcfile, strerror(errno));
480 exit_nicely(2);
482 outfile = fopen(destfile, "w");
483 if (!outfile)
485 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
486 progname, destfile, strerror(errno));
487 exit_nicely(2);
489 while (fgets(line, sizeof(line), infile))
491 replace_string(line, "@abs_srcdir@", inputdir);
492 replace_string(line, "@abs_builddir@", outputdir);
493 replace_string(line, "@testtablespace@", testtablespace);
494 replace_string(line, "@libdir@", dlpath);
495 replace_string(line, "@DLSUFFIX@", DLSUFFIX);
496 fputs(line, outfile);
498 fclose(infile);
499 fclose(outfile);
503 * If we didn't process any files, complain because it probably means
504 * somebody neglected to pass the needed --inputdir argument.
506 if (count <= 0)
508 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
509 progname, indir);
510 exit_nicely(2);
513 pgfnames_cleanup(names);
516 /* Create the .sql and .out files from the .source files, if any */
517 static void
518 convert_sourcefiles(void)
520 convert_sourcefiles_in("input", "sql", "sql");
521 convert_sourcefiles_in("output", "expected", "out");
525 * Scan resultmap file to find which platform-specific expected files to use.
527 * The format of each line of the file is
528 * testname/hostplatformpattern=substitutefile
529 * where the hostplatformpattern is evaluated per the rules of expr(1),
530 * namely, it is a standard regular expression with an implicit ^ at the start.
531 * (We currently support only a very limited subset of regular expressions,
532 * see string_matches_pattern() above.) What hostplatformpattern will be
533 * matched against is the config.guess output. (In the shell-script version,
534 * we also provided an indication of whether gcc or another compiler was in
535 * use, but that facility isn't used anymore.)
537 static void
538 load_resultmap(void)
540 char buf[MAXPGPATH];
541 FILE *f;
543 /* scan the file ... */
544 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
545 f = fopen(buf, "r");
546 if (!f)
548 /* OK if it doesn't exist, else complain */
549 if (errno == ENOENT)
550 return;
551 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
552 progname, buf, strerror(errno));
553 exit_nicely(2);
556 while (fgets(buf, sizeof(buf), f))
558 char *platform;
559 char *file_type;
560 char *expected;
561 int i;
563 /* strip trailing whitespace, especially the newline */
564 i = strlen(buf);
565 while (i > 0 && isspace((unsigned char) buf[i - 1]))
566 buf[--i] = '\0';
568 /* parse out the line fields */
569 file_type = strchr(buf, ':');
570 if (!file_type)
572 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
573 buf);
574 exit_nicely(2);
576 *file_type++ = '\0';
578 platform = strchr(file_type, ':');
579 if (!platform)
581 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
582 buf);
583 exit_nicely(2);
585 *platform++ = '\0';
586 expected = strchr(platform, '=');
587 if (!expected)
589 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
590 buf);
591 exit_nicely(2);
593 *expected++ = '\0';
596 * if it's for current platform, save it in resultmap list. Note: by
597 * adding at the front of the list, we ensure that in ambiguous cases,
598 * the last match in the resultmap file is used. This mimics the
599 * behavior of the old shell script.
601 if (string_matches_pattern(host_platform, platform))
603 _resultmap *entry = malloc(sizeof(_resultmap));
605 entry->test = strdup(buf);
606 entry->type = strdup(file_type);
607 entry->resultfile = strdup(expected);
608 entry->next = resultmap;
609 resultmap = entry;
612 fclose(f);
616 * Check in resultmap if we should be looking at a different file
618 static
619 const char *
620 get_expectfile(const char *testname, const char *file)
622 char *file_type;
623 _resultmap *rm;
626 * Determine the file type from the file name. This is just what is
627 * following the last dot in the file name.
629 if (!file || !(file_type = strrchr(file, '.')))
630 return NULL;
632 file_type++;
634 for (rm = resultmap; rm != NULL; rm = rm->next)
636 if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
638 return rm->resultfile;
642 return NULL;
646 * Handy subroutine for setting an environment variable "var" to "val"
648 static void
649 doputenv(const char *var, const char *val)
651 char *s = malloc(strlen(var) + strlen(val) + 2);
653 sprintf(s, "%s=%s", var, val);
654 putenv(s);
658 * Set the environment variable "pathname", prepending "addval" to its
659 * old value (if any).
661 static void
662 add_to_path(const char *pathname, char separator, const char *addval)
664 char *oldval = getenv(pathname);
665 char *newval;
667 if (!oldval || !oldval[0])
669 /* no previous value */
670 newval = malloc(strlen(pathname) + strlen(addval) + 2);
671 sprintf(newval, "%s=%s", pathname, addval);
673 else
675 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
676 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
678 putenv(newval);
682 * Prepare environment variables for running regression tests
684 static void
685 initialize_environment(void)
687 char *tmp;
690 * Clear out any non-C locale settings
692 unsetenv("LC_COLLATE");
693 unsetenv("LC_CTYPE");
694 unsetenv("LC_MONETARY");
695 unsetenv("LC_MESSAGES");
696 unsetenv("LC_NUMERIC");
697 unsetenv("LC_TIME");
698 unsetenv("LC_ALL");
699 unsetenv("LANG");
700 unsetenv("LANGUAGE");
701 /* On Windows the default locale cannot be English, so force it */
702 #if defined(WIN32) || defined(__CYGWIN__)
703 putenv("LANG=en");
704 #endif
707 * Set multibyte as requested
709 if (encoding)
710 doputenv("PGCLIENTENCODING", encoding);
711 else
712 unsetenv("PGCLIENTENCODING");
715 * Set timezone and datestyle for datetime-related tests
717 putenv("PGTZ=PST8PDT");
718 putenv("PGDATESTYLE=Postgres, MDY");
721 * Likewise set intervalstyle to ensure consistent results. This is a
722 * bit more painful because we must use PGOPTIONS, and we want to preserve
723 * the user's ability to set other variables through that.
726 const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
727 const char *old_pgoptions = getenv("PGOPTIONS");
728 char *new_pgoptions;
730 if (!old_pgoptions)
731 old_pgoptions = "";
732 new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
733 sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
734 putenv(new_pgoptions);
737 if (temp_install)
740 * Clear out any environment vars that might cause psql to connect to
741 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
742 * we also use psql's -X switch consistently, so that ~/.psqlrc files
743 * won't mess things up.) Also, set PGPORT to the temp port, and set
744 * or unset PGHOST depending on whether we are using TCP or Unix
745 * sockets.
747 unsetenv("PGDATABASE");
748 unsetenv("PGUSER");
749 unsetenv("PGSERVICE");
750 unsetenv("PGSSLMODE");
751 unsetenv("PGREQUIRESSL");
752 unsetenv("PGCONNECT_TIMEOUT");
753 unsetenv("PGDATA");
754 if (hostname != NULL)
755 doputenv("PGHOST", hostname);
756 else
757 unsetenv("PGHOST");
758 unsetenv("PGHOSTADDR");
759 if (port != -1)
761 char s[16];
763 sprintf(s, "%d", port);
764 doputenv("PGPORT", s);
768 * Adjust path variables to point into the temp-install tree
770 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
771 sprintf(tmp, "%s/install/%s", temp_install, bindir);
772 bindir = tmp;
774 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
775 sprintf(tmp, "%s/install/%s", temp_install, libdir);
776 libdir = tmp;
778 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
779 sprintf(tmp, "%s/install/%s", temp_install, datadir);
780 datadir = tmp;
782 /* psql will be installed into temp-install bindir */
783 psqldir = bindir;
786 * Set up shared library paths to include the temp install.
788 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
789 * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX.
790 * Windows needs shared libraries in PATH (only those linked into
791 * executables, not dlopen'ed ones). Feel free to account for others
792 * as well.
794 add_to_path("LD_LIBRARY_PATH", ':', libdir);
795 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
796 add_to_path("LIBPATH", ':', libdir);
797 #if defined(WIN32) || defined(__CYGWIN__)
798 add_to_path("PATH", ';', libdir);
799 #endif
801 else
803 const char *pghost;
804 const char *pgport;
807 * When testing an existing install, we honor existing environment
808 * variables, except if they're overridden by command line options.
810 if (hostname != NULL)
812 doputenv("PGHOST", hostname);
813 unsetenv("PGHOSTADDR");
815 if (port != -1)
817 char s[16];
819 sprintf(s, "%d", port);
820 doputenv("PGPORT", s);
822 if (user != NULL)
823 doputenv("PGUSER", user);
826 * Report what we're connecting to
828 pghost = getenv("PGHOST");
829 pgport = getenv("PGPORT");
830 #ifndef HAVE_UNIX_SOCKETS
831 if (!pghost)
832 pghost = "localhost";
833 #endif
835 if (pghost && pgport)
836 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
837 if (pghost && !pgport)
838 printf(_("(using postmaster on %s, default port)\n"), pghost);
839 if (!pghost && pgport)
840 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
841 if (!pghost && !pgport)
842 printf(_("(using postmaster on Unix socket, default port)\n"));
845 convert_sourcefiles();
846 load_resultmap();
850 * Issue a command via psql, connecting to the specified database
852 * Since we use system(), this doesn't return until the operation finishes
854 static void
855 psql_command(const char *database, const char *query,...)
857 char query_formatted[1024];
858 char query_escaped[2048];
859 char psql_cmd[MAXPGPATH + 2048];
860 va_list args;
861 char *s;
862 char *d;
864 /* Generate the query with insertion of sprintf arguments */
865 va_start(args, query);
866 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
867 va_end(args);
869 /* Now escape any shell double-quote metacharacters */
870 d = query_escaped;
871 for (s = query_formatted; *s; s++)
873 if (strchr("\\\"$`", *s))
874 *d++ = '\\';
875 *d++ = *s;
877 *d = '\0';
879 /* And now we can build and execute the shell command */
880 snprintf(psql_cmd, sizeof(psql_cmd),
881 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
882 psqldir ? psqldir : "",
883 psqldir ? "/" : "",
884 query_escaped,
885 database);
887 if (system(psql_cmd) != 0)
889 /* psql probably already reported the error */
890 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
891 exit_nicely(2);
896 * Spawn a process to execute the given shell command; don't wait for it
898 * Returns the process ID (or HANDLE) so we can wait for it later
900 PID_TYPE
901 spawn_process(const char *cmdline)
903 #ifndef WIN32
904 pid_t pid;
907 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
908 * ... does anyone still care about systems where that doesn't work?
910 fflush(stdout);
911 fflush(stderr);
912 if (logfile)
913 fflush(logfile);
915 pid = fork();
916 if (pid == -1)
918 fprintf(stderr, _("%s: could not fork: %s\n"),
919 progname, strerror(errno));
920 exit_nicely(2);
922 if (pid == 0)
925 * In child
927 * Instead of using system(), exec the shell directly, and tell it to
928 * "exec" the command too. This saves two useless processes per
929 * parallel test case.
931 char *cmdline2 = malloc(strlen(cmdline) + 6);
933 sprintf(cmdline2, "exec %s", cmdline);
934 execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
935 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
936 progname, shellprog, strerror(errno));
937 exit(1); /* not exit_nicely here... */
939 /* in parent */
940 return pid;
941 #else
942 char *cmdline2;
943 BOOL b;
944 STARTUPINFO si;
945 PROCESS_INFORMATION pi;
946 HANDLE origToken;
947 HANDLE restrictedToken;
948 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
949 SID_AND_ATTRIBUTES dropSids[2];
950 __CreateRestrictedToken _CreateRestrictedToken = NULL;
951 HANDLE Advapi32Handle;
953 ZeroMemory(&si, sizeof(si));
954 si.cb = sizeof(si);
956 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
957 if (Advapi32Handle != NULL)
959 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
962 if (_CreateRestrictedToken == NULL)
964 if (Advapi32Handle != NULL)
965 FreeLibrary(Advapi32Handle);
966 fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
967 progname);
968 exit_nicely(2);
971 /* Open the current token to use as base for the restricted one */
972 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
974 fprintf(stderr, _("could not open process token: %lu\n"),
975 GetLastError());
976 exit_nicely(2);
979 /* Allocate list of SIDs to remove */
980 ZeroMemory(&dropSids, sizeof(dropSids));
981 if (!AllocateAndInitializeSid(&NtAuthority, 2,
982 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
983 !AllocateAndInitializeSid(&NtAuthority, 2,
984 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
986 fprintf(stderr, _("could not allocate SIDs: %lu\n"), GetLastError());
987 exit_nicely(2);
990 b = _CreateRestrictedToken(origToken,
991 DISABLE_MAX_PRIVILEGE,
992 sizeof(dropSids) / sizeof(dropSids[0]),
993 dropSids,
994 0, NULL,
995 0, NULL,
996 &restrictedToken);
998 FreeSid(dropSids[1].Sid);
999 FreeSid(dropSids[0].Sid);
1000 CloseHandle(origToken);
1001 FreeLibrary(Advapi32Handle);
1003 if (!b)
1005 fprintf(stderr, _("could not create restricted token: %lu\n"),
1006 GetLastError());
1007 exit_nicely(2);
1010 cmdline2 = malloc(strlen(cmdline) + 8);
1011 sprintf(cmdline2, "cmd /c %s", cmdline);
1013 if (!CreateProcessAsUser(restrictedToken,
1014 NULL,
1015 cmdline2,
1016 NULL,
1017 NULL,
1018 TRUE,
1019 CREATE_SUSPENDED,
1020 NULL,
1021 NULL,
1022 &si,
1023 &pi))
1025 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
1026 cmdline2, GetLastError());
1027 exit_nicely(2);
1030 #ifndef __CYGWIN__
1031 AddUserToDacl(pi.hProcess);
1032 #endif
1034 free(cmdline2);
1036 ResumeThread(pi.hThread);
1037 CloseHandle(pi.hThread);
1038 return pi.hProcess;
1039 #endif
1043 * Count bytes in file
1045 static long
1046 file_size(const char *file)
1048 long r;
1049 FILE *f = fopen(file, "r");
1051 if (!f)
1053 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1054 progname, file, strerror(errno));
1055 return -1;
1057 fseek(f, 0, SEEK_END);
1058 r = ftell(f);
1059 fclose(f);
1060 return r;
1064 * Count lines in file
1066 static int
1067 file_line_count(const char *file)
1069 int c;
1070 int l = 0;
1071 FILE *f = fopen(file, "r");
1073 if (!f)
1075 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1076 progname, file, strerror(errno));
1077 return -1;
1079 while ((c = fgetc(f)) != EOF)
1081 if (c == '\n')
1082 l++;
1084 fclose(f);
1085 return l;
1088 bool
1089 file_exists(const char *file)
1091 FILE *f = fopen(file, "r");
1093 if (!f)
1094 return false;
1095 fclose(f);
1096 return true;
1099 static bool
1100 directory_exists(const char *dir)
1102 struct stat st;
1104 if (stat(dir, &st) != 0)
1105 return false;
1106 if (S_ISDIR(st.st_mode))
1107 return true;
1108 return false;
1111 /* Create a directory */
1112 static void
1113 make_directory(const char *dir)
1115 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1117 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1118 progname, dir, strerror(errno));
1119 exit_nicely(2);
1124 * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1126 static char *
1127 get_alternative_expectfile(const char *expectfile, int i)
1129 char *last_dot;
1130 int ssize = strlen(expectfile) + 2 + 1;
1131 char *tmp = (char *) malloc(ssize);
1132 char *s = (char *) malloc(ssize);
1134 strcpy(tmp, expectfile);
1135 last_dot = strrchr(tmp, '.');
1136 if (!last_dot)
1137 return NULL;
1138 *last_dot = '\0';
1139 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1140 free(tmp);
1141 return s;
1145 * Run a "diff" command and also check that it didn't crash
1147 static int
1148 run_diff(const char *cmd, const char *filename)
1150 int r;
1152 r = system(cmd);
1153 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1155 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1156 exit_nicely(2);
1158 #ifdef WIN32
1161 * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1162 * but produces nothing to stdout, so we check for that here.
1164 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1166 fprintf(stderr, _("diff command not found: %s\n"), cmd);
1167 exit_nicely(2);
1169 #endif
1171 return WEXITSTATUS(r);
1175 * Check the actual result file for the given test against expected results
1177 * Returns true if different (failure), false if correct match found.
1178 * In the true case, the diff is appended to the diffs file.
1180 static bool
1181 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1183 char expectfile[MAXPGPATH];
1184 char diff[MAXPGPATH];
1185 char cmd[MAXPGPATH * 3];
1186 char best_expect_file[MAXPGPATH];
1187 FILE *difffile;
1188 int best_line_count;
1189 int i;
1190 int l;
1191 const char *platform_expectfile;
1194 * We can pass either the resultsfile or the expectfile, they should have
1195 * the same type (filename.type) anyway.
1197 platform_expectfile = get_expectfile(testname, resultsfile);
1199 strcpy(expectfile, default_expectfile);
1200 if (platform_expectfile)
1203 * Replace everything afer the last slash in expectfile with what the
1204 * platform_expectfile contains.
1206 char *p = strrchr(expectfile, '/');
1208 if (p)
1209 strcpy(++p, platform_expectfile);
1212 /* Name to use for temporary diff file */
1213 snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1215 /* OK, run the diff */
1216 snprintf(cmd, sizeof(cmd),
1217 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1218 basic_diff_opts, expectfile, resultsfile, diff);
1220 /* Is the diff file empty? */
1221 if (run_diff(cmd, diff) == 0)
1223 unlink(diff);
1224 return false;
1227 /* There may be secondary comparison files that match better */
1228 best_line_count = file_line_count(diff);
1229 strcpy(best_expect_file, expectfile);
1231 for (i = 0; i <= 9; i++)
1233 char *alt_expectfile;
1235 alt_expectfile = get_alternative_expectfile(expectfile, i);
1236 if (!file_exists(alt_expectfile))
1237 continue;
1239 snprintf(cmd, sizeof(cmd),
1240 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1241 basic_diff_opts, alt_expectfile, resultsfile, diff);
1243 if (run_diff(cmd, diff) == 0)
1245 unlink(diff);
1246 return false;
1249 l = file_line_count(diff);
1250 if (l < best_line_count)
1252 /* This diff was a better match than the last one */
1253 best_line_count = l;
1254 strcpy(best_expect_file, alt_expectfile);
1256 free(alt_expectfile);
1260 * fall back on the canonical results file if we haven't tried it yet and
1261 * haven't found a complete match yet.
1264 if (platform_expectfile)
1266 snprintf(cmd, sizeof(cmd),
1267 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
1268 basic_diff_opts, default_expectfile, resultsfile, diff);
1270 if (run_diff(cmd, diff) == 0)
1272 /* No diff = no changes = good */
1273 unlink(diff);
1274 return false;
1277 l = file_line_count(diff);
1278 if (l < best_line_count)
1280 /* This diff was a better match than the last one */
1281 best_line_count = l;
1282 strcpy(best_expect_file, default_expectfile);
1287 * Use the best comparison file to generate the "pretty" diff, which we
1288 * append to the diffs summary file.
1290 snprintf(cmd, sizeof(cmd),
1291 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
1292 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1293 run_diff(cmd, difffilename);
1295 /* And append a separator */
1296 difffile = fopen(difffilename, "a");
1297 if (difffile)
1299 fprintf(difffile,
1300 "\n======================================================================\n\n");
1301 fclose(difffile);
1304 unlink(diff);
1305 return true;
1309 * Wait for specified subprocesses to finish, and return their exit
1310 * statuses into statuses[]
1312 * If names isn't NULL, print each subprocess's name as it finishes
1314 * Note: it's OK to scribble on the pids array, but not on the names array
1316 static void
1317 wait_for_tests(PID_TYPE *pids, int *statuses, char **names, int num_tests)
1319 int tests_left;
1320 int i;
1322 #ifdef WIN32
1323 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
1325 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1326 #endif
1328 tests_left = num_tests;
1329 while (tests_left > 0)
1331 PID_TYPE p;
1332 int exit_status;
1334 #ifndef WIN32
1335 p = wait(&exit_status);
1337 if (p == INVALID_PID)
1339 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1340 strerror(errno));
1341 exit_nicely(2);
1343 #else
1344 int r;
1346 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1347 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1349 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
1350 GetLastError());
1351 exit_nicely(2);
1353 p = active_pids[r - WAIT_OBJECT_0];
1354 /* compact the active_pids array */
1355 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1356 #endif /* WIN32 */
1358 for (i = 0; i < num_tests; i++)
1360 if (p == pids[i])
1362 #ifdef WIN32
1363 GetExitCodeProcess(pids[i], &exit_status);
1364 CloseHandle(pids[i]);
1365 #endif
1366 pids[i] = INVALID_PID;
1367 statuses[i] = exit_status;
1368 if (names)
1369 status(" %s", names[i]);
1370 tests_left--;
1371 break;
1376 #ifdef WIN32
1377 free(active_pids);
1378 #endif
1382 * report nonzero exit code from a test process
1384 static void
1385 log_child_failure(int exitstatus)
1387 if (WIFEXITED(exitstatus))
1388 status(_(" (test process exited with exit code %d)"),
1389 WEXITSTATUS(exitstatus));
1390 else if (WIFSIGNALED(exitstatus))
1392 #if defined(WIN32)
1393 status(_(" (test process was terminated by exception 0x%X)"),
1394 WTERMSIG(exitstatus));
1395 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
1396 status(_(" (test process was terminated by signal %d: %s)"),
1397 WTERMSIG(exitstatus),
1398 WTERMSIG(exitstatus) < NSIG ?
1399 sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
1400 #else
1401 status(_(" (test process was terminated by signal %d)"),
1402 WTERMSIG(exitstatus));
1403 #endif
1405 else
1406 status(_(" (test process exited with unrecognized status %d)"),
1407 exitstatus);
1411 * Run all the tests specified in one schedule file
1413 static void
1414 run_schedule(const char *schedule, test_function tfunc)
1416 #define MAX_PARALLEL_TESTS 100
1417 char *tests[MAX_PARALLEL_TESTS];
1418 _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1419 _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1420 _stringlist *tags[MAX_PARALLEL_TESTS];
1421 PID_TYPE pids[MAX_PARALLEL_TESTS];
1422 int statuses[MAX_PARALLEL_TESTS];
1423 _stringlist *ignorelist = NULL;
1424 char scbuf[1024];
1425 FILE *scf;
1426 int line_num = 0;
1428 memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1429 memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1430 memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
1432 scf = fopen(schedule, "r");
1433 if (!scf)
1435 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1436 progname, schedule, strerror(errno));
1437 exit_nicely(2);
1440 while (fgets(scbuf, sizeof(scbuf), scf))
1442 char *test = NULL;
1443 char *c;
1444 int num_tests;
1445 bool inword;
1446 int i;
1448 line_num++;
1450 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
1452 if (resultfiles[i] == NULL)
1453 break;
1454 free_stringlist(&resultfiles[i]);
1455 free_stringlist(&expectfiles[i]);
1456 free_stringlist(&tags[i]);
1459 /* strip trailing whitespace, especially the newline */
1460 i = strlen(scbuf);
1461 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1462 scbuf[--i] = '\0';
1464 if (scbuf[0] == '\0' || scbuf[0] == '#')
1465 continue;
1466 if (strncmp(scbuf, "test: ", 6) == 0)
1467 test = scbuf + 6;
1468 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1470 c = scbuf + 8;
1471 while (*c && isspace((unsigned char) *c))
1472 c++;
1473 add_stringlist_item(&ignorelist, c);
1476 * Note: ignore: lines do not run the test, they just say that
1477 * failure of this test when run later on is to be ignored. A bit
1478 * odd but that's how the shell-script version did it.
1480 continue;
1482 else
1484 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1485 schedule, line_num, scbuf);
1486 exit_nicely(2);
1489 num_tests = 0;
1490 inword = false;
1491 for (c = test; *c; c++)
1493 if (isspace((unsigned char) *c))
1495 *c = '\0';
1496 inword = false;
1498 else if (!inword)
1500 if (num_tests >= MAX_PARALLEL_TESTS)
1502 /* can't print scbuf here, it's already been trashed */
1503 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1504 schedule, line_num);
1505 exit_nicely(2);
1507 tests[num_tests] = c;
1508 num_tests++;
1509 inword = true;
1513 if (num_tests == 0)
1515 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1516 schedule, line_num, scbuf);
1517 exit_nicely(2);
1520 if (num_tests == 1)
1522 status(_("test %-20s ... "), tests[0]);
1523 pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1524 wait_for_tests(pids, statuses, NULL, 1);
1525 /* status line is finished below */
1527 else if (max_connections > 0 && max_connections < num_tests)
1529 int oldest = 0;
1531 status(_("parallel group (%d tests, in groups of %d): "),
1532 num_tests, max_connections);
1533 for (i = 0; i < num_tests; i++)
1535 if (i - oldest >= max_connections)
1537 wait_for_tests(pids + oldest, statuses + oldest,
1538 tests + oldest, i - oldest);
1539 oldest = i;
1541 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1543 wait_for_tests(pids + oldest, statuses + oldest,
1544 tests + oldest, i - oldest);
1545 status_end();
1547 else
1549 status(_("parallel group (%d tests): "), num_tests);
1550 for (i = 0; i < num_tests; i++)
1552 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1554 wait_for_tests(pids, statuses, tests, num_tests);
1555 status_end();
1558 /* Check results for all tests */
1559 for (i = 0; i < num_tests; i++)
1561 _stringlist *rl,
1562 *el,
1563 *tl;
1564 bool differ = false;
1566 if (num_tests > 1)
1567 status(_(" %-20s ... "), tests[i]);
1570 * Advance over all three lists simultaneously.
1572 * Compare resultfiles[j] with expectfiles[j] always. Tags are
1573 * optional but if there are tags, the tag list has the same
1574 * length as the other two lists.
1576 for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1577 rl != NULL; /* rl and el have the same length */
1578 rl = rl->next, el = el->next)
1580 bool newdiff;
1582 if (tl)
1583 tl = tl->next; /* tl has the same length as rl and el
1584 * if it exists */
1586 newdiff = results_differ(tests[i], rl->str, el->str);
1587 if (newdiff && tl)
1589 printf("%s ", tl->str);
1591 differ |= newdiff;
1594 if (differ)
1596 bool ignore = false;
1597 _stringlist *sl;
1599 for (sl = ignorelist; sl != NULL; sl = sl->next)
1601 if (strcmp(tests[i], sl->str) == 0)
1603 ignore = true;
1604 break;
1607 if (ignore)
1609 status(_("failed (ignored)"));
1610 fail_ignore_count++;
1612 else
1614 status(_("FAILED"));
1615 fail_count++;
1618 else
1620 status(_("ok"));
1621 success_count++;
1624 if (statuses[i] != 0)
1625 log_child_failure(statuses[i]);
1627 status_end();
1631 fclose(scf);
1635 * Run a single test
1637 static void
1638 run_single_test(const char *test, test_function tfunc)
1640 PID_TYPE pid;
1641 int exit_status;
1642 _stringlist *resultfiles = NULL;
1643 _stringlist *expectfiles = NULL;
1644 _stringlist *tags = NULL;
1645 _stringlist *rl,
1646 *el,
1647 *tl;
1648 bool differ = false;
1650 status(_("test %-20s ... "), test);
1651 pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
1652 wait_for_tests(&pid, &exit_status, NULL, 1);
1655 * Advance over all three lists simultaneously.
1657 * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1658 * but if there are tags, the tag list has the same length as the other
1659 * two lists.
1661 for (rl = resultfiles, el = expectfiles, tl = tags;
1662 rl != NULL; /* rl and el have the same length */
1663 rl = rl->next, el = el->next)
1665 bool newdiff;
1667 if (tl)
1668 tl = tl->next; /* tl has the same length as rl and el if it
1669 * exists */
1671 newdiff = results_differ(test, rl->str, el->str);
1672 if (newdiff && tl)
1674 printf("%s ", tl->str);
1676 differ |= newdiff;
1679 if (differ)
1681 status(_("FAILED"));
1682 fail_count++;
1684 else
1686 status(_("ok"));
1687 success_count++;
1690 if (exit_status != 0)
1691 log_child_failure(exit_status);
1693 status_end();
1697 * Create the summary-output files (making them empty if already existing)
1699 static void
1700 open_result_files(void)
1702 char file[MAXPGPATH];
1703 FILE *difffile;
1705 /* create the log file (copy of running status output) */
1706 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1707 logfilename = strdup(file);
1708 logfile = fopen(logfilename, "w");
1709 if (!logfile)
1711 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1712 progname, logfilename, strerror(errno));
1713 exit_nicely(2);
1716 /* create the diffs file as empty */
1717 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1718 difffilename = strdup(file);
1719 difffile = fopen(difffilename, "w");
1720 if (!difffile)
1722 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1723 progname, difffilename, strerror(errno));
1724 exit_nicely(2);
1726 /* we don't keep the diffs file open continuously */
1727 fclose(difffile);
1729 /* also create the output directory if not present */
1730 snprintf(file, sizeof(file), "%s/results", outputdir);
1731 if (!directory_exists(file))
1732 make_directory(file);
1735 static void
1736 drop_database_if_exists(const char *dbname)
1738 header(_("dropping database \"%s\""), dbname);
1739 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
1742 static void
1743 create_database(const char *dbname)
1745 _stringlist *sl;
1748 * We use template0 so that any installation-local cruft in template1 will
1749 * not mess up the tests.
1751 header(_("creating database \"%s\""), dbname);
1752 if (encoding)
1753 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname, encoding);
1754 else
1755 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0", dbname);
1756 psql_command(dbname,
1757 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1758 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1759 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1760 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1761 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1762 dbname, dbname, dbname, dbname, dbname);
1765 * Install any requested procedural languages
1767 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1769 header(_("installing %s"), sl->str);
1770 psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
1774 static void
1775 drop_role_if_exists(const char *rolename)
1777 header(_("dropping role \"%s\""), rolename);
1778 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
1781 static void
1782 create_role(const char *rolename, const _stringlist * granted_dbs)
1784 header(_("creating role \"%s\""), rolename);
1785 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
1786 for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
1788 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
1789 granted_dbs->str, rolename);
1793 static char *
1794 make_absolute_path(const char *in)
1796 char *result;
1798 if (is_absolute_path(in))
1799 result = strdup(in);
1800 else
1802 static char cwdbuf[MAXPGPATH];
1804 if (!cwdbuf[0])
1806 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1808 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1809 exit_nicely(2);
1813 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
1814 sprintf(result, "%s/%s", cwdbuf, in);
1817 canonicalize_path(result);
1818 return result;
1821 static void
1822 help(void)
1824 printf(_("PostgreSQL regression test driver\n"));
1825 printf(_("\n"));
1826 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1827 printf(_("\n"));
1828 printf(_("Options:\n"));
1829 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1830 printf(_(" --debug turn on debug mode in programs that are run\n"));
1831 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1832 printf(_(" --load-language=lang load the named language before running the\n"));
1833 printf(_(" tests; can appear multiple times\n"));
1834 printf(_(" --create-role=ROLE create the specified role before testing\n"));
1835 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1836 printf(_(" (default is 0 meaning unlimited)\n"));
1837 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1838 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1839 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1840 printf(_(" (can be used multiple times to concatenate)\n"));
1841 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
1842 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1843 printf(_("\n"));
1844 printf(_("Options for \"temp-install\" mode:\n"));
1845 printf(_(" --no-locale use C locale\n"));
1846 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1847 printf(_(" --temp-port=PORT port number to start temp postmaster on\n"));
1848 printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
1849 printf(_("\n"));
1850 printf(_("Options for using an existing installation:\n"));
1851 printf(_(" --host=HOST use postmaster running on HOST\n"));
1852 printf(_(" --port=PORT use postmaster running at PORT\n"));
1853 printf(_(" --user=USER connect as USER\n"));
1854 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1855 printf(_("\n"));
1856 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1857 printf(_("if the tests could not be run for some reason.\n"));
1858 printf(_("\n"));
1859 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1863 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
1865 _stringlist *sl;
1866 int c;
1867 int i;
1868 int option_index;
1869 char buf[MAXPGPATH * 4];
1871 static struct option long_options[] = {
1872 {"help", no_argument, NULL, 'h'},
1873 {"version", no_argument, NULL, 'V'},
1874 {"dbname", required_argument, NULL, 1},
1875 {"debug", no_argument, NULL, 2},
1876 {"inputdir", required_argument, NULL, 3},
1877 {"load-language", required_argument, NULL, 4},
1878 {"max-connections", required_argument, NULL, 5},
1879 {"multibyte", required_argument, NULL, 6},
1880 {"outputdir", required_argument, NULL, 7},
1881 {"schedule", required_argument, NULL, 8},
1882 {"temp-install", required_argument, NULL, 9},
1883 {"no-locale", no_argument, NULL, 10},
1884 {"top-builddir", required_argument, NULL, 11},
1885 {"temp-port", required_argument, NULL, 12},
1886 {"host", required_argument, NULL, 13},
1887 {"port", required_argument, NULL, 14},
1888 {"user", required_argument, NULL, 15},
1889 {"psqldir", required_argument, NULL, 16},
1890 {"dlpath", required_argument, NULL, 17},
1891 {"create-role", required_argument, NULL, 18},
1892 {"temp-config", required_argument, NULL, 19},
1893 {NULL, 0, NULL, 0}
1896 progname = get_progname(argv[0]);
1897 set_pglocale_pgservice(argv[0], "pg_regress");
1899 #ifndef HAVE_UNIX_SOCKETS
1900 /* no unix domain sockets available, so change default */
1901 hostname = "localhost";
1902 #endif
1905 * We call the initialization function here because that way we can set
1906 * default parameters and let them be overwritten by the commandline.
1908 ifunc();
1910 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1912 switch (c)
1914 case 'h':
1915 help();
1916 exit_nicely(0);
1917 case 'V':
1918 puts("pg_regress (PostgreSQL) " PG_VERSION);
1919 exit_nicely(0);
1920 case 1:
1923 * If a default database was specified, we need to remove it
1924 * before we add the specified one.
1926 free_stringlist(&dblist);
1927 split_to_stringlist(strdup(optarg), ", ", &dblist);
1928 break;
1929 case 2:
1930 debug = true;
1931 break;
1932 case 3:
1933 inputdir = strdup(optarg);
1934 break;
1935 case 4:
1936 add_stringlist_item(&loadlanguage, optarg);
1937 break;
1938 case 5:
1939 max_connections = atoi(optarg);
1940 break;
1941 case 6:
1942 encoding = strdup(optarg);
1943 break;
1944 case 7:
1945 outputdir = strdup(optarg);
1946 break;
1947 case 8:
1948 add_stringlist_item(&schedulelist, optarg);
1949 break;
1950 case 9:
1951 temp_install = make_absolute_path(optarg);
1952 break;
1953 case 10:
1954 nolocale = true;
1955 break;
1956 case 11:
1957 top_builddir = strdup(optarg);
1958 break;
1959 case 12:
1961 int p = atoi(optarg);
1963 /* Since Makefile isn't very bright, check port range */
1964 if (p >= 1024 && p <= 65535)
1965 temp_port = p;
1967 break;
1968 case 13:
1969 hostname = strdup(optarg);
1970 break;
1971 case 14:
1972 port = atoi(optarg);
1973 break;
1974 case 15:
1975 user = strdup(optarg);
1976 break;
1977 case 16:
1978 /* "--psqldir=" should mean to use PATH */
1979 if (strlen(optarg))
1980 psqldir = strdup(optarg);
1981 break;
1982 case 17:
1983 dlpath = strdup(optarg);
1984 break;
1985 case 18:
1986 split_to_stringlist(strdup(optarg), ", ", &extraroles);
1987 break;
1988 case 19:
1989 temp_config = strdup(optarg);
1990 break;
1991 default:
1992 /* getopt_long already emitted a complaint */
1993 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
1994 progname);
1995 exit_nicely(2);
2000 * if we still have arguments, they are extra tests to run
2002 while (argc - optind >= 1)
2004 add_stringlist_item(&extra_tests, argv[optind]);
2005 optind++;
2008 if (temp_install)
2009 port = temp_port;
2011 inputdir = make_absolute_path(inputdir);
2012 outputdir = make_absolute_path(outputdir);
2013 dlpath = make_absolute_path(dlpath);
2016 * Initialization
2018 open_result_files();
2020 initialize_environment();
2022 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2023 unlimit_core_size();
2024 #endif
2026 if (temp_install)
2029 * Prepare the temp installation
2031 if (!top_builddir)
2033 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
2034 exit_nicely(2);
2037 if (directory_exists(temp_install))
2039 header(_("removing existing temp installation"));
2040 rmtree(temp_install, true);
2043 header(_("creating temporary installation"));
2045 /* make the temp install top directory */
2046 make_directory(temp_install);
2048 /* and a directory for log files */
2049 snprintf(buf, sizeof(buf), "%s/log", outputdir);
2050 if (!directory_exists(buf))
2051 make_directory(buf);
2053 /* "make install" */
2054 #ifndef WIN32_ONLY_COMPILER
2055 snprintf(buf, sizeof(buf),
2056 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2057 makeprog, top_builddir, temp_install, outputdir);
2058 #else
2059 snprintf(buf, sizeof(buf),
2060 SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
2061 top_builddir, temp_install, outputdir);
2062 #endif
2063 if (system(buf))
2065 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2066 exit_nicely(2);
2069 /* initdb */
2070 header(_("initializing database system"));
2071 snprintf(buf, sizeof(buf),
2072 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
2073 bindir, temp_install, datadir,
2074 debug ? " --debug" : "",
2075 nolocale ? " --no-locale" : "",
2076 outputdir);
2077 if (system(buf))
2079 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2080 exit_nicely(2);
2083 /* add any extra config specified to the postgresql.conf */
2084 if (temp_config != NULL)
2086 FILE *extra_conf;
2087 FILE *pg_conf;
2088 char line_buf[1024];
2090 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
2091 pg_conf = fopen(buf, "a");
2092 if (pg_conf == NULL)
2094 fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2095 exit_nicely(2);
2097 extra_conf = fopen(temp_config, "r");
2098 if (extra_conf == NULL)
2100 fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2101 exit_nicely(2);
2103 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2104 fputs(line_buf, pg_conf);
2105 fclose(extra_conf);
2106 fclose(pg_conf);
2110 * Start the temp postmaster
2112 header(_("starting postmaster"));
2113 snprintf(buf, sizeof(buf),
2114 SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
2115 bindir, temp_install,
2116 debug ? " -d 5" : "",
2117 hostname ? hostname : "",
2118 outputdir);
2119 postmaster_pid = spawn_process(buf);
2120 if (postmaster_pid == INVALID_PID)
2122 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2123 progname, strerror(errno));
2124 exit_nicely(2);
2128 * Wait till postmaster is able to accept connections (normally only a
2129 * second or so, but Cygwin is reportedly *much* slower). Don't wait
2130 * forever, however.
2132 snprintf(buf, sizeof(buf),
2133 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
2134 bindir, DEVNULL, DEVNULL);
2135 for (i = 0; i < 60; i++)
2137 /* Done if psql succeeds */
2138 if (system(buf) == 0)
2139 break;
2142 * Fail immediately if postmaster has exited
2144 #ifndef WIN32
2145 if (kill(postmaster_pid, 0) != 0)
2146 #else
2147 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2148 #endif
2150 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2151 exit_nicely(2);
2154 pg_usleep(1000000L);
2156 if (i >= 60)
2158 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2161 * If we get here, the postmaster is probably wedged somewhere in
2162 * startup. Try to kill it ungracefully rather than leaving a
2163 * stuck postmaster that might interfere with subsequent test
2164 * attempts.
2166 #ifndef WIN32
2167 if (kill(postmaster_pid, SIGKILL) != 0 &&
2168 errno != ESRCH)
2169 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2170 progname, strerror(errno));
2171 #else
2172 if (TerminateProcess(postmaster_pid, 255) == 0)
2173 fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"),
2174 progname, GetLastError());
2175 #endif
2177 exit_nicely(2);
2180 postmaster_running = true;
2182 printf(_("running on port %d with pid %lu\n"),
2183 temp_port, (unsigned long) postmaster_pid);
2185 else
2188 * Using an existing installation, so may need to get rid of
2189 * pre-existing database(s) and role(s)
2191 for (sl = dblist; sl; sl = sl->next)
2192 drop_database_if_exists(sl->str);
2193 for (sl = extraroles; sl; sl = sl->next)
2194 drop_role_if_exists(sl->str);
2198 * Create the test database(s) and role(s)
2200 for (sl = dblist; sl; sl = sl->next)
2201 create_database(sl->str);
2202 for (sl = extraroles; sl; sl = sl->next)
2203 create_role(sl->str, dblist);
2206 * Ready to run the tests
2208 header(_("running regression test queries"));
2210 for (sl = schedulelist; sl != NULL; sl = sl->next)
2212 run_schedule(sl->str, tfunc);
2215 for (sl = extra_tests; sl != NULL; sl = sl->next)
2217 run_single_test(sl->str, tfunc);
2221 * Shut down temp installation's postmaster
2223 if (temp_install)
2225 header(_("shutting down postmaster"));
2226 stop_postmaster();
2229 fclose(logfile);
2232 * Emit nice-looking summary message
2234 if (fail_count == 0 && fail_ignore_count == 0)
2235 snprintf(buf, sizeof(buf),
2236 _(" All %d tests passed. "),
2237 success_count);
2238 else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2239 snprintf(buf, sizeof(buf),
2240 _(" %d of %d tests passed, %d failed test(s) ignored. "),
2241 success_count,
2242 success_count + fail_ignore_count,
2243 fail_ignore_count);
2244 else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2245 snprintf(buf, sizeof(buf),
2246 _(" %d of %d tests failed. "),
2247 fail_count,
2248 success_count + fail_count);
2249 else
2250 /* fail_count>0 && fail_ignore_count>0 */
2251 snprintf(buf, sizeof(buf),
2252 _(" %d of %d tests failed, %d of these failures ignored. "),
2253 fail_count + fail_ignore_count,
2254 success_count + fail_count + fail_ignore_count,
2255 fail_ignore_count);
2257 putchar('\n');
2258 for (i = strlen(buf); i > 0; i--)
2259 putchar('=');
2260 printf("\n%s\n", buf);
2261 for (i = strlen(buf); i > 0; i--)
2262 putchar('=');
2263 putchar('\n');
2264 putchar('\n');
2266 if (file_size(difffilename) > 0)
2268 printf(_("The differences that caused some tests to fail can be viewed in the\n"
2269 "file \"%s\". A copy of the test summary that you see\n"
2270 "above is saved in the file \"%s\".\n\n"),
2271 difffilename, logfilename);
2273 else
2275 unlink(difffilename);
2276 unlink(logfilename);
2279 if (fail_count != 0)
2280 exit_nicely(1);
2282 return 0;