]> granicus.if.org Git - postgresql/blobdiff - src/test/regress/pg_regress.c
Make the order of the header file includes consistent in non-backend modules.
[postgresql] / src / test / regress / pg_regress.c
index b28cb0b1e1e6b46b4b5cfb7ec4fca65fa6a48796..6554ce214bc02c3a5e08d51dc2f91667a45c58d6 100644 (file)
@@ -8,7 +8,7 @@
  *
  * This code is released under the terms of the PostgreSQL License.
  *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/test/regress/pg_regress.c
@@ -16,7 +16,7 @@
  *-------------------------------------------------------------------------
  */
 
-#include "pg_regress.h"
+#include "postgres_fe.h"
 
 #include <ctype.h>
 #include <sys/stat.h>
 #include <sys/resource.h>
 #endif
 
+#include "common/logging.h"
 #include "common/restricted_token.h"
 #include "common/username.h"
 #include "getopt_long.h"
 #include "libpq/pqcomm.h"              /* needed for UNIXSOCK_PATH() */
 #include "pg_config_paths.h"
+#include "pg_regress.h"
+#include "portability/instr_time.h"
 
 /* for resultmap we need a list of pairs of strings */
 typedef struct _resultmap
@@ -60,10 +63,10 @@ static char *shellprog = SHELLPROG;
  */
 #ifndef WIN32
 const char *basic_diff_opts = "";
-const char *pretty_diff_opts = "-C3";
+const char *pretty_diff_opts = "-U3";
 #else
 const char *basic_diff_opts = "-w";
-const char *pretty_diff_opts = "-w -C3";
+const char *pretty_diff_opts = "-w -U3";
 #endif
 
 /* options settable from command line */
@@ -76,6 +79,7 @@ char     *launcher = NULL;
 static _stringlist *loadlanguage = NULL;
 static _stringlist *loadextension = NULL;
 static int     max_connections = 0;
+static int     max_concurrent_tests = 0;
 static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
 static _stringlist *extra_tests = NULL;
@@ -265,7 +269,7 @@ stop_postmaster(void)
                fflush(stderr);
 
                snprintf(buf, sizeof(buf),
-                                "\"%s%spg_ctl\" stop -D \"%s/data\" -s -m fast",
+                                "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
                                 bindir ? bindir : "",
                                 bindir ? "/" : "",
                                 temp_instance);
@@ -355,7 +359,7 @@ make_temp_sockdir(void)
 
        return temp_sockdir;
 }
-#endif   /* HAVE_UNIX_SOCKETS */
+#endif                                                 /* HAVE_UNIX_SOCKETS */
 
 /*
  * Check whether string matches pattern
@@ -435,7 +439,7 @@ string_matches_pattern(const char *str, const char *pattern)
  * NOTE: Assumes there is enough room in the target buffer!
  */
 void
-replace_string(char *string, char *replace, char *replacement)
+replace_string(char *string, const char *replace, const char *replacement)
 {
        char       *ptr;
 
@@ -457,7 +461,7 @@ replace_string(char *string, char *replace, char *replacement)
  * the given suffix.
  */
 static void
-convert_sourcefiles_in(char *source_subdir, char *dest_dir, char *dest_subdir, char *suffix)
+convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
 {
        char            testtablespace[MAXPGPATH];
        char            indir[MAXPGPATH];
@@ -721,6 +725,10 @@ doputenv(const char *var, const char *val)
 static void
 initialize_environment(void)
 {
+       /*
+        * Set default application_name.  (The test_function may choose to
+        * override this, but if it doesn't, we have something useful in place.)
+        */
        putenv("PGAPPNAME=pg_regress");
 
        if (nolocale)
@@ -852,6 +860,14 @@ initialize_environment(void)
                if (user != NULL)
                        doputenv("PGUSER", user);
 
+               /*
+                * However, we *don't* honor PGDATABASE, since we certainly don't wish
+                * to connect to whatever database the user might like as default.
+                * (Most tests override PGDATABASE anyway, but there are some ECPG
+                * test cases that don't.)
+                */
+               unsetenv("PGDATABASE");
+
                /*
                 * Report what we're connecting to
                 */
@@ -876,7 +892,9 @@ initialize_environment(void)
        load_resultmap();
 }
 
-pg_attribute_unused()
+#ifdef ENABLE_SSPI
+
+/* support for config_sspi_auth() */
 static const char *
 fmtHba(const char *raw)
 {
@@ -899,7 +917,6 @@ fmtHba(const char *raw)
        return ret;
 }
 
-#ifdef ENABLE_SSPI
 /*
  * Get account and domain/realm names for the current user.  This is based on
  * pg_SSPI_recvauth().  The returned strings use static storage.
@@ -959,13 +976,15 @@ current_windows_user(const char **acct, const char **dom)
  * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication.  Permit
  * the current OS user to authenticate as the bootstrap superuser and as any
  * user named in a --create-role option.
+ *
+ * In --config-auth mode, the --user switch can be used to specify the
+ * bootstrap superuser's name, otherwise we assume it is the default.
  */
 static void
-config_sspi_auth(const char *pgdata)
+config_sspi_auth(const char *pgdata, const char *superuser_name)
 {
        const char *accountname,
                           *domainname;
-       const char *username;
        char       *errstr;
        bool            have_ipv6;
        char            fname[MAXPGPATH];
@@ -974,17 +993,25 @@ config_sspi_auth(const char *pgdata)
                           *ident;
        _stringlist *sl;
 
-       /*
-        * "username", the initdb-chosen bootstrap superuser name, may always
-        * match "accountname", the value SSPI authentication discovers.  The
-        * underlying system functions do not clearly guarantee that.
-        */
+       /* Find out the name of the current OS user */
        current_windows_user(&accountname, &domainname);
-       username = get_user_name(&errstr);
-       if (username == NULL)
+
+       /* Determine the bootstrap superuser's name */
+       if (superuser_name == NULL)
        {
-               fprintf(stderr, "%s: %s\n", progname, errstr);
-               exit(2);
+               /*
+                * Compute the default superuser name the same way initdb does.
+                *
+                * It's possible that this result always matches "accountname", the
+                * value SSPI authentication discovers.  But the underlying system
+                * functions do not clearly guarantee that.
+                */
+               superuser_name = get_user_name(&errstr);
+               if (superuser_name == NULL)
+               {
+                       fprintf(stderr, "%s: %s\n", progname, errstr);
+                       exit(2);
+               }
        }
 
        /*
@@ -1021,7 +1048,7 @@ config_sspi_auth(const char *pgdata)
        } while (0)
 
        res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
-       if (res < 0 || res >= sizeof(fname) - 1)
+       if (res < 0 || res >= sizeof(fname))
        {
                /*
                 * Truncating this name is a fatal error, because we must not fail to
@@ -1061,13 +1088,14 @@ config_sspi_auth(const char *pgdata)
         * bother escaping embedded double-quote characters.
         */
        CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
-                          accountname, domainname, fmtHba(username)) >= 0);
+                          accountname, domainname, fmtHba(superuser_name)) >= 0);
        for (sl = extraroles; sl; sl = sl->next)
                CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
                                   accountname, domainname, fmtHba(sl->str)) >= 0);
        CW(fclose(ident) == 0);
 }
-#endif
+
+#endif                                                 /* ENABLE_SSPI */
 
 /*
  * Issue a command via psql, connecting to the specified database
@@ -1170,7 +1198,7 @@ spawn_process(const char *cmdline)
        cmdline2 = psprintf("cmd /c \"%s\"", cmdline);
 
        if ((restrictedToken =
-                CreateRestrictedProcess(cmdline2, &pi, progname)) == 0)
+                CreateRestrictedProcess(cmdline2, &pi)) == 0)
                exit(2);
 
        CloseHandle(pi.hThread);
@@ -1450,34 +1478,38 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
         * 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);
-       run_diff(cmd, difffilename);
 
-       /* And append a separator */
+       /* Write diff header */
        difffile = fopen(difffilename, "a");
        if (difffile)
        {
                fprintf(difffile,
-                               "\n======================================================================\n\n");
+                               "diff %s %s %s\n",
+                               pretty_diff_opts, best_expect_file, resultsfile);
                fclose(difffile);
        }
 
+       /* Run diff */
+       snprintf(cmd, sizeof(cmd),
+                        "diff %s \"%s\" \"%s\" >> \"%s\"",
+                        pretty_diff_opts, best_expect_file, resultsfile, difffilename);
+       run_diff(cmd, difffilename);
+
        unlink(diff);
        return true;
 }
 
 /*
  * Wait for specified subprocesses to finish, and return their exit
- * statuses into statuses[]
+ * statuses into statuses[] and stop times into stoptimes[]
  *
  * If names isn't NULL, print each subprocess's name 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, int *statuses, char **names, int num_tests)
+wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
+                          char **names, int num_tests)
 {
        int                     tests_left;
        int                     i;
@@ -1518,7 +1550,7 @@ wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
                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 */
+#endif                                                 /* WIN32 */
 
                for (i = 0; i < num_tests; i++)
                {
@@ -1530,6 +1562,7 @@ wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
 #endif
                                pids[i] = INVALID_PID;
                                statuses[i] = (int) exit_status;
+                               INSTR_TIME_SET_CURRENT(stoptimes[i]);
                                if (names)
                                        status(" %s", names[i]);
                                tests_left--;
@@ -1557,14 +1590,9 @@ log_child_failure(int exitstatus)
 #if defined(WIN32)
                status(_(" (test process was terminated by exception 0x%X)"),
                           WTERMSIG(exitstatus));
-#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
-               status(_(" (test process was terminated by signal %d: %s)"),
-                          WTERMSIG(exitstatus),
-                          WTERMSIG(exitstatus) < NSIG ?
-                          sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
 #else
-               status(_(" (test process was terminated by signal %d)"),
-                          WTERMSIG(exitstatus));
+               status(_(" (test process was terminated by signal %d: %s)"),
+                          WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
 #endif
        }
        else
@@ -1584,15 +1612,18 @@ run_schedule(const char *schedule, test_function tfunc)
        _stringlist *expectfiles[MAX_PARALLEL_TESTS];
        _stringlist *tags[MAX_PARALLEL_TESTS];
        PID_TYPE        pids[MAX_PARALLEL_TESTS];
+       instr_time      starttimes[MAX_PARALLEL_TESTS];
+       instr_time      stoptimes[MAX_PARALLEL_TESTS];
        int                     statuses[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);
+       memset(tests, 0, sizeof(tests));
+       memset(resultfiles, 0, sizeof(resultfiles));
+       memset(expectfiles, 0, sizeof(expectfiles));
+       memset(tags, 0, sizeof(tags));
 
        scf = fopen(schedule, "r");
        if (!scf)
@@ -1612,15 +1643,6 @@ run_schedule(const char *schedule, test_function tfunc)
 
                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]))
@@ -1653,24 +1675,35 @@ run_schedule(const char *schedule, test_function tfunc)
 
                num_tests = 0;
                inword = false;
-               for (c = test; *c; c++)
+               for (c = test;; c++)
                {
-                       if (isspace((unsigned char) *c))
+                       if (*c == '\0' || isspace((unsigned char) *c))
                        {
-                               *c = '\0';
-                               inword = false;
+                               if (inword)
+                               {
+                                       /* Reached end of a test name */
+                                       char            sav;
+
+                                       if (num_tests >= MAX_PARALLEL_TESTS)
+                                       {
+                                               fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
+                                                               MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
+                                               exit(2);
+                                       }
+                                       sav = *c;
+                                       *c = '\0';
+                                       tests[num_tests] = pg_strdup(test);
+                                       num_tests++;
+                                       *c = sav;
+                                       inword = false;
+                               }
+                               if (*c == '\0')
+                                       break;          /* loop exit is here */
                        }
                        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(2);
-                               }
-                               tests[num_tests] = c;
-                               num_tests++;
+                               /* Start of a test name */
+                               test = c;
                                inword = true;
                        }
                }
@@ -1684,11 +1717,18 @@ run_schedule(const char *schedule, test_function tfunc)
 
                if (num_tests == 1)
                {
-                       status(_("test %-24s ... "), tests[0]);
+                       status(_("test %-28s ... "), tests[0]);
                        pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
-                       wait_for_tests(pids, statuses, NULL, 1);
+                       INSTR_TIME_SET_CURRENT(starttimes[0]);
+                       wait_for_tests(pids, statuses, stoptimes, NULL, 1);
                        /* status line is finished below */
                }
+               else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
+               {
+                       fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
+                                       max_concurrent_tests, schedule, line_num, scbuf);
+                       exit(2);
+               }
                else if (max_connections > 0 && max_connections < num_tests)
                {
                        int                     oldest = 0;
@@ -1700,12 +1740,15 @@ run_schedule(const char *schedule, test_function tfunc)
                                if (i - oldest >= max_connections)
                                {
                                        wait_for_tests(pids + oldest, statuses + oldest,
+                                                                  stoptimes + oldest,
                                                                   tests + oldest, i - oldest);
                                        oldest = i;
                                }
                                pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
+                               INSTR_TIME_SET_CURRENT(starttimes[i]);
                        }
                        wait_for_tests(pids + oldest, statuses + oldest,
+                                                  stoptimes + oldest,
                                                   tests + oldest, i - oldest);
                        status_end();
                }
@@ -1715,8 +1758,9 @@ run_schedule(const char *schedule, test_function tfunc)
                        for (i = 0; i < num_tests; i++)
                        {
                                pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
+                               INSTR_TIME_SET_CURRENT(starttimes[i]);
                        }
-                       wait_for_tests(pids, statuses, tests, num_tests);
+                       wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
                        status_end();
                }
 
@@ -1729,7 +1773,7 @@ run_schedule(const char *schedule, test_function tfunc)
                        bool            differ = false;
 
                        if (num_tests > 1)
-                               status(_("     %-24s ... "), tests[i]);
+                               status(_("     %-28s ... "), tests[i]);
 
                        /*
                         * Advance over all three lists simultaneously.
@@ -1740,14 +1784,11 @@ run_schedule(const char *schedule, test_function tfunc)
                         */
                        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)
+                                rl = rl->next, el = el->next,
+                                tl = tl ? tl->next : NULL)
                        {
                                bool            newdiff;
 
-                               if (tl)
-                                       tl = tl->next;          /* tl has the same length as rl and el
-                                                                                * if it exists */
-
                                newdiff = results_differ(tests[i], rl->str, el->str);
                                if (newdiff && tl)
                                {
@@ -1782,15 +1823,27 @@ run_schedule(const char *schedule, test_function tfunc)
                        }
                        else
                        {
-                               status(_("ok"));
+                               status(_("ok    "));    /* align with FAILED */
                                success_count++;
                        }
 
                        if (statuses[i] != 0)
                                log_child_failure(statuses[i]);
 
+                       INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
+                       status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptimes[i]));
+
                        status_end();
                }
+
+               for (i = 0; i < num_tests; i++)
+               {
+                       pg_free(tests[i]);
+                       tests[i] = NULL;
+                       free_stringlist(&resultfiles[i]);
+                       free_stringlist(&expectfiles[i]);
+                       free_stringlist(&tags[i]);
+               }
        }
 
        free_stringlist(&ignorelist);
@@ -1805,6 +1858,8 @@ static void
 run_single_test(const char *test, test_function tfunc)
 {
        PID_TYPE        pid;
+       instr_time      starttime;
+       instr_time      stoptime;
        int                     exit_status;
        _stringlist *resultfiles = NULL;
        _stringlist *expectfiles = NULL;
@@ -1814,9 +1869,10 @@ run_single_test(const char *test, test_function tfunc)
                           *tl;
        bool            differ = false;
 
-       status(_("test %-24s ... "), test);
+       status(_("test %-28s ... "), test);
        pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
-       wait_for_tests(&pid, &exit_status, NULL, 1);
+       INSTR_TIME_SET_CURRENT(starttime);
+       wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
 
        /*
         * Advance over all three lists simultaneously.
@@ -1827,14 +1883,11 @@ run_single_test(const char *test, test_function tfunc)
         */
        for (rl = resultfiles, el = expectfiles, tl = tags;
                 rl != NULL;                    /* rl and el have the same length */
-                rl = rl->next, el = el->next)
+                rl = rl->next, el = el->next,
+                tl = tl ? tl->next : NULL)
        {
                bool            newdiff;
 
-               if (tl)
-                       tl = tl->next;          /* tl has the same length as rl and el if it
-                                                                * exists */
-
                newdiff = results_differ(test, rl->str, el->str);
                if (newdiff && tl)
                {
@@ -1850,13 +1903,16 @@ run_single_test(const char *test, test_function tfunc)
        }
        else
        {
-               status(_("ok"));
+               status(_("ok    "));    /* align with FAILED */
                success_count++;
        }
 
        if (exit_status != 0)
                log_child_failure(exit_status);
 
+       INSTR_TIME_SUBTRACT(stoptime, starttime);
+       status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptime));
+
        status_end();
 }
 
@@ -1869,6 +1925,10 @@ open_result_files(void)
        char            file[MAXPGPATH];
        FILE       *difffile;
 
+       /* create outputdir directory if not present */
+       if (!directory_exists(outputdir))
+               make_directory(outputdir);
+
        /* create the log file (copy of running status output) */
        snprintf(file, sizeof(file), "%s/regression.out", outputdir);
        logfilename = pg_strdup(file);
@@ -1893,7 +1953,7 @@ open_result_files(void)
        /* we don't keep the diffs file open continuously */
        fclose(difffile);
 
-       /* also create the output directory if not present */
+       /* also create the results directory if not present */
        snprintf(file, sizeof(file), "%s/results", outputdir);
        if (!directory_exists(file))
                make_directory(file);
@@ -1927,8 +1987,9 @@ create_database(const char *dbname)
                                 "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);
+                                "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
+                                "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
+                                dbname, dbname, dbname, dbname, dbname, dbname);
 
        /*
         * Install any requested procedural languages.  We use CREATE OR REPLACE
@@ -1978,40 +2039,46 @@ help(void)
        printf(_("Usage:\n  %s [OPTION]... [EXTRA-TEST]...\n"), progname);
        printf(_("\n"));
        printf(_("Options:\n"));
-       printf(_("  --config-auth=DATADIR     update authentication settings for DATADIR\n"));
-       printf(_("  --create-role=ROLE        create the specified role before testing\n"));
-       printf(_("  --dbname=DB               use database DB (default \"regression\")\n"));
-       printf(_("  --debug                   turn on debug mode in programs that are run\n"));
-       printf(_("  --dlpath=DIR              look for dynamic libraries in DIR\n"));
-       printf(_("  --encoding=ENCODING       use ENCODING as the encoding\n"));
-       printf(_("  --inputdir=DIR            take input files from DIR (default \".\")\n"));
-       printf(_("  --launcher=CMD            use CMD as launcher of psql\n"));
-       printf(_("  --load-extension=EXT      load the named extension before running the\n"));
-       printf(_("                            tests; can appear multiple times\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(_("  --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(_("  --temp-instance=DIR       create a temporary instance in DIR\n"));
-       printf(_("  --use-existing            use an existing installation\n"));
+       printf(_("      --bindir=BINPATH          use BINPATH for programs that are run;\n"));
+       printf(_("                                if empty, use PATH from the environment\n"));
+       printf(_("      --config-auth=DATADIR     update authentication settings for DATADIR\n"));
+       printf(_("      --create-role=ROLE        create the specified role before testing\n"));
+       printf(_("      --dbname=DB               use database DB (default \"regression\")\n"));
+       printf(_("      --debug                   turn on debug mode in programs that are run\n"));
+       printf(_("      --dlpath=DIR              look for dynamic libraries in DIR\n"));
+       printf(_("      --encoding=ENCODING       use ENCODING as the encoding\n"));
+       printf(_("  -h, --help                    show this help, then exit\n"));
+       printf(_("      --inputdir=DIR            take input files from DIR (default \".\")\n"));
+       printf(_("      --launcher=CMD            use CMD as launcher of psql\n"));
+       printf(_("      --load-extension=EXT      load the named extension before running the\n"));
+       printf(_("                                tests; can appear multiple times\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(_("      --max-concurrent-tests=N  maximum number of concurrent tests in schedule\n"));
+       printf(_("                                (default is 0, meaning unlimited)\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(_("      --temp-instance=DIR       create a temporary instance in DIR\n"));
+       printf(_("      --use-existing            use an existing installation\n"));
+       printf(_("  -V, --version                 output version information, then exit\n"));
        printf(_("\n"));
        printf(_("Options for \"temp-instance\" mode:\n"));
-       printf(_("  --no-locale               use C locale\n"));
-       printf(_("  --port=PORT               start postmaster on PORT\n"));
-       printf(_("  --temp-config=FILE        append contents of FILE to temporary config\n"));
+       printf(_("      --no-locale               use C locale\n"));
+       printf(_("      --port=PORT               start postmaster on PORT\n"));
+       printf(_("      --temp-config=FILE        append contents of FILE 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(_("      --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"));
+       printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
 }
 
 int
@@ -2041,6 +2108,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                {"launcher", required_argument, NULL, 21},
                {"load-extension", required_argument, NULL, 22},
                {"config-auth", required_argument, NULL, 24},
+               {"max-concurrent-tests", required_argument, NULL, 25},
                {NULL, 0, NULL, 0}
        };
 
@@ -2051,9 +2119,12 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        char            buf[MAXPGPATH * 4];
        char            buf2[MAXPGPATH * 4];
 
+       pg_logging_init(argv[0]);
        progname = get_progname(argv[0]);
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
 
+       get_restricted_token();
+
        atexit(stop_postmaster);
 
 #ifndef HAVE_UNIX_SOCKETS
@@ -2154,6 +2225,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                        case 24:
                                config_auth_datadir = pg_strdup(optarg);
                                break;
+                       case 25:
+                               max_concurrent_tests = atoi(optarg);
+                               break;
                        default:
                                /* getopt_long already emitted a complaint */
                                fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
@@ -2174,7 +2248,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        if (config_auth_datadir)
        {
 #ifdef ENABLE_SSPI
-               config_sspi_auth(config_auth_datadir);
+               config_sspi_auth(config_auth_datadir, user);
 #endif
                exit(0);
        }
@@ -2239,7 +2313,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                /* initdb */
                header(_("initializing database system"));
                snprintf(buf, sizeof(buf),
-                                "\"%s%sinitdb\" -D \"%s/data\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
+                                "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1",
                                 bindir ? bindir : "",
                                 bindir ? "/" : "",
                                 temp_instance,
@@ -2270,6 +2344,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
                fputs("log_autovacuum_min_duration = 0\n", pg_conf);
                fputs("log_checkpoints = on\n", pg_conf);
+               fputs("log_line_prefix = '%m [%p] %q%a '\n", pg_conf);
                fputs("log_lock_waits = on\n", pg_conf);
                fputs("log_temp_files = 128kB\n", pg_conf);
                fputs("max_prepared_transactions = 2\n", pg_conf);
@@ -2300,7 +2375,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                 * "initdb" command, this can't truncate.
                 */
                snprintf(buf, sizeof(buf), "%s/data", temp_instance);
-               config_sspi_auth(buf);
+               config_sspi_auth(buf, NULL);
 #elif !defined(HAVE_UNIX_SOCKETS)
 #error Platform has no means to secure the test installation.
 #endif
@@ -2386,7 +2461,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                         * Fail immediately if postmaster has exited
                         */
 #ifndef WIN32
-                       if (kill(postmaster_pid, 0) != 0)
+                       if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
 #else
                        if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
 #endif