diff options
author | Diego Elio Pettenò <flameeyes@gentoo.org> | 2009-09-26 09:21:39 +0000 |
---|---|---|
committer | Diego Elio Pettenò <flameeyes@gentoo.org> | 2009-09-26 09:21:39 +0000 |
commit | 7e91979646858608bdd9cb5b5d76f051178b429e (patch) | |
tree | f822f9dc16cb847bc4aba87fb173e74937e6c715 /dev-db | |
parent | Move patches on a patchset on mirrors. (diff) | |
download | historical-7e91979646858608bdd9cb5b5d76f051178b429e.tar.gz historical-7e91979646858608bdd9cb5b5d76f051178b429e.tar.bz2 historical-7e91979646858608bdd9cb5b5d76f051178b429e.zip |
Remove a probably-fluke .orig file in patch, reduces size from over 60K to less than 10.
Package-Manager: portage-2.2_rc42/cvs/Linux x86_64
Diffstat (limited to 'dev-db')
-rw-r--r-- | dev-db/postgresql-server/ChangeLog | 7 | ||||
-rw-r--r-- | dev-db/postgresql-server/Manifest | 14 | ||||
-rw-r--r-- | dev-db/postgresql-server/files/postgresql-8.3-server.patch | 2224 |
3 files changed, 18 insertions, 2227 deletions
diff --git a/dev-db/postgresql-server/ChangeLog b/dev-db/postgresql-server/ChangeLog index d87cd3de30b2..296b61220664 100644 --- a/dev-db/postgresql-server/ChangeLog +++ b/dev-db/postgresql-server/ChangeLog @@ -1,6 +1,11 @@ # ChangeLog for dev-db/postgresql-server # Copyright 1999-2009 Gentoo Foundation; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/dev-db/postgresql-server/ChangeLog,v 1.21 2009/09/09 22:58:27 patrick Exp $ +# $Header: /var/cvsroot/gentoo-x86/dev-db/postgresql-server/ChangeLog,v 1.22 2009/09/26 09:21:39 flameeyes Exp $ + + 26 Sep 2009; Diego E. Pettenò <flameeyes@gentoo.org> + files/postgresql-8.3-server.patch: + Remove a probably-fluke .orig file in patch, reduces size from over 60K to + less than 10. *postgresql-server-8.0.22 (09 Sep 2009) diff --git a/dev-db/postgresql-server/Manifest b/dev-db/postgresql-server/Manifest index 4677e3e5c05b..c60642fb99df 100644 --- a/dev-db/postgresql-server/Manifest +++ b/dev-db/postgresql-server/Manifest @@ -1,3 +1,6 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + AUX postgresql-7.3-cubeparse.patch 1296 RMD160 9b9c0fcf4d58fb989ae77d9ada4588b1876400a6 SHA1 c128746e9938d7aaa4f2be6521530d07c7e207a8 SHA256 1844950b55509b83f38bfdd113350df7422f96ca4c773def6d38ca2f48fcfada AUX postgresql-7.3-regress.patch 3294 RMD160 babb74fa25f69bdc5b7a31fc590cc9b8c56b6cb8 SHA1 32be69b830f7fb93b39bba085a240a57b63ce16a SHA256 89f552ebe592677887c086b92c16104b7db47839ad889c3f91546191005d1016 AUX postgresql-7.3-server.patch 2773 RMD160 14db25b2a9f20b6f1e6c87b2aea1879b3c9873f9 SHA1 605a4efee3a05922a4387206f807c68c2625aa9c SHA256 b963985a5c6fadbb79b359549d482ebd108008eaf1755fbc29ff500bd9677b2f @@ -15,7 +18,7 @@ AUX postgresql-8.1-server.patch 6862 RMD160 94dc4c22f1f480bf5844f6e654d8a4e05340 AUX postgresql-8.2-common.patch 2640 RMD160 b25ba915d5d6ad9c12c1d51426363c196b830923 SHA1 7b946d57bfed34e2e7e1338c3ab3004341d7ab12 SHA256 36ca9cb4f26424c302fdd704b7c1a268e87612afa3006bf008d4594dabe080f8 AUX postgresql-8.2-server.patch 5319 RMD160 9aae5832defd2e43879246e773fd1aada0680716 SHA1 ea726704fc85118c27f511bfd9324b136ced3eb1 SHA256 2687fa5159a34da59e36af4c894f43b2136e8e88c965a682607cb48acb61d8ee AUX postgresql-8.3-common.patch 2641 RMD160 0822bf1512457e91d5f32f9d192de6f197db9c55 SHA1 e4bdbd5eee1023e8f0b42ef408b34b57495d1e2b SHA256 e416c26d9c3d266b306ddbc0a2b648054739b7ace35e2b4e449fbdaf094bc197 -AUX postgresql-8.3-server.patch 66296 RMD160 6acd5dec3b411d0439bab47a344406df25c08b7a SHA1 fca417c169d5de6c2ea036ab80a4ce02665ae881 SHA256 74684e07df2ff15f3c10d4f586cd72fba51c996ab9a97b6aee11f79987fc4de6 +AUX postgresql-8.3-server.patch 8546 RMD160 b3bfaadf019de8a6f03af9c524963b3b41b2be3c SHA1 d778e45937b18af05ca2c09b75cd5ed818c4829d SHA256 84e5a19c636b22963cf698af1a976893d52996ba9e8cb6e201243eabf50031f2 AUX postgresql-8.3.1-server.patch 6823 RMD160 f9dcc246eca1251526b94aa81fc8f3d5a02c3b76 SHA1 7ae8c9764d662364392d98f686060e22da2dfa46 SHA256 0e3684ce6bb03f860501819985a295d72c7579e1e94ddd1239086a38c0f4a105 AUX postgresql-8.4-common.patch 2058 RMD160 14e61a791fb1deaa327f90d207526fabfa35c4de SHA1 315543042274e3802f429fefe83568e8801078f3 SHA256 03b613fcb816b455eb92708e8095b8a0685f4c6992f90288295e1c6193af70b4 AUX postgresql-8.4-server.patch 7806 RMD160 99ab77e553987869e3243a895b4b6c4afdf39268 SHA1 ccb552141347e4545db78e73012509c6ecc7a1e4 SHA256 48b63ec1f6b61e7c167a7cb754fc6c278d56654e57f3b10678323f35984077ae @@ -69,5 +72,12 @@ EBUILD postgresql-server-8.3.7.ebuild 9662 RMD160 11262aaf1d4dc4bc7084afcab606c3 EBUILD postgresql-server-8.3.8.ebuild 9664 RMD160 fafd2872c51483e20c58cfac2c311d15d9070099 SHA1 d2de5eecb2c9835b5dd6e970744ba36fe1467c37 SHA256 924b11179ea873c3d1975057ad25a466eb135bb793a3589eb810a7015765d0c3 EBUILD postgresql-server-8.4.0.ebuild 9216 RMD160 0dab320e195d4e1562bfd79282eb019ee3a72d04 SHA1 66e8bdd80387703d6749c11c5ab46f387104c5da SHA256 275a7e4ba892f090a1da8593c30521f38f74f17d1a2470f87cb5255a56d16269 EBUILD postgresql-server-8.4.1.ebuild 9216 RMD160 9f4378f69675af8b56a3b77ef2919aa4d8f9bb48 SHA1 70c86aaa5aba5412cf8cf78acd2b323da0098cff SHA256 5d39ac495184ab1cb2952842b97b32240c1e1efe10cc185cb5ab9497d53d088c -MISC ChangeLog 13622 RMD160 9157132ffe1db3868748d49a2244c42632286f26 SHA1 a0bb03f9ae231e12cad974ce49d0ff46adea5860 SHA256 fe7b5356fc4d56beae066df279f93746394367eeef686f334fc1c8d69fc618b9 +MISC ChangeLog 13811 RMD160 f336d0e78d144c741b4fcd13caa3416c6be85aa1 SHA1 6cd70649e1ec13693074d2f00620a72e7992ebf0 SHA256 5eba04aa55d454c729574a28a1e46b7e4151518cbaa92f5568c893b855423a19 MISC metadata.xml 278 RMD160 70d8f6a6bc3d6619380cee3c0bc2179cf6a5bf28 SHA1 ca266604cf761d9ea76b5ec298ac553156c1c21e SHA256 0ec3e7bdc08e61c19df6ef7f5a1a5a2d2aeabb001c2efca4bdfe947e71a450b0 +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.11 (GNU/Linux) + +iEYEARECAAYFAkq93R8ACgkQAiZjviIA2Xhl6wCfdpHEzUy2T8nbBoZlSYdQA+nA +ZfEAoLmgPkEA8gYjHsq/7oO0xuqzox/y +=WSxw +-----END PGP SIGNATURE----- diff --git a/dev-db/postgresql-server/files/postgresql-8.3-server.patch b/dev-db/postgresql-server/files/postgresql-8.3-server.patch index 270c07887871..ffa4d23f50ee 100644 --- a/dev-db/postgresql-server/files/postgresql-8.3-server.patch +++ b/dev-db/postgresql-server/files/postgresql-8.3-server.patch @@ -223,2227 +223,3 @@ diff -Naur postgresql-8.3.3.orig/src/test/regress/pg_regress.c postgresql-8.3.3/ { /* Done if psql succeeds */ diff -Naur postgresql-8.3.3.orig/src/test/regress/pg_regress.c.orig postgresql-8.3.3/src/test/regress/pg_regress.c.orig ---- postgresql-8.3.3.orig/src/test/regress/pg_regress.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ postgresql-8.3.3/src/test/regress/pg_regress.c.orig 2008-03-31 03:32:01.000000000 +0200 -@@ -0,0 +1,2221 @@ -+/*------------------------------------------------------------------------- -+ * -+ * pg_regress --- regression test driver -+ * -+ * This is a C implementation of the previous shell script for running -+ * the regression tests, and should be mostly compatible with it. -+ * Initial author of C translation: Magnus Hagander -+ * -+ * This code is released under the terms of the PostgreSQL License. -+ * -+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ * -+ * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.41.2.2 2008/03/31 01:32:01 tgl Exp $ -+ * -+ *------------------------------------------------------------------------- -+ */ -+ -+#include "pg_regress.h" -+ -+#include <ctype.h> -+#include <sys/stat.h> -+#include <sys/wait.h> -+#include <signal.h> -+#include <unistd.h> -+ -+#ifdef HAVE_SYS_RESOURCE_H -+#include <sys/time.h> -+#include <sys/resource.h> -+#endif -+ -+#include "getopt_long.h" -+#include "pg_config_paths.h" -+ -+/* for resultmap we need a list of pairs of strings */ -+typedef struct _resultmap -+{ -+ char *test; -+ char *type; -+ char *resultfile; -+ struct _resultmap *next; -+} _resultmap; -+ -+/* -+ * Values obtained from pg_config_paths.h and Makefile. The PG installation -+ * paths are only used in temp_install mode: we use these strings to find -+ * out where "make install" will put stuff under the temp_install directory. -+ * In non-temp_install mode, the only thing we need is the location of psql, -+ * which we expect to find in psqldir, or in the PATH if psqldir isn't given. -+ */ -+char *bindir = PGBINDIR; -+char *libdir = LIBDIR; -+char *datadir = PGSHAREDIR; -+char *host_platform = HOST_TUPLE; -+ -+#ifndef WIN32_ONLY_COMPILER -+static char *makeprog = MAKEPROG; -+#endif -+ -+#ifndef WIN32 /* not used in WIN32 case */ -+static char *shellprog = SHELLPROG; -+#endif -+ -+/* currently we can use the same diff switches on all platforms */ -+const char *basic_diff_opts = "-w"; -+const char *pretty_diff_opts = "-w -C3"; -+ -+/* options settable from command line */ -+_stringlist *dblist = NULL; -+bool debug = false; -+char *inputdir = "."; -+char *outputdir = "."; -+char *psqldir = NULL; -+static _stringlist *loadlanguage = NULL; -+static int max_connections = 0; -+static char *encoding = NULL; -+static _stringlist *schedulelist = NULL; -+static _stringlist *extra_tests = NULL; -+static char *temp_install = NULL; -+static char *temp_config = NULL; -+static char *top_builddir = NULL; -+static int temp_port = 65432; -+static bool nolocale = false; -+static char *hostname = NULL; -+static int port = -1; -+static char *user = NULL; -+static char *srcdir = NULL; -+static _stringlist *extraroles = NULL; -+ -+/* internal variables */ -+static const char *progname; -+static char *logfilename; -+static FILE *logfile; -+static char *difffilename; -+ -+static _resultmap *resultmap = NULL; -+ -+static PID_TYPE postmaster_pid = INVALID_PID; -+static bool postmaster_running = false; -+ -+static int success_count = 0; -+static int fail_count = 0; -+static int fail_ignore_count = 0; -+ -+static bool directory_exists(const char *dir); -+static void make_directory(const char *dir); -+ -+static void -+header(const char *fmt,...) -+/* This extension allows gcc to check the format string for consistency with -+ the supplied arguments. */ -+__attribute__((format(printf, 1, 2))); -+static void -+status(const char *fmt,...) -+/* This extension allows gcc to check the format string for consistency with -+ the supplied arguments. */ -+__attribute__((format(printf, 1, 2))); -+static void -+psql_command(const char *database, const char *query,...) -+/* This extension allows gcc to check the format string for consistency with -+ the supplied arguments. */ -+__attribute__((format(printf, 2, 3))); -+ -+#ifdef WIN32 -+typedef BOOL(WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE); -+ -+/* Windows API define missing from MingW headers */ -+#define DISABLE_MAX_PRIVILEGE 0x1 -+#endif -+ -+/* -+ * allow core files if possible. -+ */ -+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) -+static void -+unlimit_core_size(void) -+{ -+ struct rlimit lim; -+ -+ getrlimit(RLIMIT_CORE, &lim); -+ if (lim.rlim_max == 0) -+ { -+ fprintf(stderr, -+ _("%s: cannot set core size,: disallowed by hard limit.\n"), -+ progname); -+ return; -+ } -+ else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max) -+ { -+ lim.rlim_cur = lim.rlim_max; -+ setrlimit(RLIMIT_CORE, &lim); -+ } -+} -+#endif -+ -+ -+/* -+ * Add an item at the end of a stringlist. -+ */ -+void -+add_stringlist_item(_stringlist ** listhead, const char *str) -+{ -+ _stringlist *newentry = malloc(sizeof(_stringlist)); -+ _stringlist *oldentry; -+ -+ newentry->str = strdup(str); -+ newentry->next = NULL; -+ if (*listhead == NULL) -+ *listhead = newentry; -+ else -+ { -+ for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next) -+ /* skip */ ; -+ oldentry->next = newentry; -+ } -+} -+ -+/* -+ * Free a stringlist. -+ */ -+static void -+free_stringlist(_stringlist ** listhead) -+{ -+ if (listhead == NULL || *listhead == NULL) -+ return; -+ if ((*listhead)->next != NULL) -+ free_stringlist(&((*listhead)->next)); -+ free((*listhead)->str); -+ free(*listhead); -+ *listhead = NULL; -+} -+ -+/* -+ * Split a delimited string into a stringlist -+ */ -+static void -+split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead) -+{ -+ char *sc = strdup(s); -+ char *token = strtok(sc, delim); -+ -+ while (token) -+ { -+ add_stringlist_item(listhead, token); -+ token = strtok(NULL, delim); -+ } -+ free(sc); -+} -+ -+/* -+ * Print a progress banner on stdout. -+ */ -+static void -+header(const char *fmt,...) -+{ -+ char tmp[64]; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vsnprintf(tmp, sizeof(tmp), fmt, ap); -+ va_end(ap); -+ -+ fprintf(stdout, "============== %-38s ==============\n", tmp); -+ fflush(stdout); -+} -+ -+/* -+ * Print "doing something ..." --- supplied text should not end with newline -+ */ -+static void -+status(const char *fmt,...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vfprintf(stdout, fmt, ap); -+ fflush(stdout); -+ va_end(ap); -+ -+ if (logfile) -+ { -+ va_start(ap, fmt); -+ vfprintf(logfile, fmt, ap); -+ va_end(ap); -+ } -+} -+ -+/* -+ * Done "doing something ..." -+ */ -+static void -+status_end(void) -+{ -+ fprintf(stdout, "\n"); -+ fflush(stdout); -+ if (logfile) -+ fprintf(logfile, "\n"); -+} -+ -+/* -+ * shut down temp postmaster -+ */ -+static void -+stop_postmaster(void) -+{ -+ if (postmaster_running) -+ { -+ /* We use pg_ctl to issue the kill and wait for stop */ -+ char buf[MAXPGPATH * 2]; -+ -+ /* On Windows, system() seems not to force fflush, so... */ -+ fflush(stdout); -+ fflush(stderr); -+ -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE, -+ bindir, temp_install); -+ system(buf); /* ignore exit status */ -+ postmaster_running = false; -+ } -+} -+ -+/* -+ * Always exit through here, not through plain exit(), to ensure we make -+ * an effort to shut down a temp postmaster -+ */ -+void -+exit_nicely(int code) -+{ -+ stop_postmaster(); -+ exit(code); -+} -+ -+/* -+ * Check whether string matches pattern -+ * -+ * In the original shell script, this function was implemented using expr(1), -+ * which provides basic regular expressions restricted to match starting at -+ * the string start (in conventional regex terms, there's an implicit "^" -+ * at the start of the pattern --- but no implicit "$" at the end). -+ * -+ * For now, we only support "." and ".*" as non-literal metacharacters, -+ * because that's all that anyone has found use for in resultmap. This -+ * code could be extended if more functionality is needed. -+ */ -+static bool -+string_matches_pattern(const char *str, const char *pattern) -+{ -+ while (*str && *pattern) -+ { -+ if (*pattern == '.' && pattern[1] == '*') -+ { -+ pattern += 2; -+ /* Trailing .* matches everything. */ -+ if (*pattern == '\0') -+ return true; -+ -+ /* -+ * Otherwise, scan for a text position at which we can match the -+ * rest of the pattern. -+ */ -+ while (*str) -+ { -+ /* -+ * Optimization to prevent most recursion: don't recurse -+ * unless first pattern char might match this text char. -+ */ -+ if (*str == *pattern || *pattern == '.') -+ { -+ if (string_matches_pattern(str, pattern)) -+ return true; -+ } -+ -+ str++; -+ } -+ -+ /* -+ * End of text with no match. -+ */ -+ return false; -+ } -+ else if (*pattern != '.' && *str != *pattern) -+ { -+ /* -+ * Not the single-character wildcard and no explicit match? Then -+ * time to quit... -+ */ -+ return false; -+ } -+ -+ str++; -+ pattern++; -+ } -+ -+ if (*pattern == '\0') -+ return true; /* end of pattern, so declare match */ -+ -+ /* End of input string. Do we have matching pattern remaining? */ -+ while (*pattern == '.' && pattern[1] == '*') -+ pattern += 2; -+ if (*pattern == '\0') -+ return true; /* end of pattern, so declare match */ -+ -+ return false; -+} -+ -+/* -+ * Replace all occurances of a string in a string with a different string. -+ * NOTE: Assumes there is enough room in the target buffer! -+ */ -+void -+replace_string(char *string, char *replace, char *replacement) -+{ -+ char *ptr; -+ -+ while ((ptr = strstr(string, replace)) != NULL) -+ { -+ char *dup = strdup(string); -+ -+ strlcpy(string, dup, ptr - string + 1); -+ strcat(string, replacement); -+ strcat(string, dup + (ptr - string) + strlen(replace)); -+ free(dup); -+ } -+} -+ -+/* -+ * Convert *.source found in the "source" directory, replacing certain tokens -+ * in the file contents with their intended values, and put the resulting files -+ * in the "dest" directory, replacing the ".source" prefix in their names with -+ * the given suffix. -+ */ -+static void -+convert_sourcefiles_in(char *source, char *dest, char *suffix) -+{ -+ char abs_srcdir[MAXPGPATH]; -+ char abs_builddir[MAXPGPATH]; -+ char testtablespace[MAXPGPATH]; -+ char indir[MAXPGPATH]; -+ struct stat st; -+ int ret; -+ char **name; -+ char **names; -+ int count = 0; -+ -+#ifdef WIN32 -+ char *c; -+#endif -+ -+ if (!getcwd(abs_builddir, sizeof(abs_builddir))) -+ { -+ fprintf(stderr, _("%s: could not get current directory: %s\n"), -+ progname, strerror(errno)); -+ exit_nicely(2); -+ } -+ -+ /* -+ * in a VPATH build, use the provided source directory; otherwise, use the -+ * current directory. -+ */ -+ if (srcdir) -+ strlcpy(abs_srcdir, srcdir, MAXPGPATH); -+ else -+ strlcpy(abs_srcdir, abs_builddir, MAXPGPATH); -+ -+ snprintf(indir, MAXPGPATH, "%s/%s", abs_srcdir, source); -+ -+ /* Check that indir actually exists and is a directory */ -+ ret = stat(indir, &st); -+ if (ret != 0 || !S_ISDIR(st.st_mode)) -+ { -+ /* -+ * No warning, to avoid noise in tests that do not have -+ * these directories; for example, ecpg, contrib and src/pl. -+ */ -+ return; -+ } -+ -+ names = pgfnames(indir); -+ if (!names) -+ /* Error logged in pgfnames */ -+ exit_nicely(2); -+ -+#ifdef WIN32 -+ /* in Win32, replace backslashes with forward slashes */ -+ for (c = abs_builddir; *c; c++) -+ if (*c == '\\') -+ *c = '/'; -+ for (c = abs_srcdir; *c; c++) -+ if (*c == '\\') -+ *c = '/'; -+#endif -+ -+ snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", abs_builddir); -+ -+#ifdef WIN32 -+ /* -+ * On Windows only, clean out the test tablespace dir, or create it if it -+ * doesn't exist. On other platforms we expect the Makefile to take -+ * care of that. (We don't migrate that functionality in here because -+ * it'd be harder to cope with platform-specific issues such as SELinux.) -+ * -+ * XXX it would be better if pg_regress.c had nothing at all to do with -+ * testtablespace, and this were handled by a .BAT file or similar on -+ * Windows. See pgsql-hackers discussion of 2008-01-18. -+ */ -+ if (directory_exists(testtablespace)) -+ rmtree(testtablespace, true); -+ make_directory(testtablespace); -+#endif -+ -+ /* finally loop on each file and do the replacement */ -+ for (name = names; *name; name++) -+ { -+ char srcfile[MAXPGPATH]; -+ char destfile[MAXPGPATH]; -+ char prefix[MAXPGPATH]; -+ FILE *infile, -+ *outfile; -+ char line[1024]; -+ -+ /* reject filenames not finishing in ".source" */ -+ if (strlen(*name) < 8) -+ continue; -+ if (strcmp(*name + strlen(*name) - 7, ".source") != 0) -+ continue; -+ -+ count++; -+ -+ /* build the full actual paths to open */ -+ snprintf(prefix, strlen(*name) - 6, "%s", *name); -+ snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name); -+ snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest, prefix, suffix); -+ -+ infile = fopen(srcfile, "r"); -+ if (!infile) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), -+ progname, srcfile, strerror(errno)); -+ exit_nicely(2); -+ } -+ outfile = fopen(destfile, "w"); -+ if (!outfile) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"), -+ progname, destfile, strerror(errno)); -+ exit_nicely(2); -+ } -+ while (fgets(line, sizeof(line), infile)) -+ { -+ replace_string(line, "@abs_srcdir@", abs_srcdir); -+ replace_string(line, "@abs_builddir@", abs_builddir); -+ replace_string(line, "@testtablespace@", testtablespace); -+ replace_string(line, "@DLSUFFIX@", DLSUFFIX); -+ fputs(line, outfile); -+ } -+ fclose(infile); -+ fclose(outfile); -+ } -+ -+ /* -+ * If we didn't process any files, complain because it probably means -+ * somebody neglected to pass the needed --srcdir argument. -+ */ -+ if (count <= 0) -+ { -+ fprintf(stderr, _("%s: no *.source files found in %s\n"), -+ progname, indir); -+ exit_nicely(2); -+ } -+ -+ pgfnames_cleanup(names); -+} -+ -+/* Create the .sql and .out files from the .source files, if any */ -+static void -+convert_sourcefiles(void) -+{ -+ convert_sourcefiles_in("input", "sql", "sql"); -+ convert_sourcefiles_in("output", "expected", "out"); -+} -+ -+/* -+ * Scan resultmap file to find which platform-specific expected files to use. -+ * -+ * The format of each line of the file is -+ * testname/hostplatformpattern=substitutefile -+ * where the hostplatformpattern is evaluated per the rules of expr(1), -+ * namely, it is a standard regular expression with an implicit ^ at the start. -+ * (We currently support only a very limited subset of regular expressions, -+ * see string_matches_pattern() above.) What hostplatformpattern will be -+ * matched against is the config.guess output. (In the shell-script version, -+ * we also provided an indication of whether gcc or another compiler was in -+ * use, but that facility isn't used anymore.) -+ */ -+static void -+load_resultmap(void) -+{ -+ char buf[MAXPGPATH]; -+ FILE *f; -+ -+ /* scan the file ... */ -+ snprintf(buf, sizeof(buf), "%s/resultmap", inputdir); -+ f = fopen(buf, "r"); -+ if (!f) -+ { -+ /* OK if it doesn't exist, else complain */ -+ if (errno == ENOENT) -+ return; -+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), -+ progname, buf, strerror(errno)); -+ exit_nicely(2); -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) -+ { -+ char *platform; -+ char *file_type; -+ char *expected; -+ int i; -+ -+ /* strip trailing whitespace, especially the newline */ -+ i = strlen(buf); -+ while (i > 0 && isspace((unsigned char) buf[i - 1])) -+ buf[--i] = '\0'; -+ -+ /* parse out the line fields */ -+ file_type = strchr(buf, ':'); -+ if (!file_type) -+ { -+ fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"), -+ buf); -+ exit_nicely(2); -+ } -+ *file_type++ = '\0'; -+ -+ platform = strchr(file_type, ':'); -+ if (!platform) -+ { -+ fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"), -+ buf); -+ exit_nicely(2); -+ } -+ *platform++ = '\0'; -+ expected = strchr(platform, '='); -+ if (!expected) -+ { -+ fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"), -+ buf); -+ exit_nicely(2); -+ } -+ *expected++ = '\0'; -+ -+ /* -+ * if it's for current platform, save it in resultmap list. Note: by -+ * adding at the front of the list, we ensure that in ambiguous cases, -+ * the last match in the resultmap file is used. This mimics the -+ * behavior of the old shell script. -+ */ -+ if (string_matches_pattern(host_platform, platform)) -+ { -+ _resultmap *entry = malloc(sizeof(_resultmap)); -+ -+ entry->test = strdup(buf); -+ entry->type = strdup(file_type); -+ entry->resultfile = strdup(expected); -+ entry->next = resultmap; -+ resultmap = entry; -+ } -+ } -+ fclose(f); -+} -+ -+/* -+ * Check in resultmap if we should be looking at a different file -+ */ -+static -+const char * -+get_expectfile(const char *testname, const char *file) -+{ -+ char *file_type; -+ _resultmap *rm; -+ -+ /* -+ * Determine the file type from the file name. This is just what is -+ * following the last dot in the file name. -+ */ -+ if (!file || !(file_type = strrchr(file, '.'))) -+ return NULL; -+ -+ file_type++; -+ -+ for (rm = resultmap; rm != NULL; rm = rm->next) -+ { -+ if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0) -+ { -+ return rm->resultfile; -+ } -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Handy subroutine for setting an environment variable "var" to "val" -+ */ -+static void -+doputenv(const char *var, const char *val) -+{ -+ char *s = malloc(strlen(var) + strlen(val) + 2); -+ -+ sprintf(s, "%s=%s", var, val); -+ putenv(s); -+} -+ -+/* -+ * Set the environment variable "pathname", prepending "addval" to its -+ * old value (if any). -+ */ -+static void -+add_to_path(const char *pathname, char separator, const char *addval) -+{ -+ char *oldval = getenv(pathname); -+ char *newval; -+ -+ if (!oldval || !oldval[0]) -+ { -+ /* no previous value */ -+ newval = malloc(strlen(pathname) + strlen(addval) + 2); -+ sprintf(newval, "%s=%s", pathname, addval); -+ } -+ else -+ { -+ newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3); -+ sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval); -+ } -+ putenv(newval); -+} -+ -+/* -+ * Prepare environment variables for running regression tests -+ */ -+static void -+initialize_environment(void) -+{ -+ char *tmp; -+ -+ /* -+ * Clear out any non-C locale settings -+ */ -+ unsetenv("LC_COLLATE"); -+ unsetenv("LC_CTYPE"); -+ unsetenv("LC_MONETARY"); -+ unsetenv("LC_MESSAGES"); -+ unsetenv("LC_NUMERIC"); -+ unsetenv("LC_TIME"); -+ unsetenv("LC_ALL"); -+ unsetenv("LANG"); -+ unsetenv("LANGUAGE"); -+ /* On Windows the default locale cannot be English, so force it */ -+#if defined(WIN32) || defined(__CYGWIN__) -+ putenv("LANG=en"); -+#endif -+ -+ /* -+ * Set multibyte as requested -+ */ -+ if (encoding) -+ doputenv("PGCLIENTENCODING", encoding); -+ else -+ unsetenv("PGCLIENTENCODING"); -+ -+ /* -+ * Set timezone and datestyle for datetime-related tests -+ */ -+ putenv("PGTZ=PST8PDT"); -+ putenv("PGDATESTYLE=Postgres, MDY"); -+ -+ if (temp_install) -+ { -+ /* -+ * Clear out any environment vars that might cause psql to connect to -+ * the wrong postmaster, or otherwise behave in nondefault ways. (Note -+ * we also use psql's -X switch consistently, so that ~/.psqlrc files -+ * won't mess things up.) Also, set PGPORT to the temp port, and set -+ * or unset PGHOST depending on whether we are using TCP or Unix -+ * sockets. -+ */ -+ unsetenv("PGDATABASE"); -+ unsetenv("PGUSER"); -+ unsetenv("PGSERVICE"); -+ unsetenv("PGSSLMODE"); -+ unsetenv("PGREQUIRESSL"); -+ unsetenv("PGCONNECT_TIMEOUT"); -+ unsetenv("PGDATA"); -+ if (hostname != NULL) -+ doputenv("PGHOST", hostname); -+ else -+ unsetenv("PGHOST"); -+ unsetenv("PGHOSTADDR"); -+ if (port != -1) -+ { -+ char s[16]; -+ -+ sprintf(s, "%d", port); -+ doputenv("PGPORT", s); -+ } -+ -+ /* -+ * Adjust path variables to point into the temp-install tree -+ */ -+ tmp = malloc(strlen(temp_install) + 32 + strlen(bindir)); -+ sprintf(tmp, "%s/install/%s", temp_install, bindir); -+ bindir = tmp; -+ -+ tmp = malloc(strlen(temp_install) + 32 + strlen(libdir)); -+ sprintf(tmp, "%s/install/%s", temp_install, libdir); -+ libdir = tmp; -+ -+ tmp = malloc(strlen(temp_install) + 32 + strlen(datadir)); -+ sprintf(tmp, "%s/install/%s", temp_install, datadir); -+ datadir = tmp; -+ -+ /* psql will be installed into temp-install bindir */ -+ psqldir = bindir; -+ -+ /* -+ * Set up shared library paths to include the temp install. -+ * -+ * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on -+ * Darwin, and maybe other Mach-based systems. LIBPATH is for AIX. -+ * Windows needs shared libraries in PATH (only those linked into -+ * executables, not dlopen'ed ones). Feel free to account for others -+ * as well. -+ */ -+ add_to_path("LD_LIBRARY_PATH", ':', libdir); -+ add_to_path("DYLD_LIBRARY_PATH", ':', libdir); -+ add_to_path("LIBPATH", ':', libdir); -+#if defined(WIN32) || defined(__CYGWIN__) -+ add_to_path("PATH", ';', libdir); -+#endif -+ } -+ else -+ { -+ const char *pghost; -+ const char *pgport; -+ -+ /* -+ * When testing an existing install, we honor existing environment -+ * variables, except if they're overridden by command line options. -+ */ -+ if (hostname != NULL) -+ { -+ doputenv("PGHOST", hostname); -+ unsetenv("PGHOSTADDR"); -+ } -+ if (port != -1) -+ { -+ char s[16]; -+ -+ sprintf(s, "%d", port); -+ doputenv("PGPORT", s); -+ } -+ if (user != NULL) -+ doputenv("PGUSER", user); -+ -+ /* -+ * Report what we're connecting to -+ */ -+ pghost = getenv("PGHOST"); -+ pgport = getenv("PGPORT"); -+#ifndef HAVE_UNIX_SOCKETS -+ if (!pghost) -+ pghost = "localhost"; -+#endif -+ -+ if (pghost && pgport) -+ printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport); -+ if (pghost && !pgport) -+ printf(_("(using postmaster on %s, default port)\n"), pghost); -+ if (!pghost && pgport) -+ printf(_("(using postmaster on Unix socket, port %s)\n"), pgport); -+ if (!pghost && !pgport) -+ printf(_("(using postmaster on Unix socket, default port)\n")); -+ } -+ -+ convert_sourcefiles(); -+ load_resultmap(); -+} -+ -+/* -+ * Issue a command via psql, connecting to the specified database -+ * -+ * Since we use system(), this doesn't return until the operation finishes -+ */ -+static void -+psql_command(const char *database, const char *query,...) -+{ -+ char query_formatted[1024]; -+ char query_escaped[2048]; -+ char psql_cmd[MAXPGPATH + 2048]; -+ va_list args; -+ char *s; -+ char *d; -+ -+ /* Generate the query with insertion of sprintf arguments */ -+ va_start(args, query); -+ vsnprintf(query_formatted, sizeof(query_formatted), query, args); -+ va_end(args); -+ -+ /* Now escape any shell double-quote metacharacters */ -+ d = query_escaped; -+ for (s = query_formatted; *s; s++) -+ { -+ if (strchr("\\\"$`", *s)) -+ *d++ = '\\'; -+ *d++ = *s; -+ } -+ *d = '\0'; -+ -+ /* And now we can build and execute the shell command */ -+ snprintf(psql_cmd, sizeof(psql_cmd), -+ SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE, -+ psqldir ? psqldir : "", -+ psqldir ? "/" : "", -+ query_escaped, -+ database); -+ -+ if (system(psql_cmd) != 0) -+ { -+ /* psql probably already reported the error */ -+ fprintf(stderr, _("command failed: %s\n"), psql_cmd); -+ exit_nicely(2); -+ } -+} -+ -+/* -+ * Spawn a process to execute the given shell command; don't wait for it -+ * -+ * Returns the process ID (or HANDLE) so we can wait for it later -+ */ -+PID_TYPE -+spawn_process(const char *cmdline) -+{ -+#ifndef WIN32 -+ pid_t pid; -+ -+ /* -+ * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here -+ * ... does anyone still care about systems where that doesn't work? -+ */ -+ fflush(stdout); -+ fflush(stderr); -+ if (logfile) -+ fflush(logfile); -+ -+ pid = fork(); -+ if (pid == -1) -+ { -+ fprintf(stderr, _("%s: could not fork: %s\n"), -+ progname, strerror(errno)); -+ exit_nicely(2); -+ } -+ if (pid == 0) -+ { -+ /* -+ * In child -+ * -+ * Instead of using system(), exec the shell directly, and tell it to -+ * "exec" the command too. This saves two useless processes per -+ * parallel test case. -+ */ -+ char *cmdline2 = malloc(strlen(cmdline) + 6); -+ -+ sprintf(cmdline2, "exec %s", cmdline); -+ execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL); -+ fprintf(stderr, _("%s: could not exec \"%s\": %s\n"), -+ progname, shellprog, strerror(errno)); -+ exit(1); /* not exit_nicely here... */ -+ } -+ /* in parent */ -+ return pid; -+#else -+ char *cmdline2; -+ BOOL b; -+ STARTUPINFO si; -+ PROCESS_INFORMATION pi; -+ HANDLE origToken; -+ HANDLE restrictedToken; -+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; -+ SID_AND_ATTRIBUTES dropSids[2]; -+ __CreateRestrictedToken _CreateRestrictedToken = NULL; -+ HANDLE Advapi32Handle; -+ -+ ZeroMemory(&si, sizeof(si)); -+ si.cb = sizeof(si); -+ -+ Advapi32Handle = LoadLibrary("ADVAPI32.DLL"); -+ if (Advapi32Handle != NULL) -+ { -+ _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken"); -+ } -+ -+ if (_CreateRestrictedToken == NULL) -+ { -+ if (Advapi32Handle != NULL) -+ FreeLibrary(Advapi32Handle); -+ fprintf(stderr, "ERROR: cannot create restricted tokens on this platform\n"); -+ exit_nicely(2); -+ } -+ -+ /* Open the current token to use as base for the restricted one */ -+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) -+ { -+ fprintf(stderr, "could not open process token: %lu\n", GetLastError()); -+ exit_nicely(2); -+ } -+ -+ /* Allocate list of SIDs to remove */ -+ ZeroMemory(&dropSids, sizeof(dropSids)); -+ if (!AllocateAndInitializeSid(&NtAuthority, 2, -+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) || -+ !AllocateAndInitializeSid(&NtAuthority, 2, -+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid)) -+ { -+ fprintf(stderr, "could not allocate SIDs: %lu\n", GetLastError()); -+ exit_nicely(2); -+ } -+ -+ b = _CreateRestrictedToken(origToken, -+ DISABLE_MAX_PRIVILEGE, -+ sizeof(dropSids) / sizeof(dropSids[0]), -+ dropSids, -+ 0, NULL, -+ 0, NULL, -+ &restrictedToken); -+ -+ FreeSid(dropSids[1].Sid); -+ FreeSid(dropSids[0].Sid); -+ CloseHandle(origToken); -+ FreeLibrary(Advapi32Handle); -+ -+ if (!b) -+ { -+ fprintf(stderr, "could not create restricted token: %lu\n", GetLastError()); -+ exit_nicely(2); -+ } -+ -+ cmdline2 = malloc(strlen(cmdline) + 8); -+ sprintf(cmdline2, "cmd /c %s", cmdline); -+ -+ if (!CreateProcessAsUser(restrictedToken, -+ NULL, -+ cmdline2, -+ NULL, -+ NULL, -+ TRUE, -+ CREATE_SUSPENDED, -+ NULL, -+ NULL, -+ &si, -+ &pi)) -+ { -+ fprintf(stderr, _("could not start process for \"%s\": %lu\n"), -+ cmdline2, GetLastError()); -+ exit_nicely(2); -+ } -+ -+#ifndef __CYGWIN__ -+ AddUserToDacl(pi.hProcess); -+#endif -+ -+ free(cmdline2); -+ -+ ResumeThread(pi.hThread); -+ CloseHandle(pi.hThread); -+ return pi.hProcess; -+#endif -+} -+ -+/* -+ * Count bytes in file -+ */ -+static long -+file_size(const char *file) -+{ -+ long r; -+ FILE *f = fopen(file, "r"); -+ -+ if (!f) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), -+ progname, file, strerror(errno)); -+ return -1; -+ } -+ fseek(f, 0, SEEK_END); -+ r = ftell(f); -+ fclose(f); -+ return r; -+} -+ -+/* -+ * Count lines in file -+ */ -+static int -+file_line_count(const char *file) -+{ -+ int c; -+ int l = 0; -+ FILE *f = fopen(file, "r"); -+ -+ if (!f) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), -+ progname, file, strerror(errno)); -+ return -1; -+ } -+ while ((c = fgetc(f)) != EOF) -+ { -+ if (c == '\n') -+ l++; -+ } -+ fclose(f); -+ return l; -+} -+ -+static bool -+file_exists(const char *file) -+{ -+ FILE *f = fopen(file, "r"); -+ -+ if (!f) -+ return false; -+ fclose(f); -+ return true; -+} -+ -+static bool -+directory_exists(const char *dir) -+{ -+ struct stat st; -+ -+ if (stat(dir, &st) != 0) -+ return false; -+ if (S_ISDIR(st.st_mode)) -+ return true; -+ return false; -+} -+ -+/* Create a directory */ -+static void -+make_directory(const char *dir) -+{ -+ if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0) -+ { -+ fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), -+ progname, dir, strerror(errno)); -+ exit_nicely(2); -+ } -+} -+ -+/* -+ * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9 -+ */ -+static char * -+get_alternative_expectfile(const char *expectfile, int i) -+{ -+ char *last_dot; -+ int ssize = strlen(expectfile) + 2 + 1; -+ char *tmp = (char *) malloc(ssize); -+ char *s = (char *) malloc(ssize); -+ -+ strcpy(tmp, expectfile); -+ last_dot = strrchr(tmp, '.'); -+ if (!last_dot) -+ return NULL; -+ *last_dot = '\0'; -+ snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1); -+ free(tmp); -+ return s; -+} -+ -+/* -+ * Run a "diff" command and also check that it didn't crash -+ */ -+static int -+run_diff(const char *cmd, const char *filename) -+{ -+ int r; -+ -+ r = system(cmd); -+ if (!WIFEXITED(r) || WEXITSTATUS(r) > 1) -+ { -+ fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd); -+ exit_nicely(2); -+ } -+#ifdef WIN32 -+ -+ /* -+ * On WIN32, if the 'diff' command cannot be found, system() returns 1, -+ * but produces nothing to stdout, so we check for that here. -+ */ -+ if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0) -+ { -+ fprintf(stderr, _("diff command not found: %s\n"), cmd); -+ exit_nicely(2); -+ } -+#endif -+ -+ return WEXITSTATUS(r); -+} -+ -+/* -+ * Check the actual result file for the given test against expected results -+ * -+ * Returns true if different (failure), false if correct match found. -+ * In the true case, the diff is appended to the diffs file. -+ */ -+static bool -+results_differ(const char *testname, const char *resultsfile, const char *default_expectfile) -+{ -+ char expectfile[MAXPGPATH]; -+ char diff[MAXPGPATH]; -+ char cmd[MAXPGPATH * 3]; -+ char best_expect_file[MAXPGPATH]; -+ FILE *difffile; -+ int best_line_count; -+ int i; -+ int l; -+ const char *platform_expectfile; -+ -+ /* -+ * We can pass either the resultsfile or the expectfile, they should have -+ * the same type (filename.type) anyway. -+ */ -+ platform_expectfile = get_expectfile(testname, resultsfile); -+ -+ strcpy(expectfile, default_expectfile); -+ if (platform_expectfile) -+ { -+ /* -+ * Replace everything afer the last slash in expectfile with what the -+ * platform_expectfile contains. -+ */ -+ char *p = strrchr(expectfile, '/'); -+ -+ if (p) -+ strcpy(++p, platform_expectfile); -+ } -+ -+ /* Name to use for temporary diff file */ -+ snprintf(diff, sizeof(diff), "%s.diff", resultsfile); -+ -+ /* OK, run the diff */ -+ snprintf(cmd, sizeof(cmd), -+ SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE, -+ basic_diff_opts, expectfile, resultsfile, diff); -+ -+ /* Is the diff file empty? */ -+ if (run_diff(cmd, diff) == 0) -+ { -+ unlink(diff); -+ return false; -+ } -+ -+ /* There may be secondary comparison files that match better */ -+ best_line_count = file_line_count(diff); -+ strcpy(best_expect_file, expectfile); -+ -+ for (i = 0; i <= 9; i++) -+ { -+ char *alt_expectfile; -+ -+ alt_expectfile = get_alternative_expectfile(expectfile, i); -+ if (!file_exists(alt_expectfile)) -+ continue; -+ -+ snprintf(cmd, sizeof(cmd), -+ SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE, -+ basic_diff_opts, alt_expectfile, resultsfile, diff); -+ -+ if (run_diff(cmd, diff) == 0) -+ { -+ unlink(diff); -+ return false; -+ } -+ -+ l = file_line_count(diff); -+ if (l < best_line_count) -+ { -+ /* This diff was a better match than the last one */ -+ best_line_count = l; -+ strcpy(best_expect_file, alt_expectfile); -+ } -+ free(alt_expectfile); -+ } -+ -+ /* -+ * fall back on the canonical results file if we haven't tried it yet and -+ * haven't found a complete match yet. -+ */ -+ -+ if (platform_expectfile) -+ { -+ snprintf(cmd, sizeof(cmd), -+ SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE, -+ basic_diff_opts, default_expectfile, resultsfile, diff); -+ -+ if (run_diff(cmd, diff) == 0) -+ { -+ /* No diff = no changes = good */ -+ unlink(diff); -+ return false; -+ } -+ -+ l = file_line_count(diff); -+ if (l < best_line_count) -+ { -+ /* This diff was a better match than the last one */ -+ best_line_count = l; -+ strcpy(best_expect_file, default_expectfile); -+ } -+ } -+ -+ /* -+ * Use the best comparison file to generate the "pretty" diff, which we -+ * append to the diffs summary file. -+ */ -+ snprintf(cmd, sizeof(cmd), -+ SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE, -+ pretty_diff_opts, best_expect_file, resultsfile, difffilename); -+ run_diff(cmd, difffilename); -+ -+ /* And append a separator */ -+ difffile = fopen(difffilename, "a"); -+ if (difffile) -+ { -+ fprintf(difffile, -+ "\n======================================================================\n\n"); -+ fclose(difffile); -+ } -+ -+ unlink(diff); -+ return true; -+} -+ -+/* -+ * Wait for specified subprocesses to finish -+ * -+ * If names isn't NULL, report each subprocess as it finishes -+ * -+ * Note: it's OK to scribble on the pids array, but not on the names array -+ */ -+static void -+wait_for_tests(PID_TYPE * pids, char **names, int num_tests) -+{ -+ int tests_left; -+ int i; -+ -+#ifdef WIN32 -+ PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE)); -+ -+ memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE)); -+#endif -+ -+ tests_left = num_tests; -+ while (tests_left > 0) -+ { -+ PID_TYPE p; -+ -+#ifndef WIN32 -+ p = wait(NULL); -+ -+ if (p == INVALID_PID) -+ { -+ fprintf(stderr, _("failed to wait for subprocesses: %s\n"), -+ strerror(errno)); -+ exit_nicely(2); -+ } -+#else -+ int r; -+ -+ r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE); -+ if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left) -+ { -+ fprintf(stderr, _("failed to wait for subprocesses: %lu\n"), -+ GetLastError()); -+ exit_nicely(2); -+ } -+ p = active_pids[r - WAIT_OBJECT_0]; -+ /* compact the active_pids array */ -+ active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1]; -+#endif /* WIN32 */ -+ -+ for (i = 0; i < num_tests; i++) -+ { -+ if (p == pids[i]) -+ { -+#ifdef WIN32 -+ CloseHandle(pids[i]); -+#endif -+ pids[i] = INVALID_PID; -+ if (names) -+ status(" %s", names[i]); -+ tests_left--; -+ break; -+ } -+ } -+ } -+ -+#ifdef WIN32 -+ free(active_pids); -+#endif -+} -+ -+/* -+ * Run all the tests specified in one schedule file -+ */ -+static void -+run_schedule(const char *schedule, test_function tfunc) -+{ -+#define MAX_PARALLEL_TESTS 100 -+ char *tests[MAX_PARALLEL_TESTS]; -+ _stringlist *resultfiles[MAX_PARALLEL_TESTS]; -+ _stringlist *expectfiles[MAX_PARALLEL_TESTS]; -+ _stringlist *tags[MAX_PARALLEL_TESTS]; -+ PID_TYPE pids[MAX_PARALLEL_TESTS]; -+ _stringlist *ignorelist = NULL; -+ char scbuf[1024]; -+ FILE *scf; -+ int line_num = 0; -+ -+ memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS); -+ memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS); -+ memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS); -+ -+ scf = fopen(schedule, "r"); -+ if (!scf) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), -+ progname, schedule, strerror(errno)); -+ exit_nicely(2); -+ } -+ -+ while (fgets(scbuf, sizeof(scbuf), scf)) -+ { -+ char *test = NULL; -+ char *c; -+ int num_tests; -+ bool inword; -+ int i; -+ -+ line_num++; -+ -+ for (i = 0; i < MAX_PARALLEL_TESTS; i++) -+ { -+ if (resultfiles[i] == NULL) -+ break; -+ free_stringlist(&resultfiles[i]); -+ free_stringlist(&expectfiles[i]); -+ free_stringlist(&tags[i]); -+ } -+ -+ /* strip trailing whitespace, especially the newline */ -+ i = strlen(scbuf); -+ while (i > 0 && isspace((unsigned char) scbuf[i - 1])) -+ scbuf[--i] = '\0'; -+ -+ if (scbuf[0] == '\0' || scbuf[0] == '#') -+ continue; -+ if (strncmp(scbuf, "test: ", 6) == 0) -+ test = scbuf + 6; -+ else if (strncmp(scbuf, "ignore: ", 8) == 0) -+ { -+ c = scbuf + 8; -+ while (*c && isspace((unsigned char) *c)) -+ c++; -+ add_stringlist_item(&ignorelist, c); -+ -+ /* -+ * Note: ignore: lines do not run the test, they just say that -+ * failure of this test when run later on is to be ignored. A bit -+ * odd but that's how the shell-script version did it. -+ */ -+ continue; -+ } -+ else -+ { -+ fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"), -+ schedule, line_num, scbuf); -+ exit_nicely(2); -+ } -+ -+ num_tests = 0; -+ inword = false; -+ for (c = test; *c; c++) -+ { -+ if (isspace((unsigned char) *c)) -+ { -+ *c = '\0'; -+ inword = false; -+ } -+ else if (!inword) -+ { -+ if (num_tests >= MAX_PARALLEL_TESTS) -+ { -+ /* can't print scbuf here, it's already been trashed */ -+ fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"), -+ schedule, line_num); -+ exit_nicely(2); -+ } -+ tests[num_tests] = c; -+ num_tests++; -+ inword = true; -+ } -+ } -+ -+ if (num_tests == 0) -+ { -+ fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"), -+ schedule, line_num, scbuf); -+ exit_nicely(2); -+ } -+ -+ if (num_tests == 1) -+ { -+ status(_("test %-20s ... "), tests[0]); -+ pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]); -+ wait_for_tests(pids, NULL, 1); -+ /* status line is finished below */ -+ } -+ else if (max_connections > 0 && max_connections < num_tests) -+ { -+ int oldest = 0; -+ -+ status(_("parallel group (%d tests, in groups of %d): "), -+ num_tests, max_connections); -+ for (i = 0; i < num_tests; i++) -+ { -+ if (i - oldest >= max_connections) -+ { -+ wait_for_tests(pids + oldest, tests + oldest, i - oldest); -+ oldest = i; -+ } -+ pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); -+ } -+ wait_for_tests(pids + oldest, tests + oldest, i - oldest); -+ status_end(); -+ } -+ else -+ { -+ status(_("parallel group (%d tests): "), num_tests); -+ for (i = 0; i < num_tests; i++) -+ { -+ pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); -+ } -+ wait_for_tests(pids, tests, num_tests); -+ status_end(); -+ } -+ -+ /* Check results for all tests */ -+ for (i = 0; i < num_tests; i++) -+ { -+ _stringlist *rl, -+ *el, -+ *tl; -+ bool differ = false; -+ -+ if (num_tests > 1) -+ status(_(" %-20s ... "), tests[i]); -+ -+ /* -+ * Advance over all three lists simultaneously. -+ * -+ * Compare resultfiles[j] with expectfiles[j] always. Tags are -+ * optional but if there are tags, the tag list has the same -+ * length as the other two lists. -+ */ -+ for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i]; -+ rl != NULL; /* rl and el have the same length */ -+ rl = rl->next, el = el->next) -+ { -+ bool newdiff; -+ -+ if (tl) -+ tl = tl->next; /* tl has the same lengt has rl and el -+ * if it exists */ -+ -+ newdiff = results_differ(tests[i], rl->str, el->str); -+ if (newdiff && tl) -+ { -+ printf("%s ", tl->str); -+ } -+ differ |= newdiff; -+ } -+ -+ if (differ) -+ { -+ bool ignore = false; -+ _stringlist *sl; -+ -+ for (sl = ignorelist; sl != NULL; sl = sl->next) -+ { -+ if (strcmp(tests[i], sl->str) == 0) -+ { -+ ignore = true; -+ break; -+ } -+ } -+ if (ignore) -+ { -+ status(_("failed (ignored)")); -+ fail_ignore_count++; -+ } -+ else -+ { -+ status(_("FAILED")); -+ fail_count++; -+ } -+ } -+ else -+ { -+ status(_("ok")); -+ success_count++; -+ } -+ -+ status_end(); -+ } -+ } -+ -+ fclose(scf); -+} -+ -+/* -+ * Run a single test -+ */ -+static void -+run_single_test(const char *test, test_function tfunc) -+{ -+ PID_TYPE pid; -+ _stringlist *resultfiles = NULL; -+ _stringlist *expectfiles = NULL; -+ _stringlist *tags = NULL; -+ _stringlist *rl, -+ *el, -+ *tl; -+ bool differ = false; -+ -+ status(_("test %-20s ... "), test); -+ pid = (tfunc) (test, &resultfiles, &expectfiles, &tags); -+ wait_for_tests(&pid, NULL, 1); -+ -+ /* -+ * Advance over all three lists simultaneously. -+ * -+ * Compare resultfiles[j] with expectfiles[j] always. Tags are optional -+ * but if there are tags, the tag list has the same length as the other -+ * two lists. -+ */ -+ for (rl = resultfiles, el = expectfiles, tl = tags; -+ rl != NULL; /* rl and el have the same length */ -+ rl = rl->next, el = el->next) -+ { -+ bool newdiff; -+ -+ if (tl) -+ tl = tl->next; /* tl has the same lengt has rl and el if it -+ * exists */ -+ -+ newdiff = results_differ(test, rl->str, el->str); -+ if (newdiff && tl) -+ { -+ printf("%s ", tl->str); -+ } -+ differ |= newdiff; -+ } -+ -+ if (differ) -+ { -+ status(_("FAILED")); -+ fail_count++; -+ } -+ else -+ { -+ status(_("ok")); -+ success_count++; -+ } -+ status_end(); -+} -+ -+/* -+ * Create the summary-output files (making them empty if already existing) -+ */ -+static void -+open_result_files(void) -+{ -+ char file[MAXPGPATH]; -+ FILE *difffile; -+ -+ /* create the log file (copy of running status output) */ -+ snprintf(file, sizeof(file), "%s/regression.out", outputdir); -+ logfilename = strdup(file); -+ logfile = fopen(logfilename, "w"); -+ if (!logfile) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"), -+ progname, logfilename, strerror(errno)); -+ exit_nicely(2); -+ } -+ -+ /* create the diffs file as empty */ -+ snprintf(file, sizeof(file), "%s/regression.diffs", outputdir); -+ difffilename = strdup(file); -+ difffile = fopen(difffilename, "w"); -+ if (!difffile) -+ { -+ fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"), -+ progname, difffilename, strerror(errno)); -+ exit_nicely(2); -+ } -+ /* we don't keep the diffs file open continuously */ -+ fclose(difffile); -+ -+ /* also create the output directory if not present */ -+ snprintf(file, sizeof(file), "%s/results", outputdir); -+ if (!directory_exists(file)) -+ make_directory(file); -+} -+ -+static void -+drop_database_if_exists(const char *dbname) -+{ -+ header(_("dropping database \"%s\""), dbname); -+ psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname); -+} -+ -+static void -+create_database(const char *dbname) -+{ -+ _stringlist *sl; -+ -+ /* -+ * We use template0 so that any installation-local cruft in template1 will -+ * not mess up the tests. -+ */ -+ header(_("creating database \"%s\""), dbname); -+ if (encoding) -+ psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'", dbname, encoding); -+ else -+ psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0", dbname); -+ psql_command(dbname, -+ "ALTER DATABASE \"%s\" SET lc_messages TO 'C';" -+ "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';" -+ "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';" -+ "ALTER DATABASE \"%s\" SET lc_time TO 'C';" -+ "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';", -+ dbname, dbname, dbname, dbname, dbname); -+ -+ /* -+ * Install any requested procedural languages -+ */ -+ for (sl = loadlanguage; sl != NULL; sl = sl->next) -+ { -+ header(_("installing %s"), sl->str); -+ psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str); -+ } -+} -+ -+static void -+drop_role_if_exists(const char *rolename) -+{ -+ header(_("dropping role \"%s\""), rolename); -+ psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename); -+} -+ -+static void -+create_role(const char *rolename, const _stringlist * granted_dbs) -+{ -+ header(_("creating role \"%s\""), rolename); -+ psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename); -+ for (; granted_dbs != NULL; granted_dbs = granted_dbs->next) -+ { -+ psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"", -+ granted_dbs->str, rolename); -+ } -+} -+ -+static void -+help(void) -+{ -+ printf(_("PostgreSQL regression test driver\n")); -+ printf(_("\n")); -+ printf(_("Usage: %s [options...] [extra tests...]\n"), progname); -+ printf(_("\n")); -+ printf(_("Options:\n")); -+ printf(_(" --dbname=DB use database DB (default \"regression\")\n")); -+ printf(_(" --debug turn on debug mode in programs that are run\n")); -+ printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n")); -+ printf(_(" --load-language=lang load the named language before running the\n")); -+ printf(_(" tests; can appear multiple times\n")); -+ printf(_(" --create-role=ROLE create the specified role before testing\n")); -+ printf(_(" --max-connections=N maximum number of concurrent connections\n")); -+ printf(_(" (default is 0 meaning unlimited)\n")); -+ printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n")); -+ printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n")); -+ printf(_(" --schedule=FILE use test ordering schedule from FILE\n")); -+ printf(_(" (can be used multiple times to concatenate)\n")); -+ printf(_(" --srcdir=DIR absolute path to source directory (for VPATH builds)\n")); -+ printf(_(" --temp-install=DIR create a temporary installation in DIR\n")); -+ printf(_("\n")); -+ printf(_("Options for \"temp-install\" mode:\n")); -+ printf(_(" --no-locale use C locale\n")); -+ printf(_(" --top-builddir=DIR (relative) path to top level build directory\n")); -+ printf(_(" --temp-port=PORT port number to start temp postmaster on\n")); -+ printf(_(" --temp-config=PATH append contents of PATH to temporary config\n")); -+ printf(_("\n")); -+ printf(_("Options for using an existing installation:\n")); -+ printf(_(" --host=HOST use postmaster running on HOST\n")); -+ printf(_(" --port=PORT use postmaster running at PORT\n")); -+ printf(_(" --user=USER connect as USER\n")); -+ printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n")); -+ printf(_("\n")); -+ printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n")); -+ printf(_("if the tests could not be run for some reason.\n")); -+ printf(_("\n")); -+ printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n")); -+} -+ -+int -+regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc) -+{ -+ _stringlist *sl; -+ int c; -+ int i; -+ int option_index; -+ char buf[MAXPGPATH * 4]; -+ -+ static struct option long_options[] = { -+ {"help", no_argument, NULL, 'h'}, -+ {"version", no_argument, NULL, 'V'}, -+ {"dbname", required_argument, NULL, 1}, -+ {"debug", no_argument, NULL, 2}, -+ {"inputdir", required_argument, NULL, 3}, -+ {"load-language", required_argument, NULL, 4}, -+ {"max-connections", required_argument, NULL, 5}, -+ {"multibyte", required_argument, NULL, 6}, -+ {"outputdir", required_argument, NULL, 7}, -+ {"schedule", required_argument, NULL, 8}, -+ {"temp-install", required_argument, NULL, 9}, -+ {"no-locale", no_argument, NULL, 10}, -+ {"top-builddir", required_argument, NULL, 11}, -+ {"temp-port", required_argument, NULL, 12}, -+ {"host", required_argument, NULL, 13}, -+ {"port", required_argument, NULL, 14}, -+ {"user", required_argument, NULL, 15}, -+ {"psqldir", required_argument, NULL, 16}, -+ {"srcdir", required_argument, NULL, 17}, -+ {"create-role", required_argument, NULL, 18}, -+ {"temp-config", required_argument, NULL, 19}, -+ {NULL, 0, NULL, 0} -+ }; -+ -+ progname = get_progname(argv[0]); -+ set_pglocale_pgservice(argv[0], "pg_regress"); -+ -+#ifndef HAVE_UNIX_SOCKETS -+ /* no unix domain sockets available, so change default */ -+ hostname = "localhost"; -+#endif -+ -+ /* -+ * We call the initialization function here because that way we can set -+ * default parameters and let them be overwritten by the commandline. -+ */ -+ ifunc(); -+ -+ while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1) -+ { -+ switch (c) -+ { -+ case 'h': -+ help(); -+ exit_nicely(0); -+ case 'V': -+ printf("pg_regress (PostgreSQL %s)\n", PG_VERSION); -+ exit_nicely(0); -+ case 1: -+ -+ /* -+ * If a default database was specified, we need to remove it -+ * before we add the specified one. -+ */ -+ free_stringlist(&dblist); -+ split_to_stringlist(strdup(optarg), ", ", &dblist); -+ break; -+ case 2: -+ debug = true; -+ break; -+ case 3: -+ inputdir = strdup(optarg); -+ break; -+ case 4: -+ add_stringlist_item(&loadlanguage, optarg); -+ break; -+ case 5: -+ max_connections = atoi(optarg); -+ break; -+ case 6: -+ encoding = strdup(optarg); -+ break; -+ case 7: -+ outputdir = strdup(optarg); -+ break; -+ case 8: -+ add_stringlist_item(&schedulelist, optarg); -+ break; -+ case 9: -+ /* temp_install must be absolute path */ -+ if (is_absolute_path(optarg)) -+ temp_install = strdup(optarg); -+ else -+ { -+ char cwdbuf[MAXPGPATH]; -+ -+ if (!getcwd(cwdbuf, sizeof(cwdbuf))) -+ { -+ fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno)); -+ exit_nicely(2); -+ } -+ temp_install = malloc(strlen(cwdbuf) + strlen(optarg) + 2); -+ sprintf(temp_install, "%s/%s", cwdbuf, optarg); -+ } -+ canonicalize_path(temp_install); -+ break; -+ case 10: -+ nolocale = true; -+ break; -+ case 11: -+ top_builddir = strdup(optarg); -+ break; -+ case 12: -+ { -+ int p = atoi(optarg); -+ -+ /* Since Makefile isn't very bright, check port range */ -+ if (p >= 1024 && p <= 65535) -+ temp_port = p; -+ } -+ break; -+ case 13: -+ hostname = strdup(optarg); -+ break; -+ case 14: -+ port = atoi(optarg); -+ break; -+ case 15: -+ user = strdup(optarg); -+ break; -+ case 16: -+ /* "--psqldir=" should mean to use PATH */ -+ if (strlen(optarg)) -+ psqldir = strdup(optarg); -+ break; -+ case 17: -+ srcdir = strdup(optarg); -+ break; -+ case 18: -+ split_to_stringlist(strdup(optarg), ", ", &extraroles); -+ break; -+ case 19: -+ temp_config = strdup(optarg); -+ break; -+ default: -+ /* getopt_long already emitted a complaint */ -+ fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"), -+ progname); -+ exit_nicely(2); -+ } -+ } -+ -+ /* -+ * if we still have arguments, they are extra tests to run -+ */ -+ while (argc - optind >= 1) -+ { -+ add_stringlist_item(&extra_tests, argv[optind]); -+ optind++; -+ } -+ -+ if (temp_install) -+ port = temp_port; -+ -+ /* -+ * Initialization -+ */ -+ open_result_files(); -+ -+ initialize_environment(); -+ -+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) -+ unlimit_core_size(); -+#endif -+ -+ if (temp_install) -+ { -+ /* -+ * Prepare the temp installation -+ */ -+ if (!top_builddir) -+ { -+ fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n")); -+ exit_nicely(2); -+ } -+ -+ if (directory_exists(temp_install)) -+ { -+ header(_("removing existing temp installation")); -+ rmtree(temp_install, true); -+ } -+ -+ header(_("creating temporary installation")); -+ -+ /* make the temp install top directory */ -+ make_directory(temp_install); -+ -+ /* and a directory for log files */ -+ snprintf(buf, sizeof(buf), "%s/log", outputdir); -+ if (!directory_exists(buf)) -+ make_directory(buf); -+ -+ /* "make install" */ -+#ifndef WIN32_ONLY_COMPILER -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE, -+ makeprog, top_builddir, temp_install, outputdir); -+#else -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE, -+ top_builddir, temp_install, outputdir); -+#endif -+ if (system(buf)) -+ { -+ fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf); -+ exit_nicely(2); -+ } -+ -+ /* initdb */ -+ header(_("initializing database system")); -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE, -+ bindir, temp_install, datadir, -+ debug ? " --debug" : "", -+ nolocale ? " --no-locale" : "", -+ outputdir); -+ if (system(buf)) -+ { -+ fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf); -+ exit_nicely(2); -+ } -+ -+ /* add any extra config specified to the postgresql.conf */ -+ if (temp_config != NULL) -+ { -+ FILE *extra_conf; -+ FILE *pg_conf; -+ char line_buf[1024]; -+ -+ snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install); -+ pg_conf = fopen(buf, "a"); -+ if (pg_conf == NULL) -+ { -+ fprintf(stderr, _("\n%s: could not open %s for adding extra config:\nError was %s\n"), progname, buf, strerror(errno)); -+ exit_nicely(2); -+ } -+ extra_conf = fopen(temp_config, "r"); -+ if (extra_conf == NULL) -+ { -+ fprintf(stderr, _("\n%s: could not open %s to read extra config:\nError was %s\n"), progname, buf, strerror(errno)); -+ exit_nicely(2); -+ } -+ while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL) -+ fputs(line_buf, pg_conf); -+ fclose(extra_conf); -+ fclose(pg_conf); -+ } -+ -+ /* -+ * Start the temp postmaster -+ */ -+ header(_("starting postmaster")); -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE, -+ bindir, temp_install, -+ debug ? " -d 5" : "", -+ hostname ? hostname : "", -+ outputdir); -+ postmaster_pid = spawn_process(buf); -+ if (postmaster_pid == INVALID_PID) -+ { -+ fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"), -+ progname, strerror(errno)); -+ exit_nicely(2); -+ } -+ -+ /* -+ * Wait till postmaster is able to accept connections (normally only a -+ * second or so, but Cygwin is reportedly *much* slower). Don't wait -+ * forever, however. -+ */ -+ snprintf(buf, sizeof(buf), -+ SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE, -+ bindir, DEVNULL, DEVNULL); -+ for (i = 0; i < 60; i++) -+ { -+ /* Done if psql succeeds */ -+ if (system(buf) == 0) -+ break; -+ -+ /* -+ * Fail immediately if postmaster has exited -+ */ -+#ifndef WIN32 -+ if (kill(postmaster_pid, 0) != 0) -+#else -+ if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0) -+#endif -+ { -+ fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir); -+ exit_nicely(2); -+ } -+ -+ pg_usleep(1000000L); -+ } -+ if (i >= 60) -+ { -+ fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir); -+ -+ /* -+ * If we get here, the postmaster is probably wedged somewhere in -+ * startup. Try to kill it ungracefully rather than leaving a -+ * stuck postmaster that might interfere with subsequent test -+ * attempts. -+ */ -+#ifndef WIN32 -+ if (kill(postmaster_pid, SIGKILL) != 0 && -+ errno != ESRCH) -+ fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"), -+ progname, strerror(errno)); -+#else -+ if (TerminateProcess(postmaster_pid, 255) == 0) -+ fprintf(stderr, _("\n%s: could not kill failed postmaster: %lu\n"), -+ progname, GetLastError()); -+#endif -+ -+ exit_nicely(2); -+ } -+ -+ postmaster_running = true; -+ -+ printf(_("running on port %d with pid %lu\n"), -+ temp_port, (unsigned long) postmaster_pid); -+ } -+ else -+ { -+ /* -+ * Using an existing installation, so may need to get rid of -+ * pre-existing database(s) and role(s) -+ */ -+ for (sl = dblist; sl; sl = sl->next) -+ drop_database_if_exists(sl->str); -+ for (sl = extraroles; sl; sl = sl->next) -+ drop_role_if_exists(sl->str); -+ } -+ -+ /* -+ * Create the test database(s) and role(s) -+ */ -+ for (sl = dblist; sl; sl = sl->next) -+ create_database(sl->str); -+ for (sl = extraroles; sl; sl = sl->next) -+ create_role(sl->str, dblist); -+ -+ /* -+ * Ready to run the tests -+ */ -+ header(_("running regression test queries")); -+ -+ for (sl = schedulelist; sl != NULL; sl = sl->next) -+ { -+ run_schedule(sl->str, tfunc); -+ } -+ -+ for (sl = extra_tests; sl != NULL; sl = sl->next) -+ { -+ run_single_test(sl->str, tfunc); -+ } -+ -+ /* -+ * Shut down temp installation's postmaster -+ */ -+ if (temp_install) -+ { -+ header(_("shutting down postmaster")); -+ stop_postmaster(); -+ } -+ -+ fclose(logfile); -+ -+ /* -+ * Emit nice-looking summary message -+ */ -+ if (fail_count == 0 && fail_ignore_count == 0) -+ snprintf(buf, sizeof(buf), -+ _(" All %d tests passed. "), -+ success_count); -+ else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */ -+ snprintf(buf, sizeof(buf), -+ _(" %d of %d tests passed, %d failed test(s) ignored. "), -+ success_count, -+ success_count + fail_ignore_count, -+ fail_ignore_count); -+ else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */ -+ snprintf(buf, sizeof(buf), -+ _(" %d of %d tests failed. "), -+ fail_count, -+ success_count + fail_count); -+ else -+ /* fail_count>0 && fail_ignore_count>0 */ -+ snprintf(buf, sizeof(buf), -+ _(" %d of %d tests failed, %d of these failures ignored. "), -+ fail_count + fail_ignore_count, -+ success_count + fail_count + fail_ignore_count, -+ fail_ignore_count); -+ -+ putchar('\n'); -+ for (i = strlen(buf); i > 0; i--) -+ putchar('='); -+ printf("\n%s\n", buf); -+ for (i = strlen(buf); i > 0; i--) -+ putchar('='); -+ putchar('\n'); -+ putchar('\n'); -+ -+ if (file_size(difffilename) > 0) -+ { -+ printf(_("The differences that caused some tests to fail can be viewed in the\n" -+ "file \"%s\". A copy of the test summary that you see\n" -+ "above is saved in the file \"%s\".\n\n"), -+ difffilename, logfilename); -+ } -+ else -+ { -+ unlink(difffilename); -+ unlink(logfilename); -+ } -+ -+ if (fail_count != 0) -+ exit_nicely(1); -+ -+ return 0; -+} |