LCOV - code coverage report
Current view: top level - src/test/regress - pg_regress.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 71.8 % 942 676
Test Date: 2026-04-07 14:16:30 Functions: 85.4 % 41 35
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_regress --- regression test driver
       4              :  *
       5              :  * This is a C implementation of the previous shell script for running
       6              :  * the regression tests, and should be mostly compatible with it.
       7              :  * Initial author of C translation: Magnus Hagander
       8              :  *
       9              :  * This code is released under the terms of the PostgreSQL License.
      10              :  *
      11              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      12              :  * Portions Copyright (c) 1994, Regents of the University of California
      13              :  *
      14              :  * src/test/regress/pg_regress.c
      15              :  *
      16              :  *-------------------------------------------------------------------------
      17              :  */
      18              : 
      19              : #include "postgres_fe.h"
      20              : 
      21              : #include <ctype.h>
      22              : #include <sys/resource.h>
      23              : #include <sys/stat.h>
      24              : #include <sys/time.h>
      25              : #include <sys/wait.h>
      26              : #include <signal.h>
      27              : #include <unistd.h>
      28              : 
      29              : #include "common/logging.h"
      30              : #include "common/restricted_token.h"
      31              : #include "common/username.h"
      32              : #include "getopt_long.h"
      33              : #include "lib/stringinfo.h"
      34              : #include "libpq-fe.h"
      35              : #include "libpq/pqcomm.h"     /* needed for UNIXSOCK_PATH() */
      36              : #include "pg_config_paths.h"
      37              : #include "pg_regress.h"
      38              : #include "portability/instr_time.h"
      39              : 
      40              : /* for resultmap we need a list of pairs of strings */
      41              : typedef struct _resultmap
      42              : {
      43              :     char       *test;
      44              :     char       *type;
      45              :     char       *resultfile;
      46              :     struct _resultmap *next;
      47              : } _resultmap;
      48              : 
      49              : /*
      50              :  * Values obtained from Makefile.
      51              :  */
      52              : char       *host_platform = HOST_TUPLE;
      53              : 
      54              : #ifndef WIN32                   /* not used in WIN32 case */
      55              : static char *shellprog = SHELLPROG;
      56              : #endif
      57              : 
      58              : /*
      59              :  * On Windows we use -w in diff switches to avoid problems with inconsistent
      60              :  * newline representation.  The actual result files will generally have
      61              :  * Windows-style newlines, but the comparison files might or might not.
      62              :  */
      63              : #ifndef WIN32
      64              : const char *basic_diff_opts = "";
      65              : const char *pretty_diff_opts = "-U3";
      66              : #else
      67              : const char *basic_diff_opts = "--strip-trailing-cr";
      68              : const char *pretty_diff_opts = "--strip-trailing-cr -U3";
      69              : #endif
      70              : 
      71              : /*
      72              :  * The width of the testname field when printing to ensure vertical alignment
      73              :  * of test runtimes. This number is somewhat arbitrarily chosen to match the
      74              :  * older pre-TAP output format.
      75              :  */
      76              : #define TESTNAME_WIDTH 36
      77              : 
      78              : /*
      79              :  * The number times per second that pg_regress checks to see if the test
      80              :  * instance server has started and is available for connection.
      81              :  */
      82              : #define WAIT_TICKS_PER_SECOND 20
      83              : 
      84              : typedef enum TAPtype
      85              : {
      86              :     DIAG = 0,
      87              :     DIAG_DETAIL,
      88              :     DIAG_END,
      89              :     BAIL,
      90              :     NOTE,
      91              :     NOTE_DETAIL,
      92              :     NOTE_END,
      93              :     TEST_STATUS,
      94              :     PLAN,
      95              :     NONE,
      96              : } TAPtype;
      97              : 
      98              : /* options settable from command line */
      99              : _stringlist *dblist = NULL;
     100              : bool        debug = false;
     101              : char       *inputdir = ".";
     102              : char       *outputdir = ".";
     103              : char       *expecteddir = ".";
     104              : char       *bindir = PGBINDIR;
     105              : char       *launcher = NULL;
     106              : static _stringlist *loadextension = NULL;
     107              : static int  max_connections = 0;
     108              : static int  max_concurrent_tests = 0;
     109              : static char *encoding = NULL;
     110              : static _stringlist *schedulelist = NULL;
     111              : static _stringlist *extra_tests = NULL;
     112              : static char *temp_instance = NULL;
     113              : static _stringlist *temp_configs = NULL;
     114              : static bool nolocale = false;
     115              : static bool use_existing = false;
     116              : static char *hostname = NULL;
     117              : static int  port = -1;
     118              : static char portstr[16];
     119              : static bool port_specified_by_user = false;
     120              : static char *dlpath = PKGLIBDIR;
     121              : static char *user = NULL;
     122              : static _stringlist *extraroles = NULL;
     123              : static char *config_auth_datadir = NULL;
     124              : 
     125              : /* internal variables */
     126              : static const char *progname;
     127              : static char *logfilename;
     128              : static FILE *logfile;
     129              : static char *difffilename;
     130              : static const char *sockdir;
     131              : static const char *temp_sockdir;
     132              : static char sockself[MAXPGPATH];
     133              : static char socklock[MAXPGPATH];
     134              : static StringInfo failed_tests = NULL;
     135              : static bool in_note = false;
     136              : static bool in_diag = false;
     137              : 
     138              : static _resultmap *resultmap = NULL;
     139              : 
     140              : static PID_TYPE postmaster_pid = INVALID_PID;
     141              : static bool postmaster_running = false;
     142              : 
     143              : static int  success_count = 0;
     144              : static int  fail_count = 0;
     145              : 
     146              : static bool directory_exists(const char *dir);
     147              : static void make_directory(const char *dir);
     148              : 
     149              : static void test_status_print(bool ok, const char *testname, double runtime, bool parallel);
     150              : static void test_status_ok(const char *testname, double runtime, bool parallel);
     151              : static void test_status_failed(const char *testname, double runtime, bool parallel);
     152              : static void bail_out(bool noatexit, const char *fmt,...) pg_attribute_printf(2, 3);
     153              : static void emit_tap_output(TAPtype type, const char *fmt,...) pg_attribute_printf(2, 3);
     154              : static void emit_tap_output_v(TAPtype type, const char *fmt, va_list argp) pg_attribute_printf(2, 0);
     155              : 
     156              : static StringInfo psql_start_command(void);
     157              : static void psql_add_command(StringInfo buf, const char *query,...) pg_attribute_printf(2, 3);
     158              : static void psql_end_command(StringInfo buf, const char *database);
     159              : 
     160              : /*
     161              :  * Convenience macros for printing TAP output with a more shorthand syntax
     162              :  * aimed at making the code more readable.
     163              :  */
     164              : #define plan(x)             emit_tap_output(PLAN, "1..%i", (x))
     165              : #define note(...)           emit_tap_output(NOTE, __VA_ARGS__)
     166              : #define note_detail(...)    emit_tap_output(NOTE_DETAIL, __VA_ARGS__)
     167              : #define diag(...)           emit_tap_output(DIAG, __VA_ARGS__)
     168              : #define diag_detail(...)    emit_tap_output(DIAG_DETAIL, __VA_ARGS__)
     169              : #define diag_end()          emit_tap_output(DIAG_END, "\n");
     170              : #define note_end()          emit_tap_output(NOTE_END, "\n");
     171              : #define bail_noatexit(...)  bail_out(true, __VA_ARGS__)
     172              : #define bail(...)           bail_out(false, __VA_ARGS__)
     173              : 
     174              : /*
     175              :  * allow core files if possible.
     176              :  */
     177              : #if defined(HAVE_GETRLIMIT)
     178              : static void
     179          106 : unlimit_core_size(void)
     180              : {
     181              :     struct rlimit lim;
     182              : 
     183          106 :     getrlimit(RLIMIT_CORE, &lim);
     184          106 :     if (lim.rlim_max == 0)
     185              :     {
     186            0 :         diag("could not set core size: disallowed by hard limit");
     187            0 :         return;
     188              :     }
     189          106 :     else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
     190              :     {
     191          106 :         lim.rlim_cur = lim.rlim_max;
     192          106 :         setrlimit(RLIMIT_CORE, &lim);
     193              :     }
     194              : }
     195              : #endif
     196              : 
     197              : 
     198              : /*
     199              :  * Add an item at the end of a stringlist.
     200              :  */
     201              : void
     202         5135 : add_stringlist_item(_stringlist **listhead, const char *str)
     203              : {
     204         5135 :     _stringlist *newentry = pg_malloc_object(_stringlist);
     205              :     _stringlist *oldentry;
     206              : 
     207         5135 :     newentry->str = pg_strdup(str);
     208         5135 :     newentry->next = NULL;
     209         5135 :     if (*listhead == NULL)
     210         4066 :         *listhead = newentry;
     211              :     else
     212              :     {
     213         3644 :         for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
     214              :              /* skip */ ;
     215         1069 :         oldentry->next = newentry;
     216              :     }
     217         5135 : }
     218              : 
     219              : /*
     220              :  * Free a stringlist.
     221              :  */
     222              : static void
     223         4619 : free_stringlist(_stringlist **listhead)
     224              : {
     225         4619 :     if (listhead == NULL || *listhead == NULL)
     226         1118 :         return;
     227         3501 :     if ((*listhead)->next != NULL)
     228          780 :         free_stringlist(&((*listhead)->next));
     229         3501 :     free((*listhead)->str);
     230         3501 :     free(*listhead);
     231         3501 :     *listhead = NULL;
     232              : }
     233              : 
     234              : /*
     235              :  * Split a delimited string into a stringlist
     236              :  */
     237              : static void
     238          134 : split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
     239              : {
     240              :     char       *token;
     241              :     char       *sc;
     242              :     char       *tofree;
     243              : 
     244          134 :     tofree = sc = pg_strdup(s);
     245              : 
     246          277 :     while ((token = strsep(&sc, delim)))
     247              :     {
     248          143 :         add_stringlist_item(listhead, token);
     249              :     }
     250          134 :     free(tofree);
     251          134 : }
     252              : 
     253              : /*
     254              :  * Bailing out is for unrecoverable errors which prevents further testing to
     255              :  * occur and after which the test run should be aborted. By passing noatexit
     256              :  * as true the process will terminate with _exit(2) and skipping registered
     257              :  * exit handlers, thus avoid any risk of bottomless recursion calls to exit.
     258              :  */
     259              : static void
     260            0 : bail_out(bool noatexit, const char *fmt,...)
     261              : {
     262              :     va_list     ap;
     263              : 
     264            0 :     va_start(ap, fmt);
     265            0 :     emit_tap_output_v(BAIL, fmt, ap);
     266            0 :     va_end(ap);
     267              : 
     268            0 :     if (noatexit)
     269            0 :         _exit(2);
     270              : 
     271            0 :     exit(2);
     272              : }
     273              : 
     274              : /*
     275              :  * Print the result of a test run and associated metadata like runtime. Care
     276              :  * is taken to align testnames and runtimes vertically to ensure the output
     277              :  * is human readable while still TAP compliant. Tests run in parallel are
     278              :  * prefixed with a '+' and sequential tests with a '-'. This distinction was
     279              :  * previously indicated by 'test' prefixing sequential tests while parallel
     280              :  * tests were indented by four leading spaces. The meson TAP parser consumes
     281              :  * leading space however, so a non-whitespace prefix of the same length is
     282              :  * required for both.
     283              :  */
     284              : static void
     285         1606 : test_status_print(bool ok, const char *testname, double runtime, bool parallel)
     286              : {
     287         1606 :     int         testnumber = fail_count + success_count;
     288              : 
     289              :     /*
     290              :      * Testnumbers are padded to 5 characters to ensure that testnames align
     291              :      * vertically (assuming at most 9999 tests).  Testnames are prefixed with
     292              :      * a leading character to indicate being run in parallel or not. A leading
     293              :      * '+' indicates a parallel test, '-' indicates a single test.
     294              :      */
     295         1606 :     emit_tap_output(TEST_STATUS, "%sok %-5i%*s %c %-*s %8.0f ms",
     296              :                     (ok ? "" : "not "),
     297              :                     testnumber,
     298              :     /* If ok, indent with four spaces matching "not " */
     299              :                     (ok ? (int) strlen("not ") : 0), "",
     300              :     /* Prefix a parallel test '+' and a single test with '-' */
     301              :                     (parallel ? '+' : '-'),
     302              :     /* Testnames are padded to align runtimes */
     303              :                     TESTNAME_WIDTH, testname,
     304              :                     runtime);
     305         1606 : }
     306              : 
     307              : static void
     308         1606 : test_status_ok(const char *testname, double runtime, bool parallel)
     309              : {
     310         1606 :     success_count++;
     311              : 
     312         1606 :     test_status_print(true, testname, runtime, parallel);
     313         1606 : }
     314              : 
     315              : static void
     316            0 : test_status_failed(const char *testname, double runtime, bool parallel)
     317              : {
     318              :     /*
     319              :      * Save failed tests in a buffer such that we can print a summary at the
     320              :      * end with diag() to ensure it's shown even under test harnesses.
     321              :      */
     322            0 :     if (!failed_tests)
     323            0 :         failed_tests = makeStringInfo();
     324              :     else
     325            0 :         appendStringInfoChar(failed_tests, ',');
     326              : 
     327            0 :     appendStringInfo(failed_tests, " %s", testname);
     328              : 
     329            0 :     fail_count++;
     330              : 
     331            0 :     test_status_print(false, testname, runtime, parallel);
     332            0 : }
     333              : 
     334              : 
     335              : static void
     336         3131 : emit_tap_output(TAPtype type, const char *fmt,...)
     337              : {
     338              :     va_list     argp;
     339              : 
     340         3131 :     va_start(argp, fmt);
     341         3131 :     emit_tap_output_v(type, fmt, argp);
     342         3131 :     va_end(argp);
     343         3131 : }
     344              : 
     345              : static void
     346         3131 : emit_tap_output_v(TAPtype type, const char *fmt, va_list argp)
     347              : {
     348              :     va_list     argp_logfile;
     349              :     FILE       *fp;
     350              :     int         save_errno;
     351              : 
     352              :     /*
     353              :      * The fprintf() calls used to output TAP-protocol elements might clobber
     354              :      * errno, so save it here and restore it before vfprintf()-ing the user's
     355              :      * format string, in case it contains %m placeholders.
     356              :      */
     357         3131 :     save_errno = errno;
     358              : 
     359              :     /*
     360              :      * Diagnostic output will be hidden by prove unless printed to stderr. The
     361              :      * Bail message is also printed to stderr to aid debugging under a harness
     362              :      * which might otherwise not emit such an important message.
     363              :      */
     364         3131 :     if (type == DIAG || type == DIAG_DETAIL || type == DIAG_END || type == BAIL)
     365            0 :         fp = stderr;
     366              :     else
     367         3131 :         fp = stdout;
     368              : 
     369              :     /*
     370              :      * If we are ending a note_detail line we can avoid further processing and
     371              :      * immediately return following a newline.
     372              :      */
     373         3131 :     if (type == NOTE_END || type == DIAG_END)
     374              :     {
     375           76 :         if (type == NOTE_END)
     376           76 :             in_note = false;
     377              :         else
     378            0 :             in_diag = false;
     379           76 :         fprintf(fp, "\n");
     380           76 :         if (logfile)
     381           76 :             fprintf(logfile, "\n");
     382           76 :         return;
     383              :     }
     384              : 
     385              :     /* Make a copy of the va args for printing to the logfile */
     386         3055 :     va_copy(argp_logfile, argp);
     387              : 
     388              :     /*
     389              :      * Non-protocol output such as diagnostics or notes must be prefixed by a
     390              :      * '#' character. We print the Bail message like this too.
     391              :      */
     392         3055 :     if ((type == NOTE || type == DIAG || type == BAIL)
     393         2740 :         || (type == NOTE_DETAIL && !in_note)
     394         2664 :         || (type == DIAG_DETAIL && !in_diag))
     395              :     {
     396          391 :         fprintf(fp, "# ");
     397          391 :         if (logfile)
     398          391 :             fprintf(logfile, "# ");
     399              :     }
     400         3055 :     errno = save_errno;
     401         3055 :     vfprintf(fp, fmt, argp);
     402         3055 :     if (logfile)
     403              :     {
     404         3055 :         errno = save_errno;
     405         3055 :         vfprintf(logfile, fmt, argp_logfile);
     406              :     }
     407              : 
     408              :     /*
     409              :      * If we are entering into a note with more details to follow, register
     410              :      * that the leading '#' has been printed such that subsequent details
     411              :      * aren't prefixed as well.
     412              :      */
     413         3055 :     if (type == NOTE_DETAIL)
     414         1028 :         in_note = true;
     415         3055 :     if (type == DIAG_DETAIL)
     416            0 :         in_diag = true;
     417              : 
     418              :     /*
     419              :      * If this was a Bail message, the bail protocol message must go to stdout
     420              :      * separately.
     421              :      */
     422         3055 :     if (type == BAIL)
     423              :     {
     424            0 :         fprintf(stdout, "Bail out!");
     425            0 :         if (logfile)
     426            0 :             fprintf(logfile, "Bail out!");
     427              :     }
     428              : 
     429         3055 :     va_end(argp_logfile);
     430              : 
     431         3055 :     if (type != NOTE_DETAIL && type != DIAG_DETAIL)
     432              :     {
     433         2027 :         fprintf(fp, "\n");
     434         2027 :         if (logfile)
     435         2027 :             fprintf(logfile, "\n");
     436              :     }
     437         3055 :     fflush(NULL);
     438              : }
     439              : 
     440              : /*
     441              :  * shut down temp postmaster
     442              :  */
     443              : static void
     444          570 : stop_postmaster(void)
     445              : {
     446          570 :     if (postmaster_running)
     447              :     {
     448              :         /* We use pg_ctl to issue the kill and wait for stop */
     449              :         char        buf[MAXPGPATH * 2];
     450              :         int         r;
     451              : 
     452          206 :         snprintf(buf, sizeof(buf),
     453              :                  "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
     454          103 :                  bindir ? bindir : "",
     455          103 :                  bindir ? "/" : "",
     456              :                  temp_instance);
     457          103 :         fflush(NULL);
     458          103 :         r = system(buf);
     459          103 :         if (r != 0)
     460              :         {
     461              :             /* Not using the normal bail() as we want _exit */
     462            0 :             bail_noatexit(_("could not stop postmaster: exit code was %d"), r);
     463              :         }
     464              : 
     465          103 :         postmaster_running = false;
     466              :     }
     467          570 : }
     468              : 
     469              : /*
     470              :  * Remove the socket temporary directory.  pg_regress never waits for a
     471              :  * postmaster exit, so it is indeterminate whether the postmaster has yet to
     472              :  * unlink the socket and lock file.  Unlink them here so we can proceed to
     473              :  * remove the directory.  Ignore errors; leaking a temporary directory is
     474              :  * unimportant.  This can run from a signal handler.  The code is not
     475              :  * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
     476              :  * on Windows, pg_regress does not use Unix sockets by default.
     477              :  */
     478              : static void
     479          102 : remove_temp(void)
     480              : {
     481              :     Assert(temp_sockdir);
     482          102 :     unlink(sockself);
     483          102 :     unlink(socklock);
     484          102 :     rmdir(temp_sockdir);
     485          102 : }
     486              : 
     487              : /*
     488              :  * Signal handler that calls remove_temp() and reraises the signal.
     489              :  */
     490              : static void
     491            0 : signal_remove_temp(SIGNAL_ARGS)
     492              : {
     493            0 :     remove_temp();
     494              : 
     495            0 :     pqsignal(postgres_signal_arg, SIG_DFL);
     496            0 :     raise(postgres_signal_arg);
     497            0 : }
     498              : 
     499              : /*
     500              :  * Create a temporary directory suitable for the server's Unix-domain socket.
     501              :  * The directory will have mode 0700 or stricter, so no other OS user can open
     502              :  * our socket to exploit our use of trust authentication.  Most systems
     503              :  * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
     504              :  * place the directory under /tmp rather than relative to the possibly-deep
     505              :  * current working directory.
     506              :  *
     507              :  * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
     508              :  * testing to work in builds that relocate it to a directory not writable to
     509              :  * the build/test user.
     510              :  */
     511              : static const char *
     512          102 : make_temp_sockdir(void)
     513              : {
     514          102 :     char       *template = psprintf("%s/pg_regress-XXXXXX",
     515          102 :                                     getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
     516              : 
     517          102 :     temp_sockdir = mkdtemp(template);
     518          102 :     if (temp_sockdir == NULL)
     519            0 :         bail("could not create directory \"%s\": %m", template);
     520              : 
     521              :     /* Stage file names for remove_temp().  Unsafe in a signal handler. */
     522          102 :     UNIXSOCK_PATH(sockself, port, temp_sockdir);
     523          102 :     snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
     524              : 
     525              :     /* Remove the directory during clean exit. */
     526          102 :     atexit(remove_temp);
     527              : 
     528              :     /*
     529              :      * Remove the directory before dying to the usual signals.  Omit SIGQUIT,
     530              :      * preserving it as a quick, untidy exit.
     531              :      */
     532          102 :     pqsignal(SIGINT, signal_remove_temp);
     533          102 :     pqsignal(SIGTERM, signal_remove_temp);
     534              : 
     535              :     /* the following are not valid on Windows */
     536              : #ifndef WIN32
     537          102 :     pqsignal(SIGHUP, signal_remove_temp);
     538          102 :     pqsignal(SIGPIPE, signal_remove_temp);
     539              : #endif
     540              : 
     541          102 :     return temp_sockdir;
     542              : }
     543              : 
     544              : /*
     545              :  * Check whether string matches pattern
     546              :  *
     547              :  * In the original shell script, this function was implemented using expr(1),
     548              :  * which provides basic regular expressions restricted to match starting at
     549              :  * the string start (in conventional regex terms, there's an implicit "^"
     550              :  * at the start of the pattern --- but no implicit "$" at the end).
     551              :  *
     552              :  * For now, we only support "." and ".*" as non-literal metacharacters,
     553              :  * because that's all that anyone has found use for in resultmap.  This
     554              :  * code could be extended if more functionality is needed.
     555              :  */
     556              : static bool
     557           56 : string_matches_pattern(const char *str, const char *pattern)
     558              : {
     559          104 :     while (*str && *pattern)
     560              :     {
     561          104 :         if (*pattern == '.' && pattern[1] == '*')
     562              :         {
     563           32 :             pattern += 2;
     564              :             /* Trailing .* matches everything. */
     565           32 :             if (*pattern == '\0')
     566            0 :                 return true;
     567              : 
     568              :             /*
     569              :              * Otherwise, scan for a text position at which we can match the
     570              :              * rest of the pattern.
     571              :              */
     572          376 :             while (*str)
     573              :             {
     574              :                 /*
     575              :                  * Optimization to prevent most recursion: don't recurse
     576              :                  * unless first pattern char might match this text char.
     577              :                  */
     578          344 :                 if (*str == *pattern || *pattern == '.')
     579              :                 {
     580           48 :                     if (string_matches_pattern(str, pattern))
     581            0 :                         return true;
     582              :                 }
     583              : 
     584          344 :                 str++;
     585              :             }
     586              : 
     587              :             /*
     588              :              * End of text with no match.
     589              :              */
     590           32 :             return false;
     591              :         }
     592           72 :         else if (*pattern != '.' && *str != *pattern)
     593              :         {
     594              :             /*
     595              :              * Not the single-character wildcard and no explicit match? Then
     596              :              * time to quit...
     597              :              */
     598           24 :             return false;
     599              :         }
     600              : 
     601           48 :         str++;
     602           48 :         pattern++;
     603              :     }
     604              : 
     605            0 :     if (*pattern == '\0')
     606            0 :         return true;            /* end of pattern, so declare match */
     607              : 
     608              :     /* End of input string.  Do we have matching pattern remaining? */
     609            0 :     while (*pattern == '.' && pattern[1] == '*')
     610            0 :         pattern += 2;
     611            0 :     if (*pattern == '\0')
     612            0 :         return true;            /* end of pattern, so declare match */
     613              : 
     614            0 :     return false;
     615              : }
     616              : 
     617              : /*
     618              :  * Scan resultmap file to find which platform-specific expected files to use.
     619              :  *
     620              :  * The format of each line of the file is
     621              :  *         testname/hostplatformpattern=substitutefile
     622              :  * where the hostplatformpattern is evaluated per the rules of expr(1),
     623              :  * namely, it is a standard regular expression with an implicit ^ at the start.
     624              :  * (We currently support only a very limited subset of regular expressions,
     625              :  * see string_matches_pattern() above.)  What hostplatformpattern will be
     626              :  * matched against is the config.guess output.  (In the shell-script version,
     627              :  * we also provided an indication of whether gcc or another compiler was in
     628              :  * use, but that facility isn't used anymore.)
     629              :  */
     630              : static void
     631          106 : load_resultmap(void)
     632              : {
     633              :     char        buf[MAXPGPATH];
     634              :     FILE       *f;
     635              : 
     636              :     /* scan the file ... */
     637          106 :     snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
     638          106 :     f = fopen(buf, "r");
     639          106 :     if (!f)
     640              :     {
     641              :         /* OK if it doesn't exist, else complain */
     642          102 :         if (errno == ENOENT)
     643          102 :             return;
     644            0 :         bail("could not open file \"%s\" for reading: %m", buf);
     645              :     }
     646              : 
     647           16 :     while (fgets(buf, sizeof(buf), f))
     648              :     {
     649              :         char       *platform;
     650              :         char       *file_type;
     651              :         char       *expected;
     652              :         int         i;
     653              : 
     654              :         /* strip trailing whitespace, especially the newline */
     655            8 :         i = strlen(buf);
     656           16 :         while (i > 0 && isspace((unsigned char) buf[i - 1]))
     657            8 :             buf[--i] = '\0';
     658              : 
     659              :         /* parse out the line fields */
     660            8 :         file_type = strchr(buf, ':');
     661            8 :         if (!file_type)
     662              :         {
     663            0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     664              :         }
     665            8 :         *file_type++ = '\0';
     666              : 
     667            8 :         platform = strchr(file_type, ':');
     668            8 :         if (!platform)
     669              :         {
     670            0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     671              :         }
     672            8 :         *platform++ = '\0';
     673            8 :         expected = strchr(platform, '=');
     674            8 :         if (!expected)
     675              :         {
     676            0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     677              :         }
     678            8 :         *expected++ = '\0';
     679              : 
     680              :         /*
     681              :          * if it's for current platform, save it in resultmap list. Note: by
     682              :          * adding at the front of the list, we ensure that in ambiguous cases,
     683              :          * the last match in the resultmap file is used. This mimics the
     684              :          * behavior of the old shell script.
     685              :          */
     686            8 :         if (string_matches_pattern(host_platform, platform))
     687              :         {
     688            0 :             _resultmap *entry = pg_malloc_object(_resultmap);
     689              : 
     690            0 :             entry->test = pg_strdup(buf);
     691            0 :             entry->type = pg_strdup(file_type);
     692            0 :             entry->resultfile = pg_strdup(expected);
     693            0 :             entry->next = resultmap;
     694            0 :             resultmap = entry;
     695              :         }
     696              :     }
     697            4 :     fclose(f);
     698              : }
     699              : 
     700              : /*
     701              :  * Check in resultmap if we should be looking at a different file
     702              :  */
     703              : static
     704              : const char *
     705         1872 : get_expectfile(const char *testname, const char *file)
     706              : {
     707              :     const char *file_type;
     708              :     _resultmap *rm;
     709              : 
     710              :     /*
     711              :      * Determine the file type from the file name. This is just what is
     712              :      * following the last dot in the file name.
     713              :      */
     714         1872 :     if (!file || !(file_type = strrchr(file, '.')))
     715            0 :         return NULL;
     716              : 
     717         1872 :     file_type++;
     718              : 
     719         1872 :     for (rm = resultmap; rm != NULL; rm = rm->next)
     720              :     {
     721            0 :         if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
     722              :         {
     723            0 :             return rm->resultfile;
     724              :         }
     725              :     }
     726              : 
     727         1872 :     return NULL;
     728              : }
     729              : 
     730              : /*
     731              :  * Prepare environment variables for running regression tests
     732              :  */
     733              : static void
     734          106 : initialize_environment(void)
     735              : {
     736              :     /*
     737              :      * Set default application_name.  (The test_start_function may choose to
     738              :      * override this, but if it doesn't, we have something useful in place.)
     739              :      */
     740          106 :     setenv("PGAPPNAME", "pg_regress", 1);
     741              : 
     742              :     /*
     743              :      * Set variables that the test scripts may need to refer to.
     744              :      */
     745          106 :     setenv("PG_ABS_SRCDIR", inputdir, 1);
     746          106 :     setenv("PG_ABS_BUILDDIR", outputdir, 1);
     747          106 :     setenv("PG_LIBDIR", dlpath, 1);
     748          106 :     setenv("PG_DLSUFFIX", DLSUFFIX, 1);
     749              : 
     750          106 :     if (nolocale)
     751              :     {
     752              :         /*
     753              :          * Clear out any non-C locale settings
     754              :          */
     755            2 :         unsetenv("LC_COLLATE");
     756            2 :         unsetenv("LC_CTYPE");
     757            2 :         unsetenv("LC_MONETARY");
     758            2 :         unsetenv("LC_NUMERIC");
     759            2 :         unsetenv("LC_TIME");
     760            2 :         unsetenv("LANG");
     761              : 
     762              :         /*
     763              :          * Most platforms have adopted the POSIX locale as their
     764              :          * implementation-defined default locale.  Exceptions include native
     765              :          * Windows, macOS with --enable-nls, and Cygwin with --enable-nls.
     766              :          * (Use of --enable-nls matters because libintl replaces setlocale().)
     767              :          * Also, PostgreSQL does not support macOS with locale environment
     768              :          * variables unset; see PostmasterMain().
     769              :          */
     770              : #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
     771              :         setenv("LANG", "C", 1);
     772              : #endif
     773              :     }
     774              : 
     775              :     /*
     776              :      * Set translation-related settings to English; otherwise psql will
     777              :      * produce translated messages and produce diffs.  (XXX If we ever support
     778              :      * translation of pg_regress, this needs to be moved elsewhere, where psql
     779              :      * is actually called.)
     780              :      */
     781          106 :     unsetenv("LANGUAGE");
     782          106 :     unsetenv("LC_ALL");
     783          106 :     setenv("LC_MESSAGES", "C", 1);
     784              : 
     785              :     /*
     786              :      * Set encoding as requested
     787              :      */
     788          106 :     if (encoding)
     789            1 :         setenv("PGCLIENTENCODING", encoding, 1);
     790              :     else
     791          105 :         unsetenv("PGCLIENTENCODING");
     792              : 
     793              :     /*
     794              :      * Set timezone and datestyle for datetime-related tests
     795              :      */
     796          106 :     setenv("PGTZ", "America/Los_Angeles", 1);
     797          106 :     setenv("PGDATESTYLE", "Postgres, MDY", 1);
     798              : 
     799              :     /*
     800              :      * Likewise set intervalstyle to ensure consistent results.  This is a bit
     801              :      * more painful because we must use PGOPTIONS, and we want to preserve the
     802              :      * user's ability to set other variables through that.
     803              :      */
     804              :     {
     805          106 :         const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
     806          106 :         const char *old_pgoptions = getenv("PGOPTIONS");
     807              :         char       *new_pgoptions;
     808              : 
     809          106 :         if (!old_pgoptions)
     810          106 :             old_pgoptions = "";
     811          106 :         new_pgoptions = psprintf("%s %s",
     812              :                                  old_pgoptions, my_pgoptions);
     813          106 :         setenv("PGOPTIONS", new_pgoptions, 1);
     814          106 :         free(new_pgoptions);
     815              :     }
     816              : 
     817          106 :     if (temp_instance)
     818              :     {
     819              :         /*
     820              :          * Clear out any environment vars that might cause psql to connect to
     821              :          * the wrong postmaster, or otherwise behave in nondefault ways. (Note
     822              :          * we also use psql's -X switch consistently, so that ~/.psqlrc files
     823              :          * won't mess things up.)  Also, set PGPORT to the temp port, and set
     824              :          * PGHOST depending on whether we are using TCP or Unix sockets.
     825              :          *
     826              :          * This list should be kept in sync with PostgreSQL/Test/Utils.pm.
     827              :          */
     828          103 :         unsetenv("PGCHANNELBINDING");
     829              :         /* PGCLIENTENCODING, see above */
     830          103 :         unsetenv("PGCONNECT_TIMEOUT");
     831          103 :         unsetenv("PGDATA");
     832          103 :         unsetenv("PGDATABASE");
     833          103 :         unsetenv("PGGSSDELEGATION");
     834          103 :         unsetenv("PGGSSENCMODE");
     835          103 :         unsetenv("PGGSSLIB");
     836              :         /* PGHOSTADDR, see below */
     837          103 :         unsetenv("PGKRBSRVNAME");
     838          103 :         unsetenv("PGPASSFILE");
     839          103 :         unsetenv("PGPASSWORD");
     840          103 :         unsetenv("PGREQUIREPEER");
     841          103 :         unsetenv("PGREQUIRESSL");
     842          103 :         unsetenv("PGSERVICE");
     843          103 :         unsetenv("PGSERVICEFILE");
     844          103 :         unsetenv("PGSSLCERT");
     845          103 :         unsetenv("PGSSLCRL");
     846          103 :         unsetenv("PGSSLCRLDIR");
     847          103 :         unsetenv("PGSSLKEY");
     848          103 :         unsetenv("PGSSLMAXPROTOCOLVERSION");
     849          103 :         unsetenv("PGSSLMINPROTOCOLVERSION");
     850          103 :         unsetenv("PGSSLMODE");
     851          103 :         unsetenv("PGSSLROOTCERT");
     852          103 :         unsetenv("PGSSLSNI");
     853          103 :         unsetenv("PGTARGETSESSIONATTRS");
     854          103 :         unsetenv("PGUSER");
     855              :         /* PGPORT, see below */
     856              :         /* PGHOST, see below */
     857              : 
     858          103 :         if (hostname != NULL)
     859            1 :             setenv("PGHOST", hostname, 1);
     860              :         else
     861              :         {
     862          102 :             sockdir = getenv("PG_REGRESS_SOCK_DIR");
     863          102 :             if (!sockdir)
     864          102 :                 sockdir = make_temp_sockdir();
     865          102 :             setenv("PGHOST", sockdir, 1);
     866              :         }
     867          103 :         unsetenv("PGHOSTADDR");
     868          103 :         if (port != -1)
     869              :         {
     870              :             char        s[16];
     871              : 
     872          103 :             snprintf(s, sizeof(s), "%d", port);
     873          103 :             setenv("PGPORT", s, 1);
     874              :         }
     875              :     }
     876              :     else
     877              :     {
     878              :         const char *pghost;
     879              :         const char *pgport;
     880              : 
     881              :         /*
     882              :          * When testing an existing install, we honor existing environment
     883              :          * variables, except if they're overridden by command line options.
     884              :          */
     885            3 :         if (hostname != NULL)
     886              :         {
     887            3 :             setenv("PGHOST", hostname, 1);
     888            3 :             unsetenv("PGHOSTADDR");
     889              :         }
     890            3 :         if (port != -1)
     891              :         {
     892              :             char        s[16];
     893              : 
     894            3 :             snprintf(s, sizeof(s), "%d", port);
     895            3 :             setenv("PGPORT", s, 1);
     896              :         }
     897            3 :         if (user != NULL)
     898            0 :             setenv("PGUSER", user, 1);
     899              : 
     900              :         /*
     901              :          * However, we *don't* honor PGDATABASE, since we certainly don't wish
     902              :          * to connect to whatever database the user might like as default.
     903              :          * (Most tests override PGDATABASE anyway, but there are some ECPG
     904              :          * test cases that don't.)
     905              :          */
     906            3 :         unsetenv("PGDATABASE");
     907              : 
     908              :         /*
     909              :          * Report what we're connecting to
     910              :          */
     911            3 :         pghost = getenv("PGHOST");
     912            3 :         pgport = getenv("PGPORT");
     913            3 :         if (!pghost)
     914              :         {
     915              :             /* Keep this bit in sync with libpq's default host location: */
     916            0 :             if (DEFAULT_PGSOCKET_DIR[0])
     917              :                  /* do nothing, we'll print "Unix socket" below */ ;
     918              :             else
     919            0 :                 pghost = "localhost"; /* DefaultHost in fe-connect.c */
     920              :         }
     921              : 
     922            3 :         if (pghost && pgport)
     923            3 :             note("using postmaster on %s, port %s", pghost, pgport);
     924            3 :         if (pghost && !pgport)
     925            0 :             note("using postmaster on %s, default port", pghost);
     926            3 :         if (!pghost && pgport)
     927            0 :             note("using postmaster on Unix socket, port %s", pgport);
     928            3 :         if (!pghost && !pgport)
     929            0 :             note("using postmaster on Unix socket, default port");
     930              :     }
     931              : 
     932          106 :     load_resultmap();
     933          106 : }
     934              : 
     935              : #ifdef ENABLE_SSPI
     936              : 
     937              : /* support for config_sspi_auth() */
     938              : static const char *
     939              : fmtHba(const char *raw)
     940              : {
     941              :     static char *ret;
     942              :     const char *rp;
     943              :     char       *wp;
     944              : 
     945              :     wp = ret = pg_realloc(ret, 3 + strlen(raw) * 2);
     946              : 
     947              :     *wp++ = '"';
     948              :     for (rp = raw; *rp; rp++)
     949              :     {
     950              :         if (*rp == '"')
     951              :             *wp++ = '"';
     952              :         *wp++ = *rp;
     953              :     }
     954              :     *wp++ = '"';
     955              :     *wp++ = '\0';
     956              : 
     957              :     return ret;
     958              : }
     959              : 
     960              : /*
     961              :  * Get account and domain/realm names for the current user.  This is based on
     962              :  * pg_SSPI_recvauth().  The returned strings use static storage.
     963              :  */
     964              : static void
     965              : current_windows_user(const char **acct, const char **dom)
     966              : {
     967              :     static char accountname[MAXPGPATH];
     968              :     static char domainname[MAXPGPATH];
     969              :     HANDLE      token;
     970              :     TOKEN_USER *tokenuser;
     971              :     DWORD       retlen;
     972              :     DWORD       accountnamesize = sizeof(accountname);
     973              :     DWORD       domainnamesize = sizeof(domainname);
     974              :     SID_NAME_USE accountnameuse;
     975              : 
     976              :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token))
     977              :     {
     978              :         bail("could not open process token: error code %lu", GetLastError());
     979              :     }
     980              : 
     981              :     if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
     982              :     {
     983              :         bail("could not get token information buffer size: error code %lu",
     984              :              GetLastError());
     985              :     }
     986              :     tokenuser = pg_malloc(retlen);
     987              :     if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
     988              :     {
     989              :         bail("could not get token information: error code %lu",
     990              :              GetLastError());
     991              :     }
     992              : 
     993              :     if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
     994              :                           domainname, &domainnamesize, &accountnameuse))
     995              :     {
     996              :         bail("could not look up account SID: error code %lu",
     997              :              GetLastError());
     998              :     }
     999              : 
    1000              :     free(tokenuser);
    1001              : 
    1002              :     *acct = accountname;
    1003              :     *dom = domainname;
    1004              : }
    1005              : 
    1006              : /*
    1007              :  * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication.  Permit
    1008              :  * the current OS user to authenticate as the bootstrap superuser and as any
    1009              :  * user named in a --create-role option.
    1010              :  *
    1011              :  * In --config-auth mode, the --user switch can be used to specify the
    1012              :  * bootstrap superuser's name, otherwise we assume it is the default.
    1013              :  */
    1014              : static void
    1015              : config_sspi_auth(const char *pgdata, const char *superuser_name)
    1016              : {
    1017              :     const char *accountname,
    1018              :                *domainname;
    1019              :     char       *errstr;
    1020              :     bool        have_ipv6;
    1021              :     char        fname[MAXPGPATH];
    1022              :     int         res;
    1023              :     FILE       *hba,
    1024              :                *ident;
    1025              :     _stringlist *sl;
    1026              : 
    1027              :     /* Find out the name of the current OS user */
    1028              :     current_windows_user(&accountname, &domainname);
    1029              : 
    1030              :     /* Determine the bootstrap superuser's name */
    1031              :     if (superuser_name == NULL)
    1032              :     {
    1033              :         /*
    1034              :          * Compute the default superuser name the same way initdb does.
    1035              :          *
    1036              :          * It's possible that this result always matches "accountname", the
    1037              :          * value SSPI authentication discovers.  But the underlying system
    1038              :          * functions do not clearly guarantee that.
    1039              :          */
    1040              :         superuser_name = get_user_name(&errstr);
    1041              :         if (superuser_name == NULL)
    1042              :         {
    1043              :             bail("%s", errstr);
    1044              :         }
    1045              :     }
    1046              : 
    1047              :     /*
    1048              :      * Like initdb.c:setup_config(), determine whether the platform recognizes
    1049              :      * ::1 (IPv6 loopback) as a numeric host address string.
    1050              :      */
    1051              :     {
    1052              :         struct addrinfo *gai_result;
    1053              :         struct addrinfo hints;
    1054              :         WSADATA     wsaData;
    1055              : 
    1056              :         hints.ai_flags = AI_NUMERICHOST;
    1057              :         hints.ai_family = AF_UNSPEC;
    1058              :         hints.ai_socktype = 0;
    1059              :         hints.ai_protocol = 0;
    1060              :         hints.ai_addrlen = 0;
    1061              :         hints.ai_canonname = NULL;
    1062              :         hints.ai_addr = NULL;
    1063              :         hints.ai_next = NULL;
    1064              : 
    1065              :         have_ipv6 = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0 &&
    1066              :                      getaddrinfo("::1", NULL, &hints, &gai_result) == 0);
    1067              :     }
    1068              : 
    1069              :     /* Check a Write outcome and report any error. */
    1070              : #define CW(cond)    \
    1071              :     do { \
    1072              :         if (!(cond)) \
    1073              :             bail("could not write to file \"%s\": %m", fname); \
    1074              :     } while (0)
    1075              : 
    1076              :     res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
    1077              :     if (res < 0 || res >= sizeof(fname))
    1078              :     {
    1079              :         /*
    1080              :          * Truncating this name is a fatal error, because we must not fail to
    1081              :          * overwrite an original trust-authentication pg_hba.conf.
    1082              :          */
    1083              :         bail("directory name too long");
    1084              :     }
    1085              :     hba = fopen(fname, "w");
    1086              :     if (hba == NULL)
    1087              :     {
    1088              :         bail("could not open file \"%s\" for writing: %m", fname);
    1089              :     }
    1090              :     CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
    1091              :     CW(fputs("host all all 127.0.0.1/32  sspi include_realm=1 map=regress\n",
    1092              :              hba) >= 0);
    1093              :     if (have_ipv6)
    1094              :         CW(fputs("host all all ::1/128  sspi include_realm=1 map=regress\n",
    1095              :                  hba) >= 0);
    1096              :     CW(fclose(hba) == 0);
    1097              : 
    1098              :     snprintf(fname, sizeof(fname), "%s/pg_ident.conf", pgdata);
    1099              :     ident = fopen(fname, "w");
    1100              :     if (ident == NULL)
    1101              :     {
    1102              :         bail("could not open file \"%s\" for writing: %m", fname);
    1103              :     }
    1104              :     CW(fputs("# Configuration written by config_sspi_auth()\n", ident) >= 0);
    1105              : 
    1106              :     /*
    1107              :      * Double-quote for the benefit of account names containing whitespace or
    1108              :      * '#'.  Windows forbids the double-quote character itself, so don't
    1109              :      * bother escaping embedded double-quote characters.
    1110              :      */
    1111              :     CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
    1112              :                accountname, domainname, fmtHba(superuser_name)) >= 0);
    1113              :     for (sl = extraroles; sl; sl = sl->next)
    1114              :         CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
    1115              :                    accountname, domainname, fmtHba(sl->str)) >= 0);
    1116              :     CW(fclose(ident) == 0);
    1117              : }
    1118              : 
    1119              : #endif                          /* ENABLE_SSPI */
    1120              : 
    1121              : /*
    1122              :  * psql_start_command, psql_add_command, psql_end_command
    1123              :  *
    1124              :  * Issue one or more commands within one psql call.
    1125              :  * Set up with psql_start_command, then add commands one at a time
    1126              :  * with psql_add_command, and finally execute with psql_end_command.
    1127              :  *
    1128              :  * Since we use system(), this doesn't return until the operation finishes
    1129              :  */
    1130              : static StringInfo
    1131          125 : psql_start_command(void)
    1132              : {
    1133          125 :     StringInfo  buf = makeStringInfo();
    1134              : 
    1135          250 :     appendStringInfo(buf,
    1136              :                      "\"%s%spsql\" -X -q",
    1137          125 :                      bindir ? bindir : "",
    1138          125 :                      bindir ? "/" : "");
    1139          125 :     return buf;
    1140              : }
    1141              : 
    1142              : static void
    1143          248 : psql_add_command(StringInfo buf, const char *query,...)
    1144              : {
    1145              :     StringInfoData cmdbuf;
    1146              :     const char *cmdptr;
    1147              : 
    1148              :     /* Add each command as a -c argument in the psql call */
    1149          248 :     appendStringInfoString(buf, " -c \"");
    1150              : 
    1151              :     /* Generate the query with insertion of sprintf arguments */
    1152          248 :     initStringInfo(&cmdbuf);
    1153              :     for (;;)
    1154            0 :     {
    1155              :         va_list     args;
    1156              :         int         needed;
    1157              : 
    1158          248 :         va_start(args, query);
    1159          248 :         needed = appendStringInfoVA(&cmdbuf, query, args);
    1160          248 :         va_end(args);
    1161          248 :         if (needed == 0)
    1162          248 :             break;              /* success */
    1163            0 :         enlargeStringInfo(&cmdbuf, needed);
    1164              :     }
    1165              : 
    1166              :     /* Now escape any shell double-quote metacharacters */
    1167        47520 :     for (cmdptr = cmdbuf.data; *cmdptr; cmdptr++)
    1168              :     {
    1169        47272 :         if (strchr("\\\"$`", *cmdptr))
    1170         1594 :             appendStringInfoChar(buf, '\\');
    1171        47272 :         appendStringInfoChar(buf, *cmdptr);
    1172              :     }
    1173              : 
    1174          248 :     appendStringInfoChar(buf, '"');
    1175              : 
    1176          248 :     pfree(cmdbuf.data);
    1177          248 : }
    1178              : 
    1179              : static void
    1180          125 : psql_end_command(StringInfo buf, const char *database)
    1181              : {
    1182              :     /* Add the database name --- assume it needs no extra escaping */
    1183          125 :     appendStringInfo(buf,
    1184              :                      " \"%s\"",
    1185              :                      database);
    1186              : 
    1187              :     /* And now we can execute the shell command */
    1188          125 :     fflush(NULL);
    1189          125 :     if (system(buf->data) != 0)
    1190              :     {
    1191              :         /* psql probably already reported the error */
    1192            0 :         bail("command failed: %s", buf->data);
    1193              :     }
    1194              : 
    1195              :     /* Clean up */
    1196          125 :     destroyStringInfo(buf);
    1197          125 : }
    1198              : 
    1199              : /*
    1200              :  * Shorthand macro for the common case of a single command
    1201              :  */
    1202              : #define psql_command(database, ...) \
    1203              :     do { \
    1204              :         StringInfo cmdbuf = psql_start_command(); \
    1205              :         psql_add_command(cmdbuf, __VA_ARGS__); \
    1206              :         psql_end_command(cmdbuf, database); \
    1207              :     } while (0)
    1208              : 
    1209              : /*
    1210              :  * Spawn a process to execute the given shell command; don't wait for it
    1211              :  *
    1212              :  * Returns the process ID (or HANDLE) so we can wait for it later
    1213              :  */
    1214              : PID_TYPE
    1215         1709 : spawn_process(const char *cmdline)
    1216              : {
    1217              : #ifndef WIN32
    1218              :     pid_t       pid;
    1219              : 
    1220              :     /*
    1221              :      * Must flush I/O buffers before fork.
    1222              :      */
    1223         1709 :     fflush(NULL);
    1224              : 
    1225              : #ifdef EXEC_BACKEND
    1226              :     pg_disable_aslr();
    1227              : #endif
    1228              : 
    1229         1709 :     pid = fork();
    1230         3418 :     if (pid == -1)
    1231              :     {
    1232            0 :         bail("could not fork: %m");
    1233              :     }
    1234         3418 :     if (pid == 0)
    1235              :     {
    1236              :         /*
    1237              :          * In child
    1238              :          *
    1239              :          * Instead of using system(), exec the shell directly, and tell it to
    1240              :          * "exec" the command too.  This saves two useless processes per
    1241              :          * parallel test case.
    1242              :          */
    1243              :         char       *cmdline2;
    1244              : 
    1245         1709 :         cmdline2 = psprintf("exec %s", cmdline);
    1246         1709 :         execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
    1247              :         /* Not using the normal bail() here as we want _exit */
    1248         1709 :         bail_noatexit("could not exec \"%s\": %m", shellprog);
    1249              :     }
    1250              :     /* in parent */
    1251         1709 :     return pid;
    1252              : #else
    1253              :     PROCESS_INFORMATION pi;
    1254              :     char       *cmdline2;
    1255              :     const char *comspec;
    1256              : 
    1257              :     /* Find CMD.EXE location using COMSPEC, if it's set */
    1258              :     comspec = getenv("COMSPEC");
    1259              :     if (comspec == NULL)
    1260              :         comspec = "CMD";
    1261              : 
    1262              :     memset(&pi, 0, sizeof(pi));
    1263              :     cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
    1264              : 
    1265              :     if (!CreateRestrictedProcess(cmdline2, &pi))
    1266              :         exit(2);
    1267              : 
    1268              :     CloseHandle(pi.hThread);
    1269              :     return pi.hProcess;
    1270              : #endif
    1271              : }
    1272              : 
    1273              : /*
    1274              :  * Count bytes in file
    1275              :  */
    1276              : static long
    1277          106 : file_size(const char *file)
    1278              : {
    1279              :     long        r;
    1280          106 :     FILE       *f = fopen(file, "r");
    1281              : 
    1282          106 :     if (!f)
    1283              :     {
    1284            0 :         diag("could not open file \"%s\" for reading: %m", file);
    1285            0 :         return -1;
    1286              :     }
    1287          106 :     fseek(f, 0, SEEK_END);
    1288          106 :     r = ftell(f);
    1289          106 :     fclose(f);
    1290          106 :     return r;
    1291              : }
    1292              : 
    1293              : /*
    1294              :  * Count lines in file
    1295              :  */
    1296              : static int
    1297           57 : file_line_count(const char *file)
    1298              : {
    1299              :     int         c;
    1300           57 :     int         l = 0;
    1301           57 :     FILE       *f = fopen(file, "r");
    1302              : 
    1303           57 :     if (!f)
    1304              :     {
    1305            0 :         diag("could not open file \"%s\" for reading: %m", file);
    1306            0 :         return -1;
    1307              :     }
    1308       288612 :     while ((c = fgetc(f)) != EOF)
    1309              :     {
    1310       288555 :         if (c == '\n')
    1311        10356 :             l++;
    1312              :     }
    1313           57 :     fclose(f);
    1314           57 :     return l;
    1315              : }
    1316              : 
    1317              : bool
    1318         3056 : file_exists(const char *file)
    1319              : {
    1320         3056 :     FILE       *f = fopen(file, "r");
    1321              : 
    1322         3056 :     if (!f)
    1323         1847 :         return false;
    1324         1209 :     fclose(f);
    1325         1209 :     return true;
    1326              : }
    1327              : 
    1328              : static bool
    1329          418 : directory_exists(const char *dir)
    1330              : {
    1331              :     struct stat st;
    1332              : 
    1333          418 :     if (stat(dir, &st) != 0)
    1334          320 :         return false;
    1335           98 :     if (S_ISDIR(st.st_mode))
    1336           98 :         return true;
    1337            0 :     return false;
    1338              : }
    1339              : 
    1340              : /* Create a directory */
    1341              : static void
    1342          320 : make_directory(const char *dir)
    1343              : {
    1344          320 :     if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
    1345            0 :         bail("could not create directory \"%s\": %m", dir);
    1346          320 : }
    1347              : 
    1348              : /*
    1349              :  * In: filename.ext, Return: filename_i.ext, where 0 <= i <= 9
    1350              :  */
    1351              : static char *
    1352          110 : get_alternative_expectfile(const char *expectfile, int i)
    1353              : {
    1354              :     char       *last_dot;
    1355          110 :     int         ssize = strlen(expectfile) + 2 + 1;
    1356              :     char       *tmp;
    1357              :     char       *s;
    1358              : 
    1359          110 :     if (!(tmp = (char *) malloc(ssize)))
    1360            0 :         return NULL;
    1361              : 
    1362          110 :     if (!(s = (char *) malloc(ssize)))
    1363              :     {
    1364            0 :         free(tmp);
    1365            0 :         return NULL;
    1366              :     }
    1367              : 
    1368          110 :     strcpy(tmp, expectfile);
    1369          110 :     last_dot = strrchr(tmp, '.');
    1370          110 :     if (!last_dot)
    1371              :     {
    1372            0 :         free(tmp);
    1373            0 :         free(s);
    1374            0 :         return NULL;
    1375              :     }
    1376          110 :     *last_dot = '\0';
    1377          110 :     snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
    1378          110 :     free(tmp);
    1379          110 :     return s;
    1380              : }
    1381              : 
    1382              : /*
    1383              :  * Run a "diff" command and also check that it didn't crash
    1384              :  */
    1385              : static int
    1386         1929 : run_diff(const char *cmd, const char *filename)
    1387              : {
    1388              :     int         r;
    1389              : 
    1390         1929 :     fflush(NULL);
    1391         1929 :     r = system(cmd);
    1392         1929 :     if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
    1393              :     {
    1394            0 :         bail("diff command failed with status %d: %s", r, cmd);
    1395              :     }
    1396              : #ifdef WIN32
    1397              : 
    1398              :     /*
    1399              :      * On WIN32, if the 'diff' command cannot be found, system() returns 1,
    1400              :      * but produces nothing to stdout, so we check for that here.
    1401              :      */
    1402              :     if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
    1403              :     {
    1404              :         bail("diff command not found: %s", cmd);
    1405              :     }
    1406              : #endif
    1407              : 
    1408         1929 :     return WEXITSTATUS(r);
    1409              : }
    1410              : 
    1411              : /*
    1412              :  * Check the actual result file for the given test against expected results
    1413              :  *
    1414              :  * Returns true if different (failure), false if correct match found.
    1415              :  * In the true case, the diff is appended to the diffs file.
    1416              :  */
    1417              : static bool
    1418         1872 : results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
    1419              : {
    1420              :     char        expectfile[MAXPGPATH];
    1421              :     char        diff[MAXPGPATH];
    1422              :     char        cmd[MAXPGPATH * 3];
    1423              :     char        best_expect_file[MAXPGPATH];
    1424              :     FILE       *difffile;
    1425              :     int         best_line_count;
    1426              :     int         i;
    1427              :     int         l;
    1428              :     long        startpos;
    1429              :     const char *platform_expectfile;
    1430              : 
    1431              :     /*
    1432              :      * We can pass either the resultsfile or the expectfile, they should have
    1433              :      * the same type (filename.type) anyway.
    1434              :      */
    1435         1872 :     platform_expectfile = get_expectfile(testname, resultsfile);
    1436              : 
    1437         1872 :     strlcpy(expectfile, default_expectfile, sizeof(expectfile));
    1438         1872 :     if (platform_expectfile)
    1439              :     {
    1440              :         /*
    1441              :          * Replace everything after the last slash in expectfile with what the
    1442              :          * platform_expectfile contains.
    1443              :          */
    1444            0 :         char       *p = strrchr(expectfile, '/');
    1445              : 
    1446            0 :         if (p)
    1447            0 :             strcpy(++p, platform_expectfile);
    1448              :     }
    1449              : 
    1450              :     /* Name to use for temporary diff file */
    1451         1872 :     snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
    1452              : 
    1453              :     /* OK, run the diff */
    1454         1872 :     snprintf(cmd, sizeof(cmd),
    1455              :              "diff %s \"%s\" \"%s\" > \"%s\"",
    1456              :              basic_diff_opts, expectfile, resultsfile, diff);
    1457              : 
    1458              :     /* Is the diff file empty? */
    1459         1872 :     if (run_diff(cmd, diff) == 0)
    1460              :     {
    1461         1825 :         unlink(diff);
    1462         1825 :         return false;
    1463              :     }
    1464              : 
    1465              :     /* There may be secondary comparison files that match better */
    1466           47 :     best_line_count = file_line_count(diff);
    1467           47 :     strcpy(best_expect_file, expectfile);
    1468              : 
    1469          110 :     for (i = 0; i <= 9; i++)
    1470              :     {
    1471              :         char       *alt_expectfile;
    1472              : 
    1473          110 :         alt_expectfile = get_alternative_expectfile(expectfile, i);
    1474          110 :         if (!alt_expectfile)
    1475            0 :             bail("Unable to check secondary comparison files: %m");
    1476              : 
    1477          110 :         if (!file_exists(alt_expectfile))
    1478              :         {
    1479           53 :             free(alt_expectfile);
    1480           53 :             continue;
    1481              :         }
    1482              : 
    1483           57 :         snprintf(cmd, sizeof(cmd),
    1484              :                  "diff %s \"%s\" \"%s\" > \"%s\"",
    1485              :                  basic_diff_opts, alt_expectfile, resultsfile, diff);
    1486              : 
    1487           57 :         if (run_diff(cmd, diff) == 0)
    1488              :         {
    1489           47 :             unlink(diff);
    1490           47 :             free(alt_expectfile);
    1491           47 :             return false;
    1492              :         }
    1493              : 
    1494           10 :         l = file_line_count(diff);
    1495           10 :         if (l < best_line_count)
    1496              :         {
    1497              :             /* This diff was a better match than the last one */
    1498           10 :             best_line_count = l;
    1499           10 :             strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
    1500              :         }
    1501           10 :         free(alt_expectfile);
    1502              :     }
    1503              : 
    1504              :     /*
    1505              :      * fall back on the canonical results file if we haven't tried it yet and
    1506              :      * haven't found a complete match yet.
    1507              :      */
    1508              : 
    1509            0 :     if (platform_expectfile)
    1510              :     {
    1511            0 :         snprintf(cmd, sizeof(cmd),
    1512              :                  "diff %s \"%s\" \"%s\" > \"%s\"",
    1513              :                  basic_diff_opts, default_expectfile, resultsfile, diff);
    1514              : 
    1515            0 :         if (run_diff(cmd, diff) == 0)
    1516              :         {
    1517              :             /* No diff = no changes = good */
    1518            0 :             unlink(diff);
    1519            0 :             return false;
    1520              :         }
    1521              : 
    1522            0 :         l = file_line_count(diff);
    1523            0 :         if (l < best_line_count)
    1524              :         {
    1525              :             /* This diff was a better match than the last one */
    1526            0 :             best_line_count = l;
    1527            0 :             strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
    1528              :         }
    1529              :     }
    1530              : 
    1531              :     /*
    1532              :      * Use the best comparison file to generate the "pretty" diff, which we
    1533              :      * append to the diffs summary file.
    1534              :      */
    1535              : 
    1536            0 :     difffile = fopen(difffilename, "a");
    1537            0 :     if (difffile)
    1538              :     {
    1539            0 :         startpos = ftell(difffile);
    1540              : 
    1541              :         /* Write diff header */
    1542            0 :         fprintf(difffile,
    1543              :                 "diff %s %s %s\n",
    1544              :                 pretty_diff_opts, best_expect_file, resultsfile);
    1545            0 :         fclose(difffile);
    1546              : 
    1547              :         /* Run diff */
    1548            0 :         snprintf(cmd, sizeof(cmd),
    1549              :                  "diff %s \"%s\" \"%s\" >> \"%s\"",
    1550              :                  pretty_diff_opts, best_expect_file, resultsfile, difffilename);
    1551            0 :         run_diff(cmd, difffilename);
    1552              : 
    1553              :         /*
    1554              :          * Reopen the file for reading to emit the diff as TAP diagnostics. We
    1555              :          * can't keep the file open while diff appends to it, because on
    1556              :          * Windows the file lock prevents diff from writing.
    1557              :          */
    1558            0 :         difffile = fopen(difffilename, "r");
    1559              :     }
    1560              : 
    1561            0 :     if (difffile)
    1562              :     {
    1563              :         /*
    1564              :          * In case of a crash the diff can be huge and all of the subsequent
    1565              :          * tests will fail with essentially useless diffs too. So to avoid
    1566              :          * flooding the output, while still providing useful info in most
    1567              :          * cases we output only the first 80 lines of the *combined* diff. The
    1568              :          * number 80 is chosen so that we output less than 100 lines of
    1569              :          * diagnostics per pg_regress run. Otherwise if meson is run with the
    1570              :          * --quiet flag only the last 100 lines are shown and usually the most
    1571              :          * useful information is actually in the first few lines.
    1572              :          */
    1573              :         static int  nlines = 0;
    1574            0 :         const int   max_diff_lines = 80;
    1575              :         char        line[1024];
    1576              : 
    1577            0 :         fseek(difffile, startpos, SEEK_SET);
    1578            0 :         while (nlines < max_diff_lines &&
    1579            0 :                fgets(line, sizeof(line), difffile))
    1580              :         {
    1581            0 :             size_t      len = strlen(line);
    1582            0 :             bool        newline_found = (len > 0 && line[len - 1] == '\n');
    1583              : 
    1584            0 :             if (newline_found)
    1585            0 :                 line[len - 1] = '\0';
    1586              : 
    1587            0 :             diag_detail("%s", line);
    1588            0 :             if (newline_found)
    1589              :             {
    1590            0 :                 diag_end();
    1591            0 :                 nlines++;
    1592              :             }
    1593              :         }
    1594              : 
    1595            0 :         if (in_diag)
    1596              :         {
    1597              :             /*
    1598              :              * If there was no final newline for some reason, we should still
    1599              :              * end the diagnostic.
    1600              :              */
    1601            0 :             diag_end();
    1602            0 :             nlines++;
    1603              :         }
    1604              : 
    1605            0 :         if (nlines >= max_diff_lines)
    1606            0 :             diag("(diff output truncated and silencing output for further failing tests...)");
    1607              : 
    1608            0 :         fclose(difffile);
    1609              :     }
    1610              : 
    1611            0 :     unlink(diff);
    1612            0 :     return true;
    1613              : }
    1614              : 
    1615              : /*
    1616              :  * Wait for specified subprocesses to finish, and return their exit
    1617              :  * statuses into statuses[] and stop times into stoptimes[]
    1618              :  *
    1619              :  * If names isn't NULL, print each subprocess's name as it finishes
    1620              :  *
    1621              :  * Note: it's OK to scribble on the pids array, but not on the names array
    1622              :  */
    1623              : static void
    1624          730 : wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
    1625              :                char **names, int num_tests)
    1626              : {
    1627              :     int         tests_left;
    1628              :     int         i;
    1629              : 
    1630              : #ifdef WIN32
    1631              :     PID_TYPE   *active_pids = pg_malloc_array(PID_TYPE, num_tests);
    1632              : 
    1633              :     memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
    1634              : #endif
    1635              : 
    1636          730 :     tests_left = num_tests;
    1637         2336 :     while (tests_left > 0)
    1638              :     {
    1639              :         PID_TYPE    p;
    1640              : 
    1641              : #ifndef WIN32
    1642              :         int         exit_status;
    1643              : 
    1644         1606 :         p = wait(&exit_status);
    1645              : 
    1646         1606 :         if (p == INVALID_PID)
    1647            0 :             bail("failed to wait for subprocesses: %m");
    1648              : #else
    1649              :         DWORD       exit_status;
    1650              :         int         r;
    1651              : 
    1652              :         r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
    1653              :         if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
    1654              :         {
    1655              :             bail("failed to wait for subprocesses: error code %lu",
    1656              :                  GetLastError());
    1657              :         }
    1658              :         p = active_pids[r - WAIT_OBJECT_0];
    1659              :         /* compact the active_pids array */
    1660              :         active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
    1661              : #endif                          /* WIN32 */
    1662              : 
    1663         9222 :         for (i = 0; i < num_tests; i++)
    1664              :         {
    1665         9222 :             if (p == pids[i])
    1666              :             {
    1667              : #ifdef WIN32
    1668              :                 GetExitCodeProcess(pids[i], &exit_status);
    1669              :                 CloseHandle(pids[i]);
    1670              : #endif
    1671         1606 :                 pids[i] = INVALID_PID;
    1672         1606 :                 statuses[i] = (int) exit_status;
    1673         1606 :                 INSTR_TIME_SET_CURRENT(stoptimes[i]);
    1674         1606 :                 if (names)
    1675          952 :                     note_detail(" %s", names[i]);
    1676         1606 :                 tests_left--;
    1677         1606 :                 break;
    1678              :             }
    1679              :         }
    1680              :     }
    1681              : 
    1682              : #ifdef WIN32
    1683              :     free(active_pids);
    1684              : #endif
    1685          730 : }
    1686              : 
    1687              : /*
    1688              :  * report nonzero exit code from a test process
    1689              :  */
    1690              : static void
    1691            0 : log_child_failure(int exitstatus)
    1692              : {
    1693            0 :     if (WIFEXITED(exitstatus))
    1694            0 :         diag("(test process exited with exit code %d)",
    1695              :              WEXITSTATUS(exitstatus));
    1696            0 :     else if (WIFSIGNALED(exitstatus))
    1697              :     {
    1698              : #if defined(WIN32)
    1699              :         diag("(test process was terminated by exception 0x%X)",
    1700              :              WTERMSIG(exitstatus));
    1701              : #else
    1702            0 :         diag("(test process was terminated by signal %d: %s)",
    1703              :              WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
    1704              : #endif
    1705              :     }
    1706              :     else
    1707            0 :         diag("(test process exited with unrecognized status %d)", exitstatus);
    1708            0 : }
    1709              : 
    1710              : /*
    1711              :  * Run all the tests specified in one schedule file
    1712              :  */
    1713              : static void
    1714            7 : run_schedule(const char *schedule, test_start_function startfunc,
    1715              :              postprocess_result_function postfunc)
    1716              : {
    1717              : #define MAX_PARALLEL_TESTS 100
    1718              :     char       *tests[MAX_PARALLEL_TESTS];
    1719              :     _stringlist *resultfiles[MAX_PARALLEL_TESTS];
    1720              :     _stringlist *expectfiles[MAX_PARALLEL_TESTS];
    1721              :     _stringlist *tags[MAX_PARALLEL_TESTS];
    1722              :     PID_TYPE    pids[MAX_PARALLEL_TESTS];
    1723              :     instr_time  starttimes[MAX_PARALLEL_TESTS];
    1724              :     instr_time  stoptimes[MAX_PARALLEL_TESTS];
    1725              :     int         statuses[MAX_PARALLEL_TESTS];
    1726              :     char        scbuf[1024];
    1727              :     FILE       *scf;
    1728            7 :     int         line_num = 0;
    1729              : 
    1730            7 :     memset(tests, 0, sizeof(tests));
    1731            7 :     memset(resultfiles, 0, sizeof(resultfiles));
    1732            7 :     memset(expectfiles, 0, sizeof(expectfiles));
    1733            7 :     memset(tags, 0, sizeof(tags));
    1734              : 
    1735            7 :     scf = fopen(schedule, "r");
    1736            7 :     if (!scf)
    1737            0 :         bail("could not open file \"%s\" for reading: %m", schedule);
    1738              : 
    1739          841 :     while (fgets(scbuf, sizeof(scbuf), scf))
    1740              :     {
    1741          834 :         char       *test = NULL;
    1742              :         char       *c;
    1743              :         int         num_tests;
    1744              :         bool        inword;
    1745              :         int         i;
    1746              : 
    1747          834 :         line_num++;
    1748              : 
    1749              :         /* strip trailing whitespace, especially the newline */
    1750          834 :         i = strlen(scbuf);
    1751         1668 :         while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
    1752          834 :             scbuf[--i] = '\0';
    1753              : 
    1754          834 :         if (scbuf[0] == '\0' || scbuf[0] == '#')
    1755          464 :             continue;
    1756          370 :         if (strncmp(scbuf, "test: ", 6) == 0)
    1757          370 :             test = scbuf + 6;
    1758              :         else
    1759              :         {
    1760            0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1761              :                  schedule, line_num, scbuf);
    1762              :         }
    1763              : 
    1764          370 :         num_tests = 0;
    1765          370 :         inword = false;
    1766        15016 :         for (c = test;; c++)
    1767              :         {
    1768        15016 :             if (*c == '\0' || isspace((unsigned char) *c))
    1769              :             {
    1770         1246 :                 if (inword)
    1771              :                 {
    1772              :                     /* Reached end of a test name */
    1773              :                     char        sav;
    1774              : 
    1775         1246 :                     if (num_tests >= MAX_PARALLEL_TESTS)
    1776              :                     {
    1777            0 :                         bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1778              :                              MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
    1779              :                     }
    1780         1246 :                     sav = *c;
    1781         1246 :                     *c = '\0';
    1782         1246 :                     tests[num_tests] = pg_strdup(test);
    1783         1246 :                     num_tests++;
    1784         1246 :                     *c = sav;
    1785         1246 :                     inword = false;
    1786              :                 }
    1787         1246 :                 if (*c == '\0')
    1788          370 :                     break;      /* loop exit is here */
    1789              :             }
    1790        13770 :             else if (!inword)
    1791              :             {
    1792              :                 /* Start of a test name */
    1793         1246 :                 test = c;
    1794         1246 :                 inword = true;
    1795              :             }
    1796              :         }
    1797              : 
    1798          370 :         if (num_tests == 0)
    1799              :         {
    1800            0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1801              :                  schedule, line_num, scbuf);
    1802              :         }
    1803              : 
    1804          370 :         if (num_tests == 1)
    1805              :         {
    1806          294 :             pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
    1807          294 :             INSTR_TIME_SET_CURRENT(starttimes[0]);
    1808          294 :             wait_for_tests(pids, statuses, stoptimes, NULL, 1);
    1809              :             /* status line is finished below */
    1810              :         }
    1811           76 :         else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
    1812              :         {
    1813            0 :             bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1814              :                  max_concurrent_tests, schedule, line_num, scbuf);
    1815              :         }
    1816           76 :         else if (max_connections > 0 && max_connections < num_tests)
    1817            0 :         {
    1818            0 :             int         oldest = 0;
    1819              : 
    1820            0 :             note_detail("parallel group (%d tests, in groups of %d): ",
    1821              :                         num_tests, max_connections);
    1822            0 :             for (i = 0; i < num_tests; i++)
    1823              :             {
    1824            0 :                 if (i - oldest >= max_connections)
    1825              :                 {
    1826            0 :                     wait_for_tests(pids + oldest, statuses + oldest,
    1827            0 :                                    stoptimes + oldest,
    1828            0 :                                    tests + oldest, i - oldest);
    1829            0 :                     oldest = i;
    1830              :                 }
    1831            0 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1832            0 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1833              :             }
    1834            0 :             wait_for_tests(pids + oldest, statuses + oldest,
    1835            0 :                            stoptimes + oldest,
    1836            0 :                            tests + oldest, i - oldest);
    1837            0 :             note_end();
    1838              :         }
    1839              :         else
    1840              :         {
    1841           76 :             note_detail("parallel group (%d tests): ", num_tests);
    1842         1028 :             for (i = 0; i < num_tests; i++)
    1843              :             {
    1844          952 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1845          952 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1846              :             }
    1847           76 :             wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
    1848           76 :             note_end();
    1849              :         }
    1850              : 
    1851              :         /* Check results for all tests */
    1852         1616 :         for (i = 0; i < num_tests; i++)
    1853              :         {
    1854              :             _stringlist *rl,
    1855              :                        *el,
    1856              :                        *tl;
    1857         1246 :             bool        differ = false;
    1858              : 
    1859         1246 :             INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
    1860              : 
    1861              :             /*
    1862              :              * Advance over all three lists simultaneously.
    1863              :              *
    1864              :              * Compare resultfiles[j] with expectfiles[j] always. Tags are
    1865              :              * optional but if there are tags, the tag list has the same
    1866              :              * length as the other two lists.
    1867              :              */
    1868         1246 :             for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
    1869         2752 :                  rl != NULL;    /* rl and el have the same length */
    1870         1506 :                  rl = rl->next, el = el->next,
    1871         1506 :                  tl = tl ? tl->next : NULL)
    1872              :             {
    1873              :                 bool        newdiff;
    1874              : 
    1875         1506 :                 if (postfunc)
    1876          390 :                     (*postfunc) (rl->str);
    1877         1506 :                 newdiff = results_differ(tests[i], rl->str, el->str);
    1878         1506 :                 if (newdiff && tl)
    1879              :                 {
    1880            0 :                     diag("tag: %s", tl->str);
    1881              :                 }
    1882         1506 :                 differ |= newdiff;
    1883              :             }
    1884              : 
    1885         1246 :             if (statuses[i] != 0)
    1886              :             {
    1887            0 :                 test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1888            0 :                 log_child_failure(statuses[i]);
    1889              :             }
    1890              :             else
    1891              :             {
    1892         1246 :                 if (differ)
    1893              :                 {
    1894            0 :                     test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1895              :                 }
    1896              :                 else
    1897              :                 {
    1898         1246 :                     test_status_ok(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1899              :                 }
    1900              :             }
    1901              :         }
    1902              : 
    1903         1616 :         for (i = 0; i < num_tests; i++)
    1904              :         {
    1905         1246 :             pg_free(tests[i]);
    1906         1246 :             tests[i] = NULL;
    1907         1246 :             free_stringlist(&resultfiles[i]);
    1908         1246 :             free_stringlist(&expectfiles[i]);
    1909         1246 :             free_stringlist(&tags[i]);
    1910              :         }
    1911              :     }
    1912              : 
    1913            7 :     fclose(scf);
    1914            7 : }
    1915              : 
    1916              : /*
    1917              :  * Run a single test
    1918              :  */
    1919              : static void
    1920          360 : run_single_test(const char *test, test_start_function startfunc,
    1921              :                 postprocess_result_function postfunc)
    1922              : {
    1923              :     PID_TYPE    pid;
    1924              :     instr_time  starttime;
    1925              :     instr_time  stoptime;
    1926              :     int         exit_status;
    1927          360 :     _stringlist *resultfiles = NULL;
    1928          360 :     _stringlist *expectfiles = NULL;
    1929          360 :     _stringlist *tags = NULL;
    1930              :     _stringlist *rl,
    1931              :                *el,
    1932              :                *tl;
    1933          360 :     bool        differ = false;
    1934              : 
    1935          360 :     pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
    1936          360 :     INSTR_TIME_SET_CURRENT(starttime);
    1937          360 :     wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
    1938              : 
    1939              :     /*
    1940              :      * Advance over all three lists simultaneously.
    1941              :      *
    1942              :      * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
    1943              :      * but if there are tags, the tag list has the same length as the other
    1944              :      * two lists.
    1945              :      */
    1946          360 :     for (rl = resultfiles, el = expectfiles, tl = tags;
    1947          726 :          rl != NULL;            /* rl and el have the same length */
    1948          366 :          rl = rl->next, el = el->next,
    1949          366 :          tl = tl ? tl->next : NULL)
    1950              :     {
    1951              :         bool        newdiff;
    1952              : 
    1953          366 :         if (postfunc)
    1954            9 :             (*postfunc) (rl->str);
    1955          366 :         newdiff = results_differ(test, rl->str, el->str);
    1956          366 :         if (newdiff && tl)
    1957              :         {
    1958            0 :             diag("tag: %s", tl->str);
    1959              :         }
    1960          366 :         differ |= newdiff;
    1961              :     }
    1962              : 
    1963          360 :     INSTR_TIME_SUBTRACT(stoptime, starttime);
    1964              : 
    1965          360 :     if (exit_status != 0)
    1966              :     {
    1967            0 :         test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1968            0 :         log_child_failure(exit_status);
    1969              :     }
    1970              :     else
    1971              :     {
    1972          360 :         if (differ)
    1973              :         {
    1974            0 :             test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1975              :         }
    1976              :         else
    1977              :         {
    1978          360 :             test_status_ok(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1979              :         }
    1980              :     }
    1981          360 : }
    1982              : 
    1983              : /*
    1984              :  * Create the summary-output files (making them empty if already existing)
    1985              :  */
    1986              : static void
    1987          106 : open_result_files(void)
    1988              : {
    1989              :     char        file[MAXPGPATH];
    1990              :     FILE       *difffile;
    1991              : 
    1992              :     /* create outputdir directory if not present */
    1993          106 :     if (!directory_exists(outputdir))
    1994           10 :         make_directory(outputdir);
    1995              : 
    1996              :     /* create the log file (copy of running status output) */
    1997          106 :     snprintf(file, sizeof(file), "%s/regression.out", outputdir);
    1998          106 :     logfilename = pg_strdup(file);
    1999          106 :     logfile = fopen(logfilename, "w");
    2000          106 :     if (!logfile)
    2001            0 :         bail("could not open file \"%s\" for writing: %m", logfilename);
    2002              : 
    2003              :     /* create the diffs file as empty */
    2004          106 :     snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
    2005          106 :     difffilename = pg_strdup(file);
    2006          106 :     difffile = fopen(difffilename, "w");
    2007          106 :     if (!difffile)
    2008            0 :         bail("could not open file \"%s\" for writing: %m", difffilename);
    2009              : 
    2010              :     /* we don't keep the diffs file open continuously */
    2011          106 :     fclose(difffile);
    2012              : 
    2013              :     /* also create the results directory if not present */
    2014          106 :     snprintf(file, sizeof(file), "%s/results", outputdir);
    2015          106 :     if (!directory_exists(file))
    2016          105 :         make_directory(file);
    2017          106 : }
    2018              : 
    2019              : static void
    2020            3 : drop_database_if_exists(const char *dbname)
    2021              : {
    2022            3 :     StringInfo  buf = psql_start_command();
    2023              : 
    2024              :     /* Set warning level so we don't see chatter about nonexistent DB */
    2025            3 :     psql_add_command(buf, "SET client_min_messages = warning");
    2026            3 :     psql_add_command(buf, "DROP DATABASE IF EXISTS \"%s\"", dbname);
    2027            3 :     psql_end_command(buf, "postgres");
    2028            3 : }
    2029              : 
    2030              : static void
    2031          108 : create_database(const char *dbname)
    2032              : {
    2033          108 :     StringInfo  buf = psql_start_command();
    2034              :     _stringlist *sl;
    2035              : 
    2036              :     /*
    2037              :      * We use template0 so that any installation-local cruft in template1 will
    2038              :      * not mess up the tests.
    2039              :      */
    2040          108 :     if (encoding)
    2041            1 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
    2042            1 :                          (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
    2043              :     else
    2044          107 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
    2045          107 :                          (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
    2046          108 :     psql_add_command(buf,
    2047              :                      "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
    2048              :                      "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
    2049              :                      "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
    2050              :                      "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
    2051              :                      "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
    2052              :                      "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
    2053              :                      dbname, dbname, dbname, dbname, dbname, dbname);
    2054          108 :     psql_end_command(buf, "postgres");
    2055              : 
    2056              :     /*
    2057              :      * Install any requested extensions.  We use CREATE IF NOT EXISTS so that
    2058              :      * this will work whether or not the extension is preinstalled.
    2059              :      */
    2060          114 :     for (sl = loadextension; sl != NULL; sl = sl->next)
    2061            6 :         psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
    2062          108 : }
    2063              : 
    2064              : static void
    2065            0 : drop_role_if_exists(const char *rolename)
    2066              : {
    2067            0 :     StringInfo  buf = psql_start_command();
    2068              : 
    2069              :     /* Set warning level so we don't see chatter about nonexistent role */
    2070            0 :     psql_add_command(buf, "SET client_min_messages = warning");
    2071            0 :     psql_add_command(buf, "DROP ROLE IF EXISTS \"%s\"", rolename);
    2072            0 :     psql_end_command(buf, "postgres");
    2073            0 : }
    2074              : 
    2075              : static void
    2076            8 : create_role(const char *rolename, const _stringlist *granted_dbs)
    2077              : {
    2078            8 :     StringInfo  buf = psql_start_command();
    2079              : 
    2080            8 :     psql_add_command(buf, "CREATE ROLE \"%s\" WITH LOGIN", rolename);
    2081           20 :     for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
    2082              :     {
    2083           12 :         psql_add_command(buf, "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
    2084           12 :                          granted_dbs->str, rolename);
    2085              :     }
    2086            8 :     psql_end_command(buf, "postgres");
    2087            8 : }
    2088              : 
    2089              : static void
    2090            0 : help(void)
    2091              : {
    2092            0 :     printf(_("PostgreSQL regression test driver\n"));
    2093            0 :     printf(_("\n"));
    2094            0 :     printf(_("Usage:\n  %s [OPTION]... [EXTRA-TEST]...\n"), progname);
    2095            0 :     printf(_("\n"));
    2096            0 :     printf(_("Options:\n"));
    2097            0 :     printf(_("      --bindir=BINPATH          use BINPATH for programs that are run;\n"));
    2098            0 :     printf(_("                                if empty, use PATH from the environment\n"));
    2099            0 :     printf(_("      --config-auth=DATADIR     update authentication settings for DATADIR\n"));
    2100            0 :     printf(_("      --create-role=ROLE        create the specified role before testing\n"));
    2101            0 :     printf(_("      --dbname=DB               use database DB (default \"regression\")\n"));
    2102            0 :     printf(_("      --debug                   turn on debug mode in programs that are run\n"));
    2103            0 :     printf(_("      --dlpath=DIR              look for dynamic libraries in DIR\n"));
    2104            0 :     printf(_("      --encoding=ENCODING       use ENCODING as the encoding\n"));
    2105            0 :     printf(_("      --expecteddir=DIR         take expected files from DIR (default \".\")\n"));
    2106            0 :     printf(_("  -h, --help                    show this help, then exit\n"));
    2107            0 :     printf(_("      --inputdir=DIR            take input files from DIR (default \".\")\n"));
    2108            0 :     printf(_("      --launcher=CMD            use CMD as launcher of psql\n"));
    2109            0 :     printf(_("      --load-extension=EXT      load the named extension before running the\n"));
    2110            0 :     printf(_("                                tests; can appear multiple times\n"));
    2111            0 :     printf(_("      --max-connections=N       maximum number of concurrent connections\n"));
    2112            0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2113            0 :     printf(_("      --max-concurrent-tests=N  maximum number of concurrent tests in schedule\n"));
    2114            0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2115            0 :     printf(_("      --outputdir=DIR           place output files in DIR (default \".\")\n"));
    2116            0 :     printf(_("      --schedule=FILE           use test ordering schedule from FILE\n"));
    2117            0 :     printf(_("                                (can be used multiple times to concatenate)\n"));
    2118            0 :     printf(_("      --temp-instance=DIR       create a temporary instance in DIR\n"));
    2119            0 :     printf(_("      --use-existing            use an existing installation\n"));
    2120            0 :     printf(_("  -V, --version                 output version information, then exit\n"));
    2121            0 :     printf(_("\n"));
    2122            0 :     printf(_("Options for \"temp-instance\" mode:\n"));
    2123            0 :     printf(_("      --no-locale               use C locale\n"));
    2124            0 :     printf(_("      --port=PORT               start postmaster on PORT\n"));
    2125            0 :     printf(_("      --temp-config=FILE        append contents of FILE to temporary config\n"));
    2126            0 :     printf(_("\n"));
    2127            0 :     printf(_("Options for using an existing installation:\n"));
    2128            0 :     printf(_("      --host=HOST               use postmaster running on HOST\n"));
    2129            0 :     printf(_("      --port=PORT               use postmaster running at PORT\n"));
    2130            0 :     printf(_("      --user=USER               connect as USER\n"));
    2131            0 :     printf(_("\n"));
    2132            0 :     printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
    2133            0 :     printf(_("if the tests could not be run for some reason.\n"));
    2134            0 :     printf(_("\n"));
    2135            0 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    2136            0 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    2137            0 : }
    2138              : 
    2139              : int
    2140          467 : regression_main(int argc, char *argv[],
    2141              :                 init_function ifunc,
    2142              :                 test_start_function startfunc,
    2143              :                 postprocess_result_function postfunc)
    2144              : {
    2145              :     static struct option long_options[] = {
    2146              :         {"help", no_argument, NULL, 'h'},
    2147              :         {"version", no_argument, NULL, 'V'},
    2148              :         {"dbname", required_argument, NULL, 1},
    2149              :         {"debug", no_argument, NULL, 2},
    2150              :         {"inputdir", required_argument, NULL, 3},
    2151              :         {"max-connections", required_argument, NULL, 5},
    2152              :         {"encoding", required_argument, NULL, 6},
    2153              :         {"outputdir", required_argument, NULL, 7},
    2154              :         {"schedule", required_argument, NULL, 8},
    2155              :         {"temp-instance", required_argument, NULL, 9},
    2156              :         {"no-locale", no_argument, NULL, 10},
    2157              :         {"host", required_argument, NULL, 13},
    2158              :         {"port", required_argument, NULL, 14},
    2159              :         {"user", required_argument, NULL, 15},
    2160              :         {"bindir", required_argument, NULL, 16},
    2161              :         {"dlpath", required_argument, NULL, 17},
    2162              :         {"create-role", required_argument, NULL, 18},
    2163              :         {"temp-config", required_argument, NULL, 19},
    2164              :         {"use-existing", no_argument, NULL, 20},
    2165              :         {"launcher", required_argument, NULL, 21},
    2166              :         {"load-extension", required_argument, NULL, 22},
    2167              :         {"config-auth", required_argument, NULL, 24},
    2168              :         {"max-concurrent-tests", required_argument, NULL, 25},
    2169              :         {"expecteddir", required_argument, NULL, 26},
    2170              :         {NULL, 0, NULL, 0}
    2171              :     };
    2172              : 
    2173              :     bool        use_unix_sockets;
    2174              :     _stringlist *sl;
    2175              :     int         c;
    2176              :     int         i;
    2177              :     int         option_index;
    2178              :     char        buf[MAXPGPATH * 4];
    2179              : 
    2180          467 :     pg_logging_init(argv[0]);
    2181          467 :     progname = get_progname(argv[0]);
    2182          467 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
    2183              : 
    2184          467 :     get_restricted_token();
    2185              : 
    2186          467 :     atexit(stop_postmaster);
    2187              : 
    2188              : #if defined(WIN32)
    2189              : 
    2190              :     /*
    2191              :      * We don't use Unix-domain sockets on Windows by default (see comment at
    2192              :      * remove_temp() for a reason).  Override at your own risk.
    2193              :      */
    2194              :     use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
    2195              : #else
    2196          467 :     use_unix_sockets = true;
    2197              : #endif
    2198              : 
    2199          467 :     if (!use_unix_sockets)
    2200            0 :         hostname = "localhost";
    2201              : 
    2202              :     /*
    2203              :      * We call the initialization function here because that way we can set
    2204              :      * default parameters and let them be overwritten by the commandline.
    2205              :      */
    2206          467 :     ifunc(argc, argv);
    2207              : 
    2208          467 :     if (getenv("PG_REGRESS_DIFF_OPTS"))
    2209            0 :         pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
    2210              : 
    2211         1338 :     while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
    2212              :     {
    2213          871 :         switch (c)
    2214              :         {
    2215            0 :             case 'h':
    2216            0 :                 help();
    2217            0 :                 exit(0);
    2218            0 :             case 'V':
    2219            0 :                 puts("pg_regress (PostgreSQL) " PG_VERSION);
    2220            0 :                 exit(0);
    2221          101 :             case 1:
    2222              : 
    2223              :                 /*
    2224              :                  * If a default database was specified, we need to remove it
    2225              :                  * before we add the specified one.
    2226              :                  */
    2227          101 :                 free_stringlist(&dblist);
    2228          101 :                 split_to_stringlist(optarg, ",", &dblist);
    2229          101 :                 break;
    2230            0 :             case 2:
    2231            0 :                 debug = true;
    2232            0 :                 break;
    2233          104 :             case 3:
    2234          104 :                 inputdir = pg_strdup(optarg);
    2235          104 :                 break;
    2236            0 :             case 5:
    2237            0 :                 max_connections = atoi(optarg);
    2238            0 :                 break;
    2239            1 :             case 6:
    2240            1 :                 encoding = pg_strdup(optarg);
    2241            1 :                 break;
    2242           13 :             case 7:
    2243           13 :                 outputdir = pg_strdup(optarg);
    2244           13 :                 break;
    2245            7 :             case 8:
    2246            7 :                 add_stringlist_item(&schedulelist, optarg);
    2247            7 :                 break;
    2248          103 :             case 9:
    2249          103 :                 temp_instance = make_absolute_path(optarg);
    2250          103 :                 break;
    2251            2 :             case 10:
    2252            2 :                 nolocale = true;
    2253            2 :                 break;
    2254            4 :             case 13:
    2255            4 :                 hostname = pg_strdup(optarg);
    2256            4 :                 break;
    2257            3 :             case 14:
    2258            3 :                 port = atoi(optarg);
    2259            3 :                 port_specified_by_user = true;
    2260            3 :                 break;
    2261            3 :             case 15:
    2262            3 :                 user = pg_strdup(optarg);
    2263            3 :                 break;
    2264          106 :             case 16:
    2265              :                 /* "--bindir=" means to use PATH */
    2266          106 :                 if (strlen(optarg))
    2267            0 :                     bindir = pg_strdup(optarg);
    2268              :                 else
    2269          106 :                     bindir = NULL;
    2270          106 :                 break;
    2271            7 :             case 17:
    2272            7 :                 dlpath = pg_strdup(optarg);
    2273            7 :                 break;
    2274           33 :             case 18:
    2275           33 :                 split_to_stringlist(optarg, ",", &extraroles);
    2276           33 :                 break;
    2277           11 :             case 19:
    2278           11 :                 add_stringlist_item(&temp_configs, optarg);
    2279           11 :                 break;
    2280            0 :             case 20:
    2281            0 :                 use_existing = true;
    2282            0 :                 break;
    2283            0 :             case 21:
    2284            0 :                 launcher = pg_strdup(optarg);
    2285            0 :                 break;
    2286            6 :             case 22:
    2287            6 :                 add_stringlist_item(&loadextension, optarg);
    2288            6 :                 break;
    2289          361 :             case 24:
    2290          361 :                 config_auth_datadir = pg_strdup(optarg);
    2291          361 :                 break;
    2292            4 :             case 25:
    2293            4 :                 max_concurrent_tests = atoi(optarg);
    2294            4 :                 break;
    2295            2 :             case 26:
    2296            2 :                 expecteddir = pg_strdup(optarg);
    2297            2 :                 break;
    2298            0 :             default:
    2299              :                 /* getopt_long already emitted a complaint */
    2300            0 :                 pg_log_error_hint("Try \"%s --help\" for more information.",
    2301              :                                   progname);
    2302            0 :                 exit(2);
    2303              :         }
    2304              :     }
    2305              : 
    2306              :     /*
    2307              :      * if we still have arguments, they are extra tests to run
    2308              :      */
    2309          827 :     while (argc - optind >= 1)
    2310              :     {
    2311          360 :         add_stringlist_item(&extra_tests, argv[optind]);
    2312          360 :         optind++;
    2313              :     }
    2314              : 
    2315              :     /*
    2316              :      * We must have a database to run the tests in; either a default name, or
    2317              :      * one supplied by the --dbname switch.
    2318              :      */
    2319          467 :     if (!(dblist && dblist->str && dblist->str[0]))
    2320              :     {
    2321            0 :         bail("no database name was specified");
    2322              :     }
    2323              : 
    2324          467 :     if (config_auth_datadir)
    2325              :     {
    2326              : #ifdef ENABLE_SSPI
    2327              :         if (!use_unix_sockets)
    2328              :             config_sspi_auth(config_auth_datadir, user);
    2329              : #endif
    2330          361 :         exit(0);
    2331              :     }
    2332              : 
    2333          106 :     if (temp_instance && !port_specified_by_user)
    2334              : 
    2335              :         /*
    2336              :          * To reduce chances of interference with parallel installations, use
    2337              :          * a port number starting in the private range (49152-65535)
    2338              :          * calculated from the version number.  This aids non-Unix socket mode
    2339              :          * systems; elsewhere, the use of a private socket directory already
    2340              :          * prevents interference.
    2341              :          */
    2342          103 :         port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
    2343              : 
    2344          106 :     inputdir = make_absolute_path(inputdir);
    2345          106 :     outputdir = make_absolute_path(outputdir);
    2346          106 :     expecteddir = make_absolute_path(expecteddir);
    2347          106 :     dlpath = make_absolute_path(dlpath);
    2348              : 
    2349              :     /*
    2350              :      * Initialization
    2351              :      */
    2352          106 :     open_result_files();
    2353              : 
    2354          106 :     initialize_environment();
    2355              : 
    2356              : #if defined(HAVE_GETRLIMIT)
    2357          106 :     unlimit_core_size();
    2358              : #endif
    2359              : 
    2360          106 :     if (temp_instance)
    2361              :     {
    2362              :         StringInfoData cmd;
    2363              :         FILE       *pg_conf;
    2364              :         const char *env_wait;
    2365              :         int         wait_seconds;
    2366              :         const char *initdb_template_dir;
    2367              :         const char *keywords[4];
    2368              :         const char *values[4];
    2369              :         PGPing      rv;
    2370              :         const char *initdb_extra_opts_env;
    2371              : 
    2372              :         /*
    2373              :          * Prepare the temp instance
    2374              :          */
    2375              : 
    2376          103 :         if (directory_exists(temp_instance))
    2377              :         {
    2378            0 :             if (!rmtree(temp_instance, true))
    2379              :             {
    2380            0 :                 bail("could not remove temp instance \"%s\"", temp_instance);
    2381              :             }
    2382              :         }
    2383              : 
    2384              :         /* make the temp instance top directory */
    2385          103 :         make_directory(temp_instance);
    2386              : 
    2387              :         /* and a directory for log files */
    2388          103 :         snprintf(buf, sizeof(buf), "%s/log", outputdir);
    2389          103 :         if (!directory_exists(buf))
    2390          102 :             make_directory(buf);
    2391              : 
    2392          103 :         initdb_extra_opts_env = getenv("PG_TEST_INITDB_EXTRA_OPTS");
    2393              : 
    2394          103 :         initStringInfo(&cmd);
    2395              : 
    2396              :         /*
    2397              :          * Create data directory.
    2398              :          *
    2399              :          * If available, use a previously initdb'd cluster as a template by
    2400              :          * copying it. For a lot of tests, that's substantially cheaper.
    2401              :          *
    2402              :          * There's very similar code in Cluster.pm, but we can't easily de
    2403              :          * duplicate it until we require perl at build time.
    2404              :          */
    2405          103 :         initdb_template_dir = getenv("INITDB_TEMPLATE");
    2406          103 :         if (initdb_template_dir == NULL || nolocale || debug || initdb_extra_opts_env)
    2407              :         {
    2408            2 :             note("initializing database system by running initdb");
    2409              : 
    2410            4 :             appendStringInfo(&cmd,
    2411              :                              "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync",
    2412            2 :                              bindir ? bindir : "",
    2413            2 :                              bindir ? "/" : "",
    2414              :                              temp_instance);
    2415            2 :             if (debug)
    2416            0 :                 appendStringInfoString(&cmd, " --debug");
    2417            2 :             if (nolocale)
    2418            2 :                 appendStringInfoString(&cmd, " --no-locale");
    2419            2 :             if (initdb_extra_opts_env)
    2420            0 :                 appendStringInfo(&cmd, " %s", initdb_extra_opts_env);
    2421            2 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2422            2 :             fflush(NULL);
    2423            2 :             if (system(cmd.data))
    2424              :             {
    2425            0 :                 bail("initdb failed\n"
    2426              :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2427              :                      "# Command was: %s",
    2428              :                      outputdir, cmd.data);
    2429              :             }
    2430              :         }
    2431              :         else
    2432              :         {
    2433              : #ifndef WIN32
    2434          101 :             const char *copycmd = "cp -RPp \"%s\" \"%s/data\"";
    2435          101 :             int         expected_exitcode = 0;
    2436              : #else
    2437              :             const char *copycmd = "robocopy /E /NJS /NJH /NFL /NDL /NP \"%s\" \"%s/data\"";
    2438              :             int         expected_exitcode = 1;  /* 1 denotes files were copied */
    2439              : #endif
    2440              : 
    2441          101 :             note("initializing database system by copying initdb template");
    2442              : 
    2443          101 :             appendStringInfo(&cmd,
    2444              :                              copycmd,
    2445              :                              initdb_template_dir,
    2446              :                              temp_instance);
    2447          101 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2448          101 :             fflush(NULL);
    2449          101 :             if (system(cmd.data) != expected_exitcode)
    2450              :             {
    2451            0 :                 bail("copying of initdb template failed\n"
    2452              :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2453              :                      "# Command was: %s",
    2454              :                      outputdir, cmd.data);
    2455              :             }
    2456              :         }
    2457              : 
    2458          103 :         pfree(cmd.data);
    2459              : 
    2460              :         /*
    2461              :          * Adjust the default postgresql.conf for regression testing. The user
    2462              :          * can specify a file to be appended; in any case we expand logging
    2463              :          * and set max_prepared_transactions to enable testing of prepared
    2464              :          * xacts.  (Note: to reduce the probability of unexpected shmmax
    2465              :          * failures, don't set max_prepared_transactions any higher than
    2466              :          * actually needed by the prepared_xacts regression test.)
    2467              :          */
    2468          103 :         snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
    2469          103 :         pg_conf = fopen(buf, "a");
    2470          103 :         if (pg_conf == NULL)
    2471            0 :             bail("could not open \"%s\" for adding extra config: %m", buf);
    2472              : 
    2473          103 :         fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
    2474          103 :         fputs("log_autovacuum_min_duration = 0\n", pg_conf);
    2475          103 :         fputs("log_autoanalyze_min_duration = 0\n", pg_conf);
    2476          103 :         fputs("log_checkpoints = on\n", pg_conf);
    2477          103 :         fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
    2478          103 :         fputs("log_lock_waits = on\n", pg_conf);
    2479          103 :         fputs("log_temp_files = 128kB\n", pg_conf);
    2480          103 :         fputs("max_prepared_transactions = 2\n", pg_conf);
    2481              : 
    2482          114 :         for (sl = temp_configs; sl != NULL; sl = sl->next)
    2483              :         {
    2484           11 :             char       *temp_config = sl->str;
    2485              :             FILE       *extra_conf;
    2486              :             char        line_buf[1024];
    2487              : 
    2488           11 :             extra_conf = fopen(temp_config, "r");
    2489           11 :             if (extra_conf == NULL)
    2490              :             {
    2491            0 :                 bail("could not open \"%s\" to read extra config: %m",
    2492              :                      temp_config);
    2493              :             }
    2494           33 :             while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
    2495           22 :                 fputs(line_buf, pg_conf);
    2496           11 :             fclose(extra_conf);
    2497              :         }
    2498              : 
    2499          103 :         fclose(pg_conf);
    2500              : 
    2501              : #ifdef ENABLE_SSPI
    2502              :         if (!use_unix_sockets)
    2503              :         {
    2504              :             /*
    2505              :              * Since we successfully used the same buffer for the much-longer
    2506              :              * "initdb" command, this can't truncate.
    2507              :              */
    2508              :             snprintf(buf, sizeof(buf), "%s/data", temp_instance);
    2509              :             config_sspi_auth(buf, NULL);
    2510              :         }
    2511              : #endif
    2512              : 
    2513              :         /*
    2514              :          * Prepare the connection params for checking the state of the server
    2515              :          * before starting the tests.
    2516              :          */
    2517          103 :         sprintf(portstr, "%d", port);
    2518          103 :         keywords[0] = "dbname";
    2519          103 :         values[0] = "postgres";
    2520          103 :         keywords[1] = "port";
    2521          103 :         values[1] = portstr;
    2522          103 :         keywords[2] = "host";
    2523          103 :         values[2] = hostname ? hostname : sockdir;
    2524          103 :         keywords[3] = NULL;
    2525          103 :         values[3] = NULL;
    2526              : 
    2527              :         /*
    2528              :          * Check if there is a postmaster running already.
    2529              :          */
    2530          103 :         for (i = 0; i < 16; i++)
    2531              :         {
    2532          103 :             rv = PQpingParams(keywords, values, 1);
    2533              : 
    2534          103 :             if (rv == PQPING_OK)
    2535              :             {
    2536            0 :                 if (port_specified_by_user || i == 15)
    2537              :                 {
    2538            0 :                     note("port %d apparently in use", port);
    2539            0 :                     if (!port_specified_by_user)
    2540            0 :                         note("could not determine an available port");
    2541            0 :                     bail("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.");
    2542              :                 }
    2543              : 
    2544            0 :                 note("port %d apparently in use, trying %d", port, port + 1);
    2545            0 :                 port++;
    2546            0 :                 sprintf(portstr, "%d", port);
    2547            0 :                 setenv("PGPORT", portstr, 1);
    2548              :             }
    2549              :             else
    2550          103 :                 break;
    2551              :         }
    2552              : 
    2553              :         /*
    2554              :          * Start the temp postmaster
    2555              :          */
    2556          515 :         snprintf(buf, sizeof(buf),
    2557              :                  "\"%s%spostgres\" -D \"%s/data\" -F%s "
    2558              :                  "-c \"listen_addresses=%s\" -k \"%s\" "
    2559              :                  "> \"%s/log/postmaster.log\" 2>&1",
    2560          103 :                  bindir ? bindir : "",
    2561          103 :                  bindir ? "/" : "",
    2562          103 :                  temp_instance, debug ? " -d 5" : "",
    2563          206 :                  hostname ? hostname : "", sockdir ? sockdir : "",
    2564              :                  outputdir);
    2565          103 :         postmaster_pid = spawn_process(buf);
    2566          103 :         if (postmaster_pid == INVALID_PID)
    2567            0 :             bail("could not spawn postmaster: %m");
    2568              : 
    2569              :         /*
    2570              :          * Wait till postmaster is able to accept connections; normally takes
    2571              :          * only a fraction of a second or so, but Cygwin is reportedly *much*
    2572              :          * slower, and test builds using Valgrind or similar tools might be
    2573              :          * too.  Hence, allow the default timeout of 60 seconds to be
    2574              :          * overridden from the PGCTLTIMEOUT environment variable.
    2575              :          */
    2576          103 :         env_wait = getenv("PGCTLTIMEOUT");
    2577          103 :         if (env_wait != NULL)
    2578              :         {
    2579            0 :             wait_seconds = atoi(env_wait);
    2580            0 :             if (wait_seconds <= 0)
    2581            0 :                 wait_seconds = 60;
    2582              :         }
    2583              :         else
    2584          103 :             wait_seconds = 60;
    2585              : 
    2586          446 :         for (i = 0; i < wait_seconds * WAIT_TICKS_PER_SECOND; i++)
    2587              :         {
    2588              :             /*
    2589              :              * It's fairly unlikely that the server is responding immediately
    2590              :              * so we start with sleeping before checking instead of the other
    2591              :              * way around.
    2592              :              */
    2593          446 :             pg_usleep(1000000L / WAIT_TICKS_PER_SECOND);
    2594              : 
    2595          446 :             rv = PQpingParams(keywords, values, 1);
    2596              : 
    2597              :             /* Done if the server is running and accepts connections */
    2598          446 :             if (rv == PQPING_OK)
    2599          103 :                 break;
    2600              : 
    2601          343 :             if (rv == PQPING_NO_ATTEMPT)
    2602            0 :                 bail("attempting to connect to postmaster failed");
    2603              : 
    2604              :             /*
    2605              :              * Fail immediately if postmaster has exited
    2606              :              */
    2607              : #ifndef WIN32
    2608          343 :             if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
    2609              : #else
    2610              :             if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
    2611              : #endif
    2612              :             {
    2613            0 :                 bail("postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
    2614              :                      outputdir);
    2615              :             }
    2616              :         }
    2617          103 :         if (i >= wait_seconds * WAIT_TICKS_PER_SECOND)
    2618              :         {
    2619            0 :             diag("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
    2620              :                  wait_seconds, outputdir);
    2621              : 
    2622              :             /*
    2623              :              * If we get here, the postmaster is probably wedged somewhere in
    2624              :              * startup.  Try to kill it ungracefully rather than leaving a
    2625              :              * stuck postmaster that might interfere with subsequent test
    2626              :              * attempts.
    2627              :              */
    2628              : #ifndef WIN32
    2629            0 :             if (kill(postmaster_pid, SIGKILL) != 0 && errno != ESRCH)
    2630            0 :                 bail("could not kill failed postmaster: %m");
    2631              : #else
    2632              :             if (TerminateProcess(postmaster_pid, 255) == 0)
    2633              :                 bail("could not kill failed postmaster: error code %lu",
    2634              :                      GetLastError());
    2635              : #endif
    2636            0 :             bail("postmaster failed");
    2637              :         }
    2638              : 
    2639          103 :         postmaster_running = true;
    2640              : 
    2641              : #ifdef _WIN64
    2642              : /* need a series of two casts to convert HANDLE without compiler warning */
    2643              : #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
    2644              : #else
    2645              : #define ULONGPID(x) (unsigned long) (x)
    2646              : #endif
    2647          103 :         note("using temp instance on port %d with PID %lu",
    2648              :              port, ULONGPID(postmaster_pid));
    2649              :     }
    2650              :     else
    2651              :     {
    2652              :         /*
    2653              :          * Using an existing installation, so may need to get rid of
    2654              :          * pre-existing database(s) and role(s)
    2655              :          */
    2656            3 :         if (!use_existing)
    2657              :         {
    2658            6 :             for (sl = dblist; sl; sl = sl->next)
    2659            3 :                 drop_database_if_exists(sl->str);
    2660            3 :             for (sl = extraroles; sl; sl = sl->next)
    2661            0 :                 drop_role_if_exists(sl->str);
    2662              :         }
    2663              :     }
    2664              : 
    2665              :     /*
    2666              :      * Create the test database(s) and role(s)
    2667              :      */
    2668          106 :     if (!use_existing)
    2669              :     {
    2670          214 :         for (sl = dblist; sl; sl = sl->next)
    2671          108 :             create_database(sl->str);
    2672          114 :         for (sl = extraroles; sl; sl = sl->next)
    2673            8 :             create_role(sl->str, dblist);
    2674              :     }
    2675              : 
    2676              :     /*
    2677              :      * Ready to run the tests
    2678              :      */
    2679          113 :     for (sl = schedulelist; sl != NULL; sl = sl->next)
    2680              :     {
    2681            7 :         run_schedule(sl->str, startfunc, postfunc);
    2682              :     }
    2683              : 
    2684          466 :     for (sl = extra_tests; sl != NULL; sl = sl->next)
    2685              :     {
    2686          360 :         run_single_test(sl->str, startfunc, postfunc);
    2687              :     }
    2688              : 
    2689              :     /*
    2690              :      * Shut down temp installation's postmaster
    2691              :      */
    2692          106 :     if (temp_instance)
    2693              :     {
    2694          103 :         stop_postmaster();
    2695              :     }
    2696              : 
    2697              :     /*
    2698              :      * If there were no errors, remove the temp instance immediately to
    2699              :      * conserve disk space.  (If there were errors, we leave the instance in
    2700              :      * place for possible manual investigation.)
    2701              :      */
    2702          106 :     if (temp_instance && fail_count == 0)
    2703              :     {
    2704          103 :         if (!rmtree(temp_instance, true))
    2705            0 :             diag("could not remove temp instance \"%s\"",
    2706              :                  temp_instance);
    2707              :     }
    2708              : 
    2709              :     /*
    2710              :      * Emit a TAP compliant Plan
    2711              :      */
    2712          106 :     plan(fail_count + success_count);
    2713              : 
    2714              :     /*
    2715              :      * Emit nice-looking summary message
    2716              :      */
    2717          106 :     if (fail_count == 0)
    2718          106 :         note("All %d tests passed.", success_count);
    2719              :     else
    2720            0 :         diag("%d of %d tests failed.", fail_count, success_count + fail_count);
    2721              : 
    2722          106 :     if (file_size(difffilename) > 0)
    2723              :     {
    2724            0 :         diag("The differences that caused some tests to fail can be viewed in the file \"%s\".",
    2725              :              difffilename);
    2726            0 :         diag("A copy of the test summary that you see above is saved in the file \"%s\".",
    2727              :              logfilename);
    2728              :     }
    2729              :     else
    2730              :     {
    2731          106 :         unlink(difffilename);
    2732          106 :         unlink(logfilename);
    2733              :     }
    2734              : 
    2735          106 :     fclose(logfile);
    2736          106 :     logfile = NULL;
    2737              : 
    2738          106 :     if (fail_count != 0)
    2739            0 :         exit(1);
    2740              : 
    2741          106 :     return 0;
    2742              : }
        

Generated by: LCOV version 2.0-1