diff --git a/doc/FAQ_HPUX b/doc/FAQ_HPUX
index d04aa92d0e8b2c8dcb3375b1aa416c1ab9ecc2e3..227adbefd59cea330c95dfad6b3d17f4067fdadf 100644
--- a/doc/FAQ_HPUX
+++ b/doc/FAQ_HPUX
@@ -3,7 +3,7 @@ Frequently Asked Questions (FAQ) for PostgreSQL 7.3
 HP-UX Specific
 TO BE READ IN CONJUNCTION WITH THE NORMAL FAQ
 =======================================================
-last updated:           $Date: 2004/09/02 17:46:24 $
+last updated:           $Date: 2006/07/19 02:37:00 $
 
 current maintainer:     Tom Lane (tgl@sss.pgh.pa.us)
 original author:        Tom Lane (tgl@sss.pgh.pa.us)
@@ -84,19 +84,3 @@ low-order-digit differences in the geometry tests, which vary depending
 on which compiler and math library versions you use.
 
 Any other error is cause for suspicion.
-
-The parallel regression test script (gmake check) is known to lock up
-on PA-RISC when run under HP's Bourne shells: /usr/bin/sh and
-/sbin/sh. To fix this problem, you will need PHCO_30269 with its
-dependent patch or successor patches:
-
-    PHCO_30269  s700_800 cumulative sh-posix(1) patch
-    PHCO_29816  s700_800 rc(1M) scripts cumulative patch 
-
-To work around this problem, use ksh to run the regression script:
-
-	gmake SHELL=/bin/ksh check
-
-If you see that the tests have stopped making progress and only a shell
-process is consuming CPU, kill the shell process and start over with the
-above command.
diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index 855c13a1ec61087f765a83eb81cbff9c949c3a2c..141eaaa0bf178789cf6af154f48fd7574fc3cd6a 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/regress.sgml,v 1.52 2006/06/18 15:38:36 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/regress.sgml,v 1.53 2006/07/19 02:37:00 tgl Exp $ -->
 
  <chapter id="regress">
   <title id="regress-title">Regression Tests</title>
@@ -110,19 +110,6 @@ gmake MAX_CONNECTIONS=10 check
     runs no more than ten tests concurrently.
    </para>
 
-   <para>
-    On some systems, the default Bourne-compatible shell
-    (<filename>/bin/sh</filename>) gets confused when it has to manage
-    too many child processes in parallel.  This may cause the parallel
-    test run to lock up or fail.  In such cases, specify a different
-    Bourne-compatible shell on the command line, for example:
-<screen>
-gmake SHELL=/bin/ksh check
-</screen>
-    If no non-broken shell is available, you may be able to work around the
-    problem by limiting the number of connections, as shown above.
-   </para>
-
   <para>
    To run the tests after installation<![%standalone-ignore;[ (see <xref linkend="installation">)]]>,
    initialize a data area and start the
@@ -370,13 +357,10 @@ testname/platformpattern=comparisonfilename
     The test name is just the name of the particular regression test
     module.  The platform pattern is a pattern in the style of the Unix
     tool <command>expr</> (that is, a regular expression with an implicit
-    <literal>^</literal> anchor
-    at the start).  It is matched against the platform name as printed
-    by <command>config.guess</command> followed by
-    <literal>:gcc</literal> or <literal>:cc</literal>, depending on
-    whether you use the GNU compiler or the system's native compiler
-    (on systems where there is a difference).  The comparison file
-    name is the base name of the substitute result comparison file.
+    <literal>^</literal> anchor at the start).  It is matched against the
+    platform name as printed by <command>config.guess</command>.
+    The comparison file name is the base name of the substitute result
+    comparison file.
    </para>
 
    <para>
diff --git a/src/makefiles/pgxs.mk b/src/makefiles/pgxs.mk
index d2969e44407e8502953faf0cc59ab36ceb2e084a..a26622922bd043cf5a281e44aa62f49755ab63c1 100644
--- a/src/makefiles/pgxs.mk
+++ b/src/makefiles/pgxs.mk
@@ -1,6 +1,6 @@
 # PGXS: PostgreSQL extensions makefile
 
-# $PostgreSQL: pgsql/src/makefiles/pgxs.mk,v 1.7 2005/12/09 21:19:36 petere Exp $ 
+# $PostgreSQL: pgsql/src/makefiles/pgxs.mk,v 1.8 2006/07/19 02:37:00 tgl Exp $ 
 
 # This file contains generic rules to build many kinds of simple
 # extension modules.  You only need to set a few variables and include
@@ -230,16 +230,16 @@ endif # VPATH
 .PHONY: submake
 submake:
 ifndef PGXS
-	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress
+	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
 endif
 
 # against installed postmaster
 installcheck: submake
-	$(SHELL) $(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
+	$(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
 
 # in-tree test doesn't work yet (no way to install my shared library)
 #check: all submake
-#	$(SHELL) $(top_builddir)/src/test/regress/pg_regress --temp-install \
+#	$(top_builddir)/src/test/regress/pg_regress --temp-install \
 #	  --top-builddir=$(top_builddir) $(REGRESS_OPTS) $(REGRESS)
 check:
 	@echo "'make check' is not supported."
diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile
index 1831f9ddf8a7c4da056c95e2e5048d807b272722..73f36bd44ac9ca5cd6559b8ef75dde1a1ec7824d 100644
--- a/src/pl/plperl/GNUmakefile
+++ b/src/pl/plperl/GNUmakefile
@@ -1,5 +1,5 @@
 # Makefile for PL/Perl
-# $PostgreSQL: pgsql/src/pl/plperl/GNUmakefile,v 1.26 2005/12/09 21:19:36 petere Exp $
+# $PostgreSQL: pgsql/src/pl/plperl/GNUmakefile,v 1.27 2006/07/19 02:37:00 tgl Exp $
 
 subdir = src/pl/plperl
 top_builddir = ../../..
@@ -84,11 +84,11 @@ uninstall:
 	rm -f '$(DESTDIR)$(pkglibdir)/plperl$(DLSUFFIX)'
 
 installcheck: submake
-	$(SHELL) $(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
+	$(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
 
 .PHONY: submake
 submake:
-	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress
+	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
 
 clean distclean maintainer-clean: clean-lib
 	rm -f SPI.c $(OBJS)
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index df691cf8dfef41cf296b1363672ab67ed6be094b..5823e205dcd8b1b18a1d975e60cffe27e2043dfe 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.24 2005/12/09 21:19:36 petere Exp $
+# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.25 2006/07/19 02:37:00 tgl Exp $
 
 subdir = src/pl/plpython
 top_builddir = ../../..
@@ -103,11 +103,11 @@ uninstall:
 	rm -f '$(DESTDIR)$(pkglibdir)/plpython$(DLSUFFIX)'
 
 installcheck: submake
-	$(SHELL) $(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
+	$(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
 
 .PHONY: submake
 submake:
-	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress
+	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
 
 clean distclean maintainer-clean: clean-lib
 	rm -f $(OBJS)
diff --git a/src/pl/tcl/Makefile b/src/pl/tcl/Makefile
index d953c4bff836bd48d1e1bcaa29b81c8b8b1bcf43..a474c71e2d91f9f60b9c20755dd98493a747ecc7 100644
--- a/src/pl/tcl/Makefile
+++ b/src/pl/tcl/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for the pltcl shared object
 #
-# $PostgreSQL: pgsql/src/pl/tcl/Makefile,v 1.48 2005/12/09 21:19:36 petere Exp $
+# $PostgreSQL: pgsql/src/pl/tcl/Makefile,v 1.49 2006/07/19 02:37:00 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -90,11 +90,11 @@ uninstall:
 	$(MAKE) -C modules $@
 
 installcheck: submake
-	$(SHELL) $(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
+	$(top_builddir)/src/test/regress/pg_regress $(REGRESS_OPTS) $(REGRESS)
 
 .PHONY: submake
 submake:
-	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress
+	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
 
 else # TCL_SHARED_BUILD = 0
 
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index 3a2b66740541cd7aed1887b8c64a958a2b55b225..a3e00a7f65bcb609713807287c4928423309e4a4 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -6,7 +6,7 @@
 # Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/test/regress/GNUmakefile,v 1.57 2006/03/05 15:59:11 momjian Exp $
+# $PostgreSQL: pgsql/src/test/regress/GNUmakefile,v 1.58 2006/07/19 02:37:00 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -34,32 +34,33 @@ ifdef NO_LOCALE
 NOLOCALE += --no-locale
 endif
 
+# stuff to pass into build of pg_regress
+EXTRADEFS = '-DPGBINDIR="$(bindir)"' \
+	'-DLIBDIR="$(libdir)"' \
+	'-DPGSHAREDIR="$(datadir)"' \
+	'-DHOST_TUPLE="$(host_tuple)"' \
+	'-DMAKEPROG="$(MAKE)"'
+
 ##
 ## Prepare for tests
 ##
 
 # Build regression test driver
 
-all: pg_regress
+all: submake-libpgport pg_regress$(X)
+
+pg_regress$(X): pg_regress.o
+	$(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LIBS) -o $@
 
-pg_regress: pg_regress.sh GNUmakefile $(top_builddir)/src/Makefile.global
-	sed -e 's,@bindir@,$(bindir),g' \
-	    -e 's,@libdir@,$(libdir),g' \
-	    -e 's,@pkglibdir@,$(pkglibdir),g' \
-	    -e 's,@datadir@,$(datadir),g' \
-	    -e 's/@VERSION@/$(VERSION)/g' \
-	    -e 's/@host_tuple@/$(host_tuple)/g' \
-	    -e 's,@GMAKE@,$(MAKE),g' \
-	    -e 's/@enable_shared@/$(enable_shared)/g' \
-	    -e 's/@GCC@/$(GCC)/g' \
-	  $< >$@
-	chmod a+x $@
+# depend on Makefile.global to ensure that symbol changes propagate
+pg_regress.o: pg_regress.c $(top_builddir)/src/Makefile.global
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(EXTRADEFS) -c -o $@ $<
 
-install: pg_regress
-	$(INSTALL_SCRIPT) pg_regress '$(DESTDIR)$(pgxsdir)/$(subdir)/pg_regress'
+install: pg_regress$(X)
+	$(INSTALL_PROGRAM) pg_regress$(X) '$(DESTDIR)$(pgxsdir)/$(subdir)/pg_regress$(X)'
 
 uninstall:
-	rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/pg_regress'
+	rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/pg_regress$(X)'
 
 
 # Build dynamically-loaded object file for CREATE FUNCTION ... LANGUAGE C.
@@ -143,17 +144,17 @@ all-spi:
 check: all
 	-rm -rf ./testtablespace
 	mkdir ./testtablespace
-	$(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
+	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
 
 installcheck: all
 	-rm -rf ./testtablespace
 	mkdir ./testtablespace
-	$(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE)
+	./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE)
 
 installcheck-parallel: all
 	-rm -rf ./testtablespace
 	mkdir ./testtablespace
-	$(SHELL) ./pg_regress --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
+	./pg_regress --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
 
 
 # old interfaces follow...
@@ -163,10 +164,10 @@ runtest: installcheck
 runtest-parallel: installcheck-parallel
 
 bigtest:
-	$(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE) numeric_big 
+	./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE) numeric_big 
 
 bigcheck:
-	$(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE) numeric_big
+	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE) numeric_big
 
 
 ##
@@ -177,7 +178,7 @@ clean distclean maintainer-clean: clean-lib
 # things built by `all' target
 	rm -f $(NAME)$(DLSUFFIX) $(OBJS)
 	$(MAKE) -C $(contribdir)/spi clean
-	rm -f $(output_files) $(input_files) pg_regress
+	rm -f $(output_files) $(input_files) pg_regress.o pg_regress$(X)
 # things created by various check targets
 	rm -rf testtablespace
 	rm -rf results tmp_check log
diff --git a/src/test/regress/Makefile b/src/test/regress/Makefile
index fbb3148861da882b1755e72f26f56a0be6d1295a..ede55c17f17155b9e593bfcd9501ee83830cfee6 100644
--- a/src/test/regress/Makefile
+++ b/src/test/regress/Makefile
@@ -7,6 +7,6 @@
 # GNU make uses a make file named "GNUmakefile" in preference to "Makefile"
 # if it exists.  Postgres is shipped with a "GNUmakefile".
 
-all install clean dep depend:
+all install clean dep depend check installcheck:
 	@echo "You must use GNU make to use Postgres.  It may be installed"
 	@echo "on your system with the name 'gmake'."
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
new file mode 100644
index 0000000000000000000000000000000000000000..d8f7c3e1d965700661d64aa7b11a8e891709d423
--- /dev/null
+++ b/src/test/regress/pg_regress.c
@@ -0,0 +1,1601 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_regress --- regression test driver
+ *
+ * This is a C implementation of the previous shell script for running
+ * the regression tests, and should be highly 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-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.1 2006/07/19 02:37:00 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "getopt_long.h"
+
+#ifndef WIN32
+#define PID_TYPE pid_t
+#define INVALID_PID (-1)
+#else
+#define PID_TYPE HANDLE
+#define INVALID_PID INVALID_HANDLE_VALUE
+#endif
+
+
+/* simple list of strings */
+typedef struct _stringlist
+{
+	char *str;
+	struct _stringlist *next;
+} _stringlist;
+
+/* for resultmap we need a list of pairs of strings */
+typedef struct _resultmap
+{
+	char *test;
+	char *resultfile;
+	struct _resultmap *next;
+} _resultmap;
+
+/*
+ * Values inserted from Makefile.  (It might seem tempting to get the paths
+ * via get_share_path() and friends, but that's not going to work because
+ * pg_regress is typically not executed from an installed bin directory.)
+ */
+static char *bindir = PGBINDIR;
+static char *libdir = LIBDIR;
+static char *datadir = PGSHAREDIR;
+static char *host_platform = HOST_TUPLE;
+static char *makeprog = MAKEPROG;
+
+/* currently we can use the same diff switches on all platforms */
+static const char *basic_diff_opts = "-w";
+static const char *pretty_diff_opts = "-w -C3";
+
+/* options settable from command line */
+static char *dbname = "regression";
+static bool debug = false;
+static char *inputdir = ".";
+static char *outputdir = ".";
+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 *top_builddir = NULL;
+static int temp_port = 65432;
+static bool nolocale = false;
+static char *hostname = NULL;
+static int port = -1;
+static char *user = 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 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)));
+
+
+/*
+ * Add an item at the end of a stringlist.
+ */
+static 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;
+	}
+}
+
+/*
+ * 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];
+
+		snprintf(buf, sizeof(buf),
+				 "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast",
+				 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
+ */
+static 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;
+}
+
+/*
+ * 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);
+	}
+	memset(buf, 0, sizeof(buf));
+	while (fgets(buf, sizeof(buf)-1, f))
+	{
+		char *platform;
+		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 */
+		platform = strchr(buf, '/');
+		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->resultfile = strdup(expected);
+			entry->next = resultmap;
+			resultmap = entry;
+		}
+	}
+	fclose(f);
+}
+
+/*
+ * 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 may not 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;
+
+		/*
+		 * 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.  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);
+#ifdef WIN32
+		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);
+
+		/*
+		 * On Windows, it seems to be necessary to adjust PATH even in
+		 * this case.
+		 */
+#ifdef WIN32
+		add_to_path("PATH", ';', libdir);
+#endif
+
+		/*
+		 * 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"));
+	}
+
+	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),
+			 "\"%s/psql\" -X -c \"%s\" \"%s\"",
+			 bindir, 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 so we can wait for it later
+ */
+static 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 */
+		exit(system(cmdline) ? 1 : 0);
+	}
+	/* in parent */
+	return pid;
+#else
+	char *cmdline2;
+	STARTUPINFO si;
+	PROCESS_INFORMATION pi;
+
+	ZeroMemory(&si, sizeof(si));
+	si.cb = sizeof(si);
+
+	cmdline2 = malloc(strlen(cmdline) + 8);
+	sprintf(cmdline2, "cmd /c %s", cmdline);
+
+	if (!CreateProcess(NULL, cmdline2, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+	{
+		fprintf(stderr, _("failed to start process for \"%s\": %lu\n"),
+				cmdline2, GetLastError());
+		exit_nicely(2);
+	}
+	free(cmdline2);
+
+	CloseHandle(pi.hThread);
+	return pi.hProcess;
+#endif
+}
+
+/*
+ * start a psql test process for specified file (including redirection),
+ * and return process ID
+ */
+static PID_TYPE
+psql_start_test(const char *testname)
+{
+	PID_TYPE pid;
+	char infile[MAXPGPATH];
+	char outfile[MAXPGPATH];
+	char psql_cmd[MAXPGPATH * 3];
+
+	snprintf(infile, sizeof(infile), "%s/sql/%s.sql",
+			 inputdir, testname);
+	snprintf(outfile, sizeof(outfile), "%s/results/%s.out",
+			 outputdir, testname);
+
+	snprintf(psql_cmd, sizeof(psql_cmd),
+			 "\"%s/psql\" -X -a -q -d \"%s\" <\"%s\" >\"%s\" 2>&1",
+			 bindir, dbname, infile, outfile);
+
+	pid = spawn_process(psql_cmd);
+
+	if (pid == INVALID_PID)
+	{
+		fprintf(stderr, _("failed to start process for test %s\n"),
+				testname);
+		exit_nicely(2);
+	}
+
+	return pid;
+}
+
+/*
+ * 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 (st.st_mode & S_IFDIR)
+		return true;
+	return false;
+}
+
+/* Create a directory */
+static void
+make_directory(const char *dir)
+{
+	if (mkdir(dir, S_IRWXU) < 0)
+	{
+		fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
+				progname, dir, strerror(errno));
+		exit_nicely(2);
+	}
+}
+
+/*
+ * 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 *expectname;
+	char resultsfile[MAXPGPATH];
+	char expectfile[MAXPGPATH];
+	char diff[MAXPGPATH];
+	char cmd[MAXPGPATH * 3];
+	char best_expect_file[MAXPGPATH];
+	_resultmap *rm;
+	FILE *difffile;
+	int best_line_count;
+	int i;
+	int l;
+	int r;
+
+	/* Check in resultmap if we should be looking at a different file */
+	expectname = testname;
+	for (rm = resultmap; rm != NULL; rm = rm->next)
+	{
+		if (strcmp(testname, rm->test) == 0)
+		{
+			expectname = rm->resultfile;
+			break;
+		}
+	}
+
+	/* Name of test results file */
+	snprintf(resultsfile, sizeof(resultsfile), "%s/results/%s.out",
+			 outputdir, testname);
+
+	/* Name of expected-results file */
+	snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
+			 inputdir, expectname);
+
+	/* Name to use for temporary diff file */
+	snprintf(diff, sizeof(diff), "%s/results/%s.diff",
+			 outputdir, testname);
+
+	/* OK, run the diff */
+	snprintf(cmd, sizeof(cmd),
+			 "diff %s \"%s\" \"%s\" >\"%s\"",
+			 basic_diff_opts, expectfile, resultsfile, diff);
+	r = system(cmd);
+	if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
+	{
+		fprintf(stderr, _("diff command failed: %s\n"), cmd);
+		exit_nicely(2);
+	}
+
+	/* Is the diff file empty? */
+	if (file_size(diff) == 0)
+	{
+		/* No diff = no changes = good */
+		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++)
+	{
+		snprintf(expectfile, sizeof(expectfile), "%s/expected/%s_%d.out",
+				 inputdir, expectname, i);
+		if (!file_exists(expectfile))
+			continue;
+
+		snprintf(cmd, sizeof(cmd),
+				 "diff %s \"%s\" \"%s\" >\"%s\"",
+				 basic_diff_opts, expectfile, resultsfile, diff);
+		r = system(cmd);
+		if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
+		{
+			fprintf(stderr, _("diff command failed: %s\n"), cmd);
+			exit_nicely(2);
+		}
+
+		if (file_size(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, expectfile);
+		}
+	}
+
+	/*
+	 * Use the best comparison file to generate the "pretty" diff, which
+	 * we append to the diffs summary file.
+	 */
+	snprintf(cmd, sizeof(cmd),
+			 "diff %s \"%s\" \"%s\" >>\"%s\"",
+			 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
+	r = system(cmd);
+	if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
+	{
+		fprintf(stderr, _("diff command failed: %s\n"), cmd);
+		exit_nicely(2);
+	}
+
+	/* 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
+ */
+static void
+wait_for_tests(PID_TYPE *pids, int num_tests)
+{
+#ifndef WIN32
+	int tests_left;
+	int i;
+
+	tests_left = num_tests;
+	while (tests_left > 0)
+	{
+		pid_t p = wait(NULL);
+
+		if (p == -1)
+		{
+			fprintf(stderr, _("failed to wait(): %s\n"), strerror(errno));
+			exit_nicely(2);
+		}
+		for (i=0; i < num_tests; i++)
+		{
+			/* Make sure we only count the processes we explicitly started */
+			if (p == pids[i])
+			{
+				pids[i] = -1;
+				tests_left--;
+			}
+		}
+	}
+#else
+	int r;
+	int i;
+
+	r = WaitForMultipleObjects(num_tests, pids, TRUE, INFINITE);
+	if (r != WAIT_OBJECT_0)
+	{
+		fprintf(stderr, _("failed to wait for commands to finish: %lu\n"),
+				GetLastError());
+		exit_nicely(2);
+	}
+	for (i = 0; i < num_tests; i++)
+		CloseHandle(pids[i]);
+#endif
+}
+
+/*
+ * Run all the tests specified in one schedule file
+ */
+static void
+run_schedule(const char *schedule)
+{
+#define MAX_PARALLEL_TESTS 100
+	char *tests[MAX_PARALLEL_TESTS];
+	PID_TYPE pids[MAX_PARALLEL_TESTS];
+	_stringlist *ignorelist = NULL;
+	char scbuf[1024];
+	FILE *scf;
+	int line_num = 0;
+
+	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);
+	}
+
+	memset(scbuf, 0, sizeof(scbuf));
+	while (fgets(scbuf, sizeof(scbuf)-1, scf))
+	{
+		char *test = NULL;
+		char *c;
+		int num_tests;
+		bool inword;
+		int i;
+
+		line_num++;
+
+		/* 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] = psql_start_test(tests[0]);
+			wait_for_tests(pids, 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, i - oldest);
+					oldest = i;
+				}
+				status(" %s", tests[i]);
+				pids[i] = psql_start_test(tests[i]);
+			}
+			wait_for_tests(pids + oldest, i - oldest);
+			status_end();
+		}
+		else
+		{
+			status(_("parallel group (%d tests): "), num_tests);
+			for (i = 0; i < num_tests; i++)
+			{
+				status(" %s", tests[i]);
+				pids[i] = psql_start_test(tests[i]);
+			}
+			wait_for_tests(pids, num_tests);
+			status_end();
+		}
+
+		/* Check results for all tests */
+		for (i = 0; i < num_tests; i++)
+		{
+			if (num_tests > 1)
+				status(_("     %-20s ... "), tests[i]);
+
+			if (results_differ(tests[i]))
+			{
+				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)
+{
+	PID_TYPE pid;
+
+	status(_("test %-20s ... "), test);
+	pid = psql_start_test(test);
+	wait_for_tests(&pid, 1);
+
+	if (results_differ(test))
+	{
+		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
+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(_("  --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(_("                            (may be used multiple times to concatenate)\n"));
+	printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
+	printf(_("  --no-locale               use C locale\n"));
+	printf(_("\n"));
+	printf(_("Options for \"temp-install\" mode:\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(_("\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(_("\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
+main(int argc, char *argv[])
+{
+	_stringlist *sl;
+	int c;
+	int i;
+	int option_index;
+	char buf[MAXPGPATH];
+
+	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},
+		{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
+
+	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:
+				dbname = strdup(optarg);
+				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;
+			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 (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" */
+		snprintf(buf, sizeof(buf),
+				 "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no >\"%s/log/install.log\" 2>&1",
+				makeprog, top_builddir, temp_install, outputdir);
+		if (system(buf))
+		{
+			fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\n"), progname, outputdir);
+			exit_nicely(2);
+		}
+
+		/* initdb */
+		header(_("initializing database system"));
+		snprintf(buf, sizeof(buf),
+				 "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean %s %s >\"%s/log/initdb.log\" 2>&1",
+				 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.\n"), progname, outputdir);
+			exit_nicely(2);
+		}
+
+		/*
+		 * Start the temp postmaster
+		 */
+		header(_("starting postmaster"));
+		snprintf(buf, sizeof(buf),
+				 "\"%s/postmaster\" -D \"%s/data\" -F %s -c \"listen_addresses=%s\" >\"%s/log/postmaster.log\" 2>&1",
+				 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);
+		}
+
+		/*
+		 * XXX Note that because we use system() to launch the subprocess,
+		 * the returned postmaster_pid is not really the PID of the
+		 * postmaster itself; on most systems it'll be the PID of a parent
+		 * shell process.  This is OK for the limited purposes we currently
+		 * use postmaster_pid for, but beware!
+		 */
+
+		/*
+		 * 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),
+				 "\"%s/psql\" -X postgres <%s 2>%s",
+				 bindir, DEVNULL, DEVNULL);
+		for (i = 0; i < 60; i++)
+		{
+			/* Done if psql succeeds */
+			if (system(buf) == 0)
+				break;
+
+			/*
+			 * Fail immediately if postmaster has exited
+			 *
+			 * XXX is there a way to do this on Windows?
+			 */
+#ifndef WIN32
+			if (kill(postmaster_pid, 0) != 0)
+			{
+				fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
+				exit_nicely(2);
+			}
+#endif
+
+			pg_usleep(1000000L);
+		}
+		if (i == 60)
+		{
+			fprintf(stderr, _("\n%s: postmaster did not start within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
+			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.
+		 */
+		header(_("dropping database \"%s\""), dbname);
+		psql_command("postgres","DROP DATABASE IF EXISTS \"%s\"", dbname);
+	}
+
+	/*
+	 * Create the test database
+	 *
+	 * 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						/* use installation default */
+		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';",
+				 dbname, dbname, dbname, dbname);
+
+	/*
+	 * Install any requested PL languages
+	 */
+	for (sl = loadlanguage; sl != NULL; sl = sl->next)
+	{
+		header(_("installing %s"), sl->str);
+		psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
+	}
+
+	/*
+	 * Ready to run the tests
+	 */
+	header(_("running regression test queries"));
+
+	for (sl = schedulelist; sl != NULL; sl = sl->next)
+	{
+		run_schedule(sl->str);
+	}
+
+	for (sl = extra_tests; sl != NULL; sl = sl->next)
+	{
+		run_single_test(sl->str);
+	}
+
+	/*
+	 * 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;
+}
diff --git a/src/test/regress/pg_regress.sh b/src/test/regress/pg_regress.sh
deleted file mode 100644
index f56b737d0bcb5dd74f787e6ad413a0d82c745007..0000000000000000000000000000000000000000
--- a/src/test/regress/pg_regress.sh
+++ /dev/null
@@ -1,777 +0,0 @@
-#! /bin/sh
-# $PostgreSQL: pgsql/src/test/regress/pg_regress.sh,v 1.65 2006/07/18 00:32:41 tgl Exp $
-
-me=`basename $0`
-: ${TMPDIR=/tmp}
-TMPFILE=$TMPDIR/pg_regress.$$
-
-help="\
-PostgreSQL regression test driver
-
-Usage: $me [options...] [extra tests...]
-
-Options:
-  --dbname=DB               use database DB (default \`regression')
-  --debug                   turn on debug mode in programs that are run
-  --inputdir=DIR            take input files from DIR (default \`.')
-  --load-language=lang      load the named language before running the
-                            tests; can appear multiple times
-  --max-connections=N       maximum number of concurrent connections
-                            (default is 0 meaning unlimited)
-  --multibyte=ENCODING      use ENCODING as the multibyte encoding, and
-                            also run a test by the same name
-  --outputdir=DIR           place output files in DIR (default \`.')
-  --schedule=FILE           use test ordering schedule from FILE
-                            (may be used multiple times to concatenate)
-  --temp-install[=DIR]      create a temporary installation (in DIR)
-  --no-locale               use C locale
-
-Options for \`temp-install' mode:
-  --top-builddir=DIR        (relative) path to top level build directory
-  --temp-port=PORT          port number to start temp postmaster on
-
-Options for using an existing installation:
-  --host=HOST               use postmaster running on HOST
-  --port=PORT               use postmaster running at PORT
-  --user=USER               connect as USER
-
-The exit status is 0 if all tests passed, 1 if some tests failed, and 2
-if the tests could not be run for some reason.
-
-Report bugs to <pgsql-bugs@postgresql.org>."
-
-
-message(){
-    _dashes='==============' # 14
-    _spaces='                                      ' # 38
-    _msg=`echo "$1$_spaces" | cut -c 1-38`
-    echo "$_dashes $_msg $_dashes"
-}
-
-
-# ----------
-# Unset locale settings
-# ----------
-
-unset LC_COLLATE LC_CTYPE LC_MONETARY LC_MESSAGES LC_NUMERIC LC_TIME LC_ALL LANG LANGUAGE
-
-# On Windows the default locale may not be English, so force it
-case $host_platform in
-    *-*-cygwin*|*-*-mingw32*)
-	LANG=en
-	export LANG
-	;;
-esac
-
-
-# ----------
-# Check for echo -n vs echo \c
-# ----------
-
-if echo '\c' | grep c >/dev/null 2>&1; then
-    ECHO_N='echo -n'
-    ECHO_C=''
-else
-    ECHO_N='echo'
-    ECHO_C='\c'
-fi
-
-
-# ----------
-# Initialize default settings
-# ----------
-
-: ${inputdir=.}
-: ${outputdir=.}
-
-libdir='@libdir@'
-bindir='@bindir@'
-datadir='@datadir@'
-host_platform='@host_tuple@'
-enable_shared='@enable_shared@'
-GCC=@GCC@
-
-if [ "$GCC" = yes ]; then
-    compiler=gcc
-else
-    compiler=cc
-fi
-
-unset mode
-unset schedule
-unset debug
-unset nolocale
-unset top_builddir
-unset temp_install
-unset multibyte
-
-dbname=regression
-hostname=localhost
-maxconnections=0
-temp_port=65432
-load_langs=""
-
-: ${GMAKE='@GMAKE@'}
-
-
-# ----------
-# Parse command line options
-# ----------
-
-while [ "$#" -gt 0 ]
-do
-    case $1 in
-        --help|-\?)
-                echo "$help"
-                exit 0;;
-        --version)
-                echo "pg_regress (PostgreSQL @VERSION@)"
-                exit 0;;
-        --dbname=*)
-                dbname=`expr "x$1" : "x--dbname=\(.*\)"`
-                shift;;
-        --debug)
-                debug=yes
-                shift;;
-        --inputdir=*)
-                inputdir=`expr "x$1" : "x--inputdir=\(.*\)"`
-                shift;;
-        --load-language=*)
-                lang=`expr "x$1" : "x--load-language=\(.*\)"`
-                load_langs="$load_langs $lang"
-                unset lang
-                shift;;
-        --multibyte=*)
-                multibyte=`expr "x$1" : "x--multibyte=\(.*\)"`
-                shift;;
-        --no-locale)
-                nolocale=yes
-                shift;;
-        --temp-install)
-                temp_install=./tmp_check
-                shift;;
-        --temp-install=*)
-                temp_install=`expr "x$1" : "x--temp-install=\(.*\)"`
-                shift;;
-        --max-connections=*)
-                maxconnections=`expr "x$1" : "x--max-connections=\(.*\)"`
-                shift;;
-        --outputdir=*)
-                outputdir=`expr "x$1" : "x--outputdir=\(.*\)"`
-                shift;;
-        --schedule=*)
-                foo=`expr "x$1" : "x--schedule=\(.*\)"`
-                schedule="$schedule $foo"
-                shift;;
-        --top-builddir=*)
-                top_builddir=`expr "x$1" : "x--top-builddir=\(.*\)"`
-                shift;;
-        --temp-port=*)
-                temp_port=`expr "x$1" : "x--temp-port=\(.*\)"`
-                shift;;
-        --host=*)
-                PGHOST=`expr "x$1" : "x--host=\(.*\)"`
-                export PGHOST
-                unset PGHOSTADDR
-                shift;;
-        --port=*)
-                PGPORT=`expr "x$1" : "x--port=\(.*\)"`
-                export PGPORT
-                shift;;
-        --user=*)
-                PGUSER=`expr "x$1" : "x--user=\(.*\)"`
-                export PGUSER
-                shift;;
-        -*)
-                echo "$me: invalid argument $1" 1>&2
-                exit 2;;
-        *)
-                extra_tests="$extra_tests $1"
-                shift;;
-    esac
-done
-
-# ----------
-# warn of Cygwin likely failure if maxconnections = 0
-# and we are running parallel tests
-# ----------
-
-case $host_platform in
-    *-*-cygwin*)
-	case "$schedule" in
-	    *parallel_schedule*)
-		if [ $maxconnections -eq 0 ] ; then
-		    echo Using unlimited parallel connections is likely to fail or hang on Cygwin.
-		    echo Try \"$me --max-connections=n\" or \"gmake MAX_CONNECTIONS=n check\"
-		    echo with n = 5 or 10 if this happens.
-		    echo
-		fi
-		;;
-	esac
-	;;
-esac
-
-
-# ----------
-# On some platforms we can't use Unix sockets.
-# ----------
-case $host_platform in
-    *-*-cygwin* | *-*-mingw32*)
-        unix_sockets=no;;
-    *)
-        unix_sockets=yes;;
-esac
-
-
-# ----------
-# Set up diff to ignore horizontal white space differences.
-# ----------
-
-case $host_platform in
-    *-*-sco3.2v5*)
-        DIFFFLAGS=-b;;
-    *)
-        DIFFFLAGS=-w;;
-esac
-
-
-# ----------
-# Set backend timezone and datestyle explicitly
-#
-# To pass the horology test in its current form, the postmaster must be
-# started with PGDATESTYLE=ISO, while the frontend must be started with
-# PGDATESTYLE=Postgres.  We set the postmaster values here and change
-# to the frontend settings after the postmaster has been started.
-# ----------
-
-PGTZ='PST8PDT'; export PGTZ
-PGDATESTYLE='ISO, MDY'; export PGDATESTYLE
-
-
-# ----------
-# Exit trap to remove temp file and shut down postmaster
-# ----------
-
-# Note:  There are some stupid shells (even among recent ones) that
-# ignore the argument to exit (as in `exit 1') if there is an exit
-# trap.  The trap (and thus the shell script) will then always exit
-# with the result of the last shell command before the `exit'.  Hence
-# we have to write `(exit x); exit' below this point.
-
-exit_trap(){ 
-    savestatus=$1
-    if [ -n "$postmaster_pid" ]; then
-        kill -2 "$postmaster_pid"
-        wait "$postmaster_pid"
-        unset postmaster_pid
-    fi
-    rm -f "$TMPFILE" && exit $savestatus
-}
-
-trap 'exit_trap $?' 0
-
-sig_trap() {
-    savestatus=$1
-    echo; echo "caught signal"
-    if [ -n "$postmaster_pid" ]; then
-        echo "signalling fast shutdown to postmaster with pid $postmaster_pid"
-        kill -2 "$postmaster_pid"
-        wait "$postmaster_pid"
-        unset postmaster_pid
-    fi
-    (exit $savestatus); exit
-}
-
-trap 'sig_trap $?' 1 2 13 15
-
-
-
-# ----------
-# 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.
-# What hostplatformpattern will be matched against is the config.guess output
-# followed by either ':gcc' or ':cc' (independent of the actual name of the
-# compiler executable).
-#
-# The tempfile hackery is needed because some shells will run the loop
-# inside a subshell, whereupon shell variables set therein aren't seen
-# outside the loop :-(
-# ----------
-
-cat /dev/null >$TMPFILE
-if [ -f "$inputdir/resultmap" ]
-then
-    while read LINE
-    do
-        HOSTPAT=`expr "$LINE" : '.*/\(.*\)='`
-        if [ `expr "$host_platform:$compiler" : "$HOSTPAT"` -ne 0 ]
-        then
-            # remove hostnamepattern from line so that there are no shell
-            # wildcards in SUBSTLIST; else later 'for' could expand them!
-            TESTNAME=`expr "$LINE" : '\(.*\)/'`
-            SUBST=`echo "$LINE" | sed 's/^.*=//'`
-            echo "$TESTNAME=$SUBST" >> $TMPFILE
-        fi
-    done <"$inputdir/resultmap"
-fi
-SUBSTLIST=`cat $TMPFILE`
-rm -f $TMPFILE
-
-
-LOGDIR=$outputdir/log
-
-if [ x"$temp_install" != x"" ]
-then
-    if echo x"$temp_install" | grep -v '^x/' >/dev/null 2>&1; then
-        temp_install="`pwd`/$temp_install"
-    fi
-
-    bindir=$temp_install/install/$bindir
-    libdir=$temp_install/install/$libdir
-    datadir=$temp_install/install/$datadir
-    PGDATA=$temp_install/data
-
-    if [ "$unix_sockets" = no ]; then
-        PGHOST=$hostname
-        export PGHOST
-        unset PGHOSTADDR
-    else
-        unset PGHOST
-        unset PGHOSTADDR
-    fi
-
-    # since Makefile isn't very bright, check for out-of-range temp_port
-    if [ "$temp_port" -ge 1024 -a "$temp_port" -le 65535 ] ; then
-	PGPORT=$temp_port
-    else
-	PGPORT=65432
-    fi
-    export PGPORT
-
-    # Get rid of environment stuff that might cause psql to misbehave
-    # while contacting our temp installation
-    unset PGDATABASE PGUSER PGSERVICE PGSSLMODE PGREQUIRESSL PGCONNECT_TIMEOUT
-
-    # ----------
-    # Set up shared library paths, needed by psql and pg_encoding
-    # (if you run multibyte).  LD_LIBRARY_PATH covers many platforms.
-    # DYLD_LIBRARY_PATH works on Darwin, and maybe other Mach-based systems.
-    # Feel free to account for others as well.
-    # ----------
-
-    if [ -n "$LD_LIBRARY_PATH" ]; then
-        LD_LIBRARY_PATH="$libdir:$LD_LIBRARY_PATH"
-    else
-        LD_LIBRARY_PATH=$libdir
-    fi
-    export LD_LIBRARY_PATH
-
-    if [ -n "$DYLD_LIBRARY_PATH" ]; then
-        DYLD_LIBRARY_PATH="$libdir:$DYLD_LIBRARY_PATH"
-    else
-        DYLD_LIBRARY_PATH=$libdir
-    fi
-    export DYLD_LIBRARY_PATH
-
-    # ----------
-    # Windows needs shared libraries in PATH. (Only those linked into
-    # executables, not dlopen'ed ones)
-    # ----------
-    case $host_platform in
-        *-*-cygwin*|*-*-mingw32*)
-            PATH=$libdir:$PATH
-            export PATH
-            ;;
-    esac
-
-    if [ -d "$temp_install" ]; then
-        message "removing existing temp installation"
-        rm -rf "$temp_install"
-    fi
-
-    message "creating temporary installation"
-    if [ ! -d "$LOGDIR" ]; then
-        mkdir -p "$LOGDIR" || { (exit 2); exit; }
-    fi
-    $GMAKE -C "$top_builddir" DESTDIR="$temp_install/install" install with_perl=no with_python=no >"$LOGDIR/install.log" 2>&1
-
-    if [ $? -ne 0 ]
-    then
-        echo
-        echo "$me: installation failed"
-        echo "Examine $LOGDIR/install.log for the reason."
-        echo
-        (exit 2); exit
-    fi
-
-    message "initializing database system"
-    [ "$debug" = yes ] && initdb_options="--debug"
-    [ "$nolocale" = yes ] && initdb_options="$initdb_options --no-locale"
-    "$bindir/initdb" -D "$PGDATA" -L "$datadir" --noclean $initdb_options >"$LOGDIR/initdb.log" 2>&1
-
-    if [ $? -ne 0 ]
-    then
-        echo
-        echo "$me: initdb failed"
-        echo "Examine $LOGDIR/initdb.log for the reason."
-        echo
-        (exit 2); exit
-    fi
-
-
-    # ----------
-    # Start postmaster
-    # ----------
-
-    message "starting postmaster"
-    [ "$debug" = yes ] && postmaster_options="$postmaster_options -d 5"
-    if [ "$unix_sockets" = no ]; then
-        postmaster_options="$postmaster_options -c listen_addresses=$hostname"
-    else
-        postmaster_options="$postmaster_options -c listen_addresses="
-    fi
-    "$bindir/postmaster" -D "$PGDATA" -F $postmaster_options >"$LOGDIR/postmaster.log" 2>&1 &
-    postmaster_pid=$!
-
-    # 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.
-    i=0
-    max=60
-    until "$bindir/psql" -X $psql_options postgres </dev/null 2>/dev/null
-    do
-        i=`expr $i + 1`
-        if [ $i -ge $max ]
-        then
-            break
-        fi
-        if kill -0 $postmaster_pid >/dev/null 2>&1
-        then
-            : still starting up
-        else
-            break
-        fi
-        sleep 1
-    done
-
-    if kill -0 $postmaster_pid >/dev/null 2>&1
-    then
-        echo "running on port $PGPORT with pid $postmaster_pid"
-    else
-        echo
-        echo "$me: postmaster did not start"
-        echo "Examine $LOGDIR/postmaster.log for the reason."
-        echo
-        (exit 2); exit
-    fi
-
-else # not temp-install
-
-    # ----------
-    # Windows needs shared libraries in PATH. (Only those linked into
-    # executables, not dlopen'ed ones)
-    # ----------
-    case $host_platform in
-        *-*-cygwin*|*-*-mingw32*)
-            PATH=$libdir:$PATH
-            export PATH
-            ;;
-    esac
-
-    if [ -n "$PGPORT" ]; then
-        port_info="port $PGPORT"
-    else
-        port_info="default port"
-    fi
-
-    if [ -n "$PGHOST" ]; then
-        echo "(using postmaster on $PGHOST, $port_info)"
-    else
-        if [ "$unix_sockets" = no ]; then
-            echo "(using postmaster on localhost, $port_info)"
-        else
-            echo "(using postmaster on Unix socket, $port_info)"
-        fi
-    fi
-
-    message "dropping database \"$dbname\""
-    "$bindir/dropdb" $psql_options "$dbname"
-    # errors can be ignored
-fi
-
-
-# ----------
-# Set up SQL shell for the test.
-# ----------
-
-psql_test_options="-a -q -X $psql_options"
-
-
-# ----------
-# Set frontend timezone and datestyle explicitly
-# ----------
-
-PGTZ='PST8PDT'; export PGTZ
-PGDATESTYLE='Postgres, MDY'; export PGDATESTYLE
-
-
-# ----------
-# Set up multibyte environment
-# ----------
-
-if [ -n "$multibyte" ]; then
-    PGCLIENTENCODING=$multibyte
-    export PGCLIENTENCODING
-    encoding_opt="-E $multibyte"
-else
-    unset PGCLIENTENCODING
-fi
-
-
-# ----------
-# Create the regression database
-# We use template0 so that any installation-local cruft in template1
-# will not mess up the tests.
-# ----------
-
-message "creating database \"$dbname\""
-"$bindir/createdb" $encoding_opt $psql_options --template template0 "$dbname"
-if [ $? -ne 0 ]; then
-    echo "$me: createdb failed"
-    (exit 2); exit
-fi
-
-"$bindir/psql" -q -X $psql_options -c "\
-alter database \"$dbname\" set lc_messages to 'C';
-alter database \"$dbname\" set lc_monetary to 'C';
-alter database \"$dbname\" set lc_numeric to 'C';
-alter database \"$dbname\" set lc_time to 'C';" "$dbname"
-if [ $? -ne 0 ]; then
-    echo "$me: could not set database default locales"
-    (exit 2); exit
-fi
-
-
-# ----------
-# Install any requested PL languages
-# ----------
-
-if [ "$enable_shared" = yes ]; then
-    for lang in xyzzy $load_langs ; do    
-        if [ "$lang" != "xyzzy" ]; then
-            message "installing $lang"
-            "$bindir/createlang" $psql_options $lang $dbname
-            if [ $? -ne 0 ] && [ $? -ne 2 ]; then
-                echo "$me: createlang $lang failed"
-                (exit 2); exit
-            fi
-        fi
-    done
-fi
-
-
-# ----------
-# Let's go
-# ----------
-
-message "running regression test queries"
-
-if [ ! -d "$outputdir/results" ]; then
-    mkdir -p "$outputdir/results" || { (exit 2); exit; }
-fi
-result_summary_file=$outputdir/regression.out
-diff_file=$outputdir/regression.diffs
-
-cat /dev/null >"$result_summary_file"
-cat /dev/null >"$diff_file"
-
-lno=0
-(
-    [ "$enable_shared" != yes ] && echo "ignore: plpgsql"
-    cat $schedule </dev/null
-    for x in $extra_tests; do
-        echo "test: $x"
-    done
-) | sed 's/[ 	]*#.*//g' | \
-while read line
-do
-    # Count line numbers
-    lno=`expr $lno + 1`
-    [ -z "$line" ] && continue
-
-    set X $line; shift
-
-    if [ x"$1" = x"ignore:" ]; then
-        shift
-        ignore_list="$ignore_list $@"
-        continue
-    elif [ x"$1" != x"test:" ]; then
-        echo "$me:$schedule:$lno: syntax error"
-        (exit 2); exit
-    fi
-
-    shift
-
-    # ----------
-    # Start tests
-    # ----------
-
-    if [ $# -eq 1 ]; then
-        # Run a single test
-        formatted=`echo $1 | awk '{printf "%-20.20s", $1;}'`
-        $ECHO_N "test $formatted ... $ECHO_C"
-        ( "$bindir/psql" $psql_test_options -d "$dbname" <"$inputdir/sql/$1.sql" >"$outputdir/results/$1.out" 2>&1 )&
-        wait
-    else
-        # Start a parallel group
-        $ECHO_N "parallel group ($# tests): $ECHO_C"
-        if [ $maxconnections -gt 0 ] ; then
-            connnum=0
-            test $# -gt $maxconnections && $ECHO_N "(in groups of $maxconnections) $ECHO_C"
-        fi
-        for name do
-            ( 
-              "$bindir/psql" $psql_test_options -d "$dbname" <"$inputdir/sql/$name.sql" >"$outputdir/results/$name.out" 2>&1
-              $ECHO_N " $name$ECHO_C"
-            ) &
-            if [ $maxconnections -gt 0 ] ; then
-                connnum=`expr \( $connnum + 1 \) % $maxconnections`
-                test $connnum -eq 0 && wait
-            fi
-        done
-        wait
-        echo
-    fi
-
-    # ----------
-    # Run diff
-    # (We do not want to run the diffs immediately after each test,
-    # because they would certainly get corrupted if run in parallel
-    # subshells.)
-    # ----------
-
-    for name do
-        if [ $# -ne 1 ]; then
-            formatted=`echo "$name" | awk '{printf "%-20.20s", $1;}'`
-            $ECHO_N "     $formatted ... $ECHO_C"
-        fi
-
-        # Check list extracted from resultmap to see if we should compare
-        # to a system-specific expected file.
-        # There shouldn't be multiple matches, but take the last if there are.
-
-        EXPECTED="$inputdir/expected/${name}"
-        for LINE in $SUBSTLIST
-        do
-            if [ `expr "$LINE" : "$name="` -ne 0 ]
-            then
-                SUBST=`echo "$LINE" | sed 's/^.*=//'`
-                EXPECTED="$inputdir/expected/${SUBST}"
-            fi
-        done
-
-        # If there are multiple equally valid result files, loop to get the right one.
-        # If none match, diff against the closest one.
-
-        bestfile=
-        bestdiff=
-        result=2
-        for thisfile in $EXPECTED.out ${EXPECTED}_[0-9].out; do
-            [ ! -r "$thisfile" ] && continue
-            diff $DIFFFLAGS $thisfile $outputdir/results/${name}.out >/dev/null 2>&1
-            result=$?
-            case $result in
-                0) break;;
-                1) thisdiff=`diff $DIFFFLAGS $thisfile $outputdir/results/${name}.out | wc -l`
-                   if [ -z "$bestdiff" ] || [ "$thisdiff" -lt "$bestdiff" ]; then
-                       bestdiff=$thisdiff; bestfile=$thisfile
-                   fi
-                   continue;;
-                2) break;;
-            esac
-        done
-
-        # Now print the result.
-
-        case $result in
-            0)
-                echo "ok";;
-            1)
-                ( diff $DIFFFLAGS -C3 $bestfile $outputdir/results/${name}.out
-                  echo
-                  echo "======================================================================"
-                  echo ) >> "$diff_file"
-                if echo " $ignore_list " | grep " $name " >/dev/null 2>&1 ; then
-                    echo "failed (ignored)"
-                else
-                    echo "FAILED"
-                fi
-                ;;
-            2)
-                # disaster struck
-                echo "trouble" 1>&2
-                (exit 2); exit;;
-        esac
-    done
-done | tee "$result_summary_file" 2>&1
-
-[ $? -ne 0 ] && exit
-
-# ----------
-# Server shutdown
-# ----------
-
-if [ -n "$postmaster_pid" ]; then
-    message "shutting down postmaster"
-    "$bindir/pg_ctl" -s -D "$PGDATA" stop
-    wait "$postmaster_pid"
-    unset postmaster_pid
-fi
-
-rm -f "$TMPFILE"
-
-
-# ----------
-# Evaluation
-# ----------
-
-count_total=`cat "$result_summary_file" | grep '\.\.\.' | wc -l | sed 's/ //g'`
-count_ok=`cat "$result_summary_file" | grep '\.\.\. ok' | wc -l | sed 's/ //g'`
-count_failed=`cat "$result_summary_file" | grep '\.\.\. FAILED' | wc -l | sed 's/ //g'`
-count_ignored=`cat "$result_summary_file" | grep '\.\.\. failed (ignored)' | wc -l | sed 's/ //g'`
-
-echo
-if [ $count_total -eq $count_ok ]; then
-    msg="All $count_total tests passed."
-    result=0
-elif [ $count_failed -eq 0 ]; then
-    msg="$count_ok of $count_total tests passed, $count_ignored failed test(s) ignored."
-    result=0
-elif [ $count_ignored -eq 0 ]; then
-    msg="$count_failed of $count_total tests failed."
-    result=1
-else
-    msg="`expr $count_failed + $count_ignored` of $count_total tests failed, $count_ignored of these failures ignored."
-    result=1
-fi
-
-dashes=`echo " $msg " | sed 's/./=/g'`
-echo "$dashes"
-echo " $msg "
-echo "$dashes"
-echo
-
-if [ -s "$diff_file" ]; then
-    echo "The differences that caused some tests to fail can be viewed in the"
-    echo "file \`$diff_file'.  A copy of the test summary that you see"
-    echo "above is saved in the file \`$result_summary_file'."
-    echo
-else
-    rm -f "$diff_file" "$result_summary_file"
-fi
-
-
-(exit $result); exit