LCOV - code coverage report
Current view: top level - src/test/regress - pg_regress.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 71.6 % 945 677
Test Date: 2026-06-19 09:16:36 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         5151 : add_stringlist_item(_stringlist **listhead, const char *str)
     203              : {
     204         5151 :     _stringlist *newentry = pg_malloc_object(_stringlist);
     205              :     _stringlist *oldentry;
     206              : 
     207         5151 :     newentry->str = pg_strdup(str);
     208         5151 :     newentry->next = NULL;
     209         5151 :     if (*listhead == NULL)
     210         4066 :         *listhead = newentry;
     211              :     else
     212              :     {
     213         3702 :         for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
     214              :              /* skip */ ;
     215         1085 :         oldentry->next = newentry;
     216              :     }
     217         5151 : }
     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         1112 :         return;
     227         3507 :     if ((*listhead)->next != NULL)
     228          792 :         free_stringlist(&((*listhead)->next));
     229         3507 :     free((*listhead)->str);
     230         3507 :     free(*listhead);
     231         3507 :     *listhead = NULL;
     232              : }
     233              : 
     234              : /*
     235              :  * Split a delimited string into a stringlist
     236              :  */
     237              : static void
     238          135 : split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
     239              : {
     240              :     char       *token;
     241              :     char       *sc;
     242              :     char       *tofree;
     243              : 
     244          135 :     tofree = sc = pg_strdup(s);
     245              : 
     246          279 :     while ((token = strsep(&sc, delim)))
     247              :     {
     248          144 :         add_stringlist_item(listhead, token);
     249              :     }
     250          135 :     free(tofree);
     251          135 : }
     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         3123 : emit_tap_output(TAPtype type, const char *fmt, ...)
     337              : {
     338              :     va_list     argp;
     339              : 
     340         3123 :     va_start(argp, fmt);
     341         3123 :     emit_tap_output_v(type, fmt, argp);
     342         3123 :     va_end(argp);
     343         3123 : }
     344              : 
     345              : static void
     346         3123 : 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         3123 :     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         3123 :     if (type == DIAG || type == DIAG_DETAIL || type == DIAG_END || type == BAIL)
     365            0 :         fp = stderr;
     366              :     else
     367         3123 :         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         3123 :     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         3047 :     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         3047 :     if ((type == NOTE || type == DIAG || type == BAIL)
     393         2732 :         || (type == NOTE_DETAIL && !in_note)
     394         2656 :         || (type == DIAG_DETAIL && !in_diag))
     395              :     {
     396          391 :         fprintf(fp, "# ");
     397          391 :         if (logfile)
     398          391 :             fprintf(logfile, "# ");
     399              :     }
     400         3047 :     errno = save_errno;
     401         3047 :     vfprintf(fp, fmt, argp);
     402         3047 :     if (logfile)
     403              :     {
     404         3047 :         errno = save_errno;
     405         3047 :         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         3047 :     if (type == NOTE_DETAIL)
     414         1020 :         in_note = true;
     415         3047 :     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         3047 :     if (type == BAIL)
     423              :     {
     424            0 :         fprintf(stdout, "Bail out!");
     425            0 :         if (logfile)
     426            0 :             fprintf(logfile, "Bail out!");
     427              :     }
     428              : 
     429         3047 :     va_end(argp_logfile);
     430              : 
     431         3047 :     if (type != NOTE_DETAIL && type != DIAG_DETAIL)
     432              :     {
     433         2027 :         fprintf(fp, "\n");
     434         2027 :         if (logfile)
     435         2027 :             fprintf(logfile, "\n");
     436              :     }
     437         3047 :     fflush(NULL);
     438              : }
     439              : 
     440              : /*
     441              :  * shut down temp postmaster
     442              :  */
     443              : static void
     444          567 : stop_postmaster(void)
     445              : {
     446          567 :     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          567 : }
     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, PG_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         1876 : 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         1876 :     if (!file || !(file_type = strrchr(file, '.')))
     715            0 :         return NULL;
     716              : 
     717         1876 :     file_type++;
     718              : 
     719         1876 :     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         1876 :     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         3052 : file_exists(const char *file)
    1319              : {
    1320         3052 :     FILE       *f = fopen(file, "r");
    1321              : 
    1322         3052 :     if (!f)
    1323         1843 :         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         1933 : run_diff(const char *cmd, const char *filename)
    1387              : {
    1388              :     int         r;
    1389              : 
    1390         1933 :     fflush(NULL);
    1391         1933 :     r = system(cmd);
    1392         1933 :     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         1933 :     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         1876 : 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         1876 :     platform_expectfile = get_expectfile(testname, resultsfile);
    1436              : 
    1437         1876 :     strlcpy(expectfile, default_expectfile, sizeof(expectfile));
    1438         1876 :     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         1876 :     snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
    1452              : 
    1453              :     /* OK, run the diff */
    1454         1876 :     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         1876 :     if (run_diff(cmd, diff) == 0)
    1460              :     {
    1461         1829 :         unlink(diff);
    1462         1829 :         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            0 :         bail("could not open file \"%s\" for writing: %m", difffilename);
    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              :      * Emit the diff output as TAP diagnostics
    1555              :      *
    1556              :      * Reopen the file for reading. We can't keep the file open while diff
    1557              :      * appends to it, because on Windows the file lock prevents diff from
    1558              :      * writing.
    1559              :      */
    1560            0 :     difffile = fopen(difffilename, "r");
    1561            0 :     if (!difffile)
    1562            0 :         bail("could not open file \"%s\" for reading: %m", difffilename);
    1563              :     else
    1564              :     {
    1565              :         /*
    1566              :          * In case of a crash the diff can be huge and all of the subsequent
    1567              :          * tests will fail with essentially useless diffs too. So to avoid
    1568              :          * flooding the output, while still providing useful info in most
    1569              :          * cases we output only the first 80 lines of the *combined* diff. The
    1570              :          * number 80 is chosen so that we output less than 100 lines of
    1571              :          * diagnostics per pg_regress run. Otherwise if meson is run with the
    1572              :          * --quiet flag only the last 100 lines are shown and usually the most
    1573              :          * useful information is actually in the first few lines.
    1574              :          */
    1575              :         static int  nlines = 0;
    1576            0 :         const int   max_diff_lines = 80;
    1577              :         char        line[1024];
    1578              : 
    1579            0 :         fseek(difffile, startpos, SEEK_SET);
    1580            0 :         while (nlines < max_diff_lines &&
    1581            0 :                fgets(line, sizeof(line), difffile))
    1582              :         {
    1583            0 :             size_t      len = strlen(line);
    1584            0 :             bool        newline_found = (len > 0 && line[len - 1] == '\n');
    1585              : 
    1586            0 :             if (newline_found)
    1587            0 :                 line[len - 1] = '\0';
    1588              : 
    1589            0 :             diag_detail("%s", line);
    1590            0 :             if (newline_found)
    1591              :             {
    1592            0 :                 diag_end();
    1593            0 :                 nlines++;
    1594              :             }
    1595              :         }
    1596              : 
    1597            0 :         if (in_diag)
    1598              :         {
    1599              :             /*
    1600              :              * If there was no final newline for some reason, we should still
    1601              :              * end the diagnostic.
    1602              :              */
    1603            0 :             diag_end();
    1604            0 :             nlines++;
    1605              :         }
    1606              : 
    1607            0 :         if (nlines >= max_diff_lines)
    1608            0 :             diag("(diff output truncated and silencing output for further failing tests...)");
    1609              : 
    1610            0 :         fclose(difffile);
    1611              :     }
    1612              : 
    1613            0 :     unlink(diff);
    1614            0 :     return true;
    1615              : }
    1616              : 
    1617              : /*
    1618              :  * Wait for specified subprocesses to finish, and return their exit
    1619              :  * statuses into statuses[] and stop times into stoptimes[]
    1620              :  *
    1621              :  * If names isn't NULL, print each subprocess's name as it finishes
    1622              :  *
    1623              :  * Note: it's OK to scribble on the pids array, but not on the names array
    1624              :  */
    1625              : static void
    1626          738 : wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
    1627              :                char **names, int num_tests)
    1628              : {
    1629              :     int         tests_left;
    1630              :     int         i;
    1631              : 
    1632              : #ifdef WIN32
    1633              :     PID_TYPE   *active_pids = pg_malloc_array(PID_TYPE, num_tests);
    1634              : 
    1635              :     memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
    1636              : #endif
    1637              : 
    1638          738 :     tests_left = num_tests;
    1639         2344 :     while (tests_left > 0)
    1640              :     {
    1641              :         PID_TYPE    p;
    1642              : 
    1643              : #ifndef WIN32
    1644              :         int         exit_status;
    1645              : 
    1646         1606 :         p = wait(&exit_status);
    1647              : 
    1648         1606 :         if (p == INVALID_PID)
    1649            0 :             bail("failed to wait for subprocesses: %m");
    1650              : #else
    1651              :         DWORD       exit_status;
    1652              :         int         r;
    1653              : 
    1654              :         r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
    1655              :         if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
    1656              :         {
    1657              :             bail("failed to wait for subprocesses: error code %lu",
    1658              :                  GetLastError());
    1659              :         }
    1660              :         p = active_pids[r - WAIT_OBJECT_0];
    1661              :         /* compact the active_pids array */
    1662              :         active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
    1663              : #endif                          /* WIN32 */
    1664              : 
    1665         9014 :         for (i = 0; i < num_tests; i++)
    1666              :         {
    1667         9014 :             if (p == pids[i])
    1668              :             {
    1669              : #ifdef WIN32
    1670              :                 GetExitCodeProcess(pids[i], &exit_status);
    1671              :                 CloseHandle(pids[i]);
    1672              : #endif
    1673         1606 :                 pids[i] = INVALID_PID;
    1674         1606 :                 statuses[i] = (int) exit_status;
    1675         1606 :                 INSTR_TIME_SET_CURRENT(stoptimes[i]);
    1676         1606 :                 if (names)
    1677          944 :                     note_detail(" %s", names[i]);
    1678         1606 :                 tests_left--;
    1679         1606 :                 break;
    1680              :             }
    1681              :         }
    1682              :     }
    1683              : 
    1684              : #ifdef WIN32
    1685              :     free(active_pids);
    1686              : #endif
    1687          738 : }
    1688              : 
    1689              : /*
    1690              :  * report nonzero exit code from a test process
    1691              :  */
    1692              : static void
    1693            0 : log_child_failure(int exitstatus)
    1694              : {
    1695            0 :     if (WIFEXITED(exitstatus))
    1696            0 :         diag("(test process exited with exit code %d)",
    1697              :              WEXITSTATUS(exitstatus));
    1698            0 :     else if (WIFSIGNALED(exitstatus))
    1699              :     {
    1700              : #if defined(WIN32)
    1701              :         diag("(test process was terminated by exception 0x%X)",
    1702              :              WTERMSIG(exitstatus));
    1703              : #else
    1704            0 :         diag("(test process was terminated by signal %d: %s)",
    1705              :              WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
    1706              : #endif
    1707              :     }
    1708              :     else
    1709            0 :         diag("(test process exited with unrecognized status %d)", exitstatus);
    1710            0 : }
    1711              : 
    1712              : /*
    1713              :  * Run all the tests specified in one schedule file
    1714              :  */
    1715              : static void
    1716            7 : run_schedule(const char *schedule, test_start_function startfunc,
    1717              :              postprocess_result_function postfunc)
    1718              : {
    1719              : #define MAX_PARALLEL_TESTS 100
    1720              :     char       *tests[MAX_PARALLEL_TESTS];
    1721              :     _stringlist *resultfiles[MAX_PARALLEL_TESTS];
    1722              :     _stringlist *expectfiles[MAX_PARALLEL_TESTS];
    1723              :     _stringlist *tags[MAX_PARALLEL_TESTS];
    1724              :     PID_TYPE    pids[MAX_PARALLEL_TESTS];
    1725              :     instr_time  starttimes[MAX_PARALLEL_TESTS];
    1726              :     instr_time  stoptimes[MAX_PARALLEL_TESTS];
    1727              :     int         statuses[MAX_PARALLEL_TESTS];
    1728              :     char        scbuf[1024];
    1729              :     FILE       *scf;
    1730            7 :     int         line_num = 0;
    1731              : 
    1732            7 :     memset(tests, 0, sizeof(tests));
    1733            7 :     memset(resultfiles, 0, sizeof(resultfiles));
    1734            7 :     memset(expectfiles, 0, sizeof(expectfiles));
    1735            7 :     memset(tags, 0, sizeof(tags));
    1736              : 
    1737            7 :     scf = fopen(schedule, "r");
    1738            7 :     if (!scf)
    1739            0 :         bail("could not open file \"%s\" for reading: %m", schedule);
    1740              : 
    1741          861 :     while (fgets(scbuf, sizeof(scbuf), scf))
    1742              :     {
    1743          854 :         char       *test = NULL;
    1744              :         char       *c;
    1745              :         int         num_tests;
    1746              :         bool        inword;
    1747              :         int         i;
    1748              : 
    1749          854 :         line_num++;
    1750              : 
    1751              :         /* strip trailing whitespace, especially the newline */
    1752          854 :         i = strlen(scbuf);
    1753         1708 :         while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
    1754          854 :             scbuf[--i] = '\0';
    1755              : 
    1756          854 :         if (scbuf[0] == '\0' || scbuf[0] == '#')
    1757          480 :             continue;
    1758          374 :         if (strncmp(scbuf, "test: ", 6) == 0)
    1759          374 :             test = scbuf + 6;
    1760              :         else
    1761              :         {
    1762            0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1763              :                  schedule, line_num, scbuf);
    1764              :         }
    1765              : 
    1766          374 :         num_tests = 0;
    1767          374 :         inword = false;
    1768        15009 :         for (c = test;; c++)
    1769              :         {
    1770        15009 :             if (*c == '\0' || isspace((unsigned char) *c))
    1771              :             {
    1772         1242 :                 if (inword)
    1773              :                 {
    1774              :                     /* Reached end of a test name */
    1775              :                     char        sav;
    1776              : 
    1777         1242 :                     if (num_tests >= MAX_PARALLEL_TESTS)
    1778              :                     {
    1779            0 :                         bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1780              :                              MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
    1781              :                     }
    1782         1242 :                     sav = *c;
    1783         1242 :                     *c = '\0';
    1784         1242 :                     tests[num_tests] = pg_strdup(test);
    1785         1242 :                     num_tests++;
    1786         1242 :                     *c = sav;
    1787         1242 :                     inword = false;
    1788              :                 }
    1789         1242 :                 if (*c == '\0')
    1790          374 :                     break;      /* loop exit is here */
    1791              :             }
    1792        13767 :             else if (!inword)
    1793              :             {
    1794              :                 /* Start of a test name */
    1795         1242 :                 test = c;
    1796         1242 :                 inword = true;
    1797              :             }
    1798              :         }
    1799              : 
    1800          374 :         if (num_tests == 0)
    1801              :         {
    1802            0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1803              :                  schedule, line_num, scbuf);
    1804              :         }
    1805              : 
    1806          374 :         if (num_tests == 1)
    1807              :         {
    1808          298 :             pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
    1809          298 :             INSTR_TIME_SET_CURRENT(starttimes[0]);
    1810          298 :             wait_for_tests(pids, statuses, stoptimes, NULL, 1);
    1811              :             /* status line is finished below */
    1812              :         }
    1813           76 :         else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
    1814              :         {
    1815            0 :             bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1816              :                  max_concurrent_tests, schedule, line_num, scbuf);
    1817              :         }
    1818           76 :         else if (max_connections > 0 && max_connections < num_tests)
    1819            0 :         {
    1820            0 :             int         oldest = 0;
    1821              : 
    1822            0 :             note_detail("parallel group (%d tests, in groups of %d): ",
    1823              :                         num_tests, max_connections);
    1824            0 :             for (i = 0; i < num_tests; i++)
    1825              :             {
    1826            0 :                 if (i - oldest >= max_connections)
    1827              :                 {
    1828            0 :                     wait_for_tests(pids + oldest, statuses + oldest,
    1829            0 :                                    stoptimes + oldest,
    1830            0 :                                    tests + oldest, i - oldest);
    1831            0 :                     oldest = i;
    1832              :                 }
    1833            0 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1834            0 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1835              :             }
    1836            0 :             wait_for_tests(pids + oldest, statuses + oldest,
    1837            0 :                            stoptimes + oldest,
    1838            0 :                            tests + oldest, i - oldest);
    1839            0 :             note_end();
    1840              :         }
    1841              :         else
    1842              :         {
    1843           76 :             note_detail("parallel group (%d tests): ", num_tests);
    1844         1020 :             for (i = 0; i < num_tests; i++)
    1845              :             {
    1846          944 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1847          944 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1848              :             }
    1849           76 :             wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
    1850           76 :             note_end();
    1851              :         }
    1852              : 
    1853              :         /* Check results for all tests */
    1854         1616 :         for (i = 0; i < num_tests; i++)
    1855              :         {
    1856              :             _stringlist *rl,
    1857              :                        *el,
    1858              :                        *tl;
    1859         1242 :             bool        differ = false;
    1860              : 
    1861         1242 :             INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
    1862              : 
    1863              :             /*
    1864              :              * Advance over all three lists simultaneously.
    1865              :              *
    1866              :              * Compare resultfiles[j] with expectfiles[j] always. Tags are
    1867              :              * optional but if there are tags, the tag list has the same
    1868              :              * length as the other two lists.
    1869              :              */
    1870         1242 :             for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
    1871         2748 :                  rl != NULL;    /* rl and el have the same length */
    1872         1506 :                  rl = rl->next, el = el->next,
    1873         1506 :                  tl = tl ? tl->next : NULL)
    1874              :             {
    1875              :                 bool        newdiff;
    1876              : 
    1877         1506 :                 if (postfunc)
    1878          396 :                     (*postfunc) (rl->str);
    1879         1506 :                 newdiff = results_differ(tests[i], rl->str, el->str);
    1880         1506 :                 if (newdiff && tl)
    1881              :                 {
    1882            0 :                     diag("tag: %s", tl->str);
    1883              :                 }
    1884         1506 :                 differ |= newdiff;
    1885              :             }
    1886              : 
    1887         1242 :             if (statuses[i] != 0)
    1888              :             {
    1889            0 :                 test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1890            0 :                 log_child_failure(statuses[i]);
    1891              :             }
    1892              :             else
    1893              :             {
    1894         1242 :                 if (differ)
    1895              :                 {
    1896            0 :                     test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1897              :                 }
    1898              :                 else
    1899              :                 {
    1900         1242 :                     test_status_ok(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1901              :                 }
    1902              :             }
    1903              :         }
    1904              : 
    1905         1616 :         for (i = 0; i < num_tests; i++)
    1906              :         {
    1907         1242 :             pg_free(tests[i]);
    1908         1242 :             tests[i] = NULL;
    1909         1242 :             free_stringlist(&resultfiles[i]);
    1910         1242 :             free_stringlist(&expectfiles[i]);
    1911         1242 :             free_stringlist(&tags[i]);
    1912              :         }
    1913              :     }
    1914              : 
    1915            7 :     fclose(scf);
    1916            7 : }
    1917              : 
    1918              : /*
    1919              :  * Run a single test
    1920              :  */
    1921              : static void
    1922          364 : run_single_test(const char *test, test_start_function startfunc,
    1923              :                 postprocess_result_function postfunc)
    1924              : {
    1925              :     PID_TYPE    pid;
    1926              :     instr_time  starttime;
    1927              :     instr_time  stoptime;
    1928              :     int         exit_status;
    1929          364 :     _stringlist *resultfiles = NULL;
    1930          364 :     _stringlist *expectfiles = NULL;
    1931          364 :     _stringlist *tags = NULL;
    1932              :     _stringlist *rl,
    1933              :                *el,
    1934              :                *tl;
    1935          364 :     bool        differ = false;
    1936              : 
    1937          364 :     pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
    1938          364 :     INSTR_TIME_SET_CURRENT(starttime);
    1939          364 :     wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
    1940              : 
    1941              :     /*
    1942              :      * Advance over all three lists simultaneously.
    1943              :      *
    1944              :      * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
    1945              :      * but if there are tags, the tag list has the same length as the other
    1946              :      * two lists.
    1947              :      */
    1948          364 :     for (rl = resultfiles, el = expectfiles, tl = tags;
    1949          734 :          rl != NULL;            /* rl and el have the same length */
    1950          370 :          rl = rl->next, el = el->next,
    1951          370 :          tl = tl ? tl->next : NULL)
    1952              :     {
    1953              :         bool        newdiff;
    1954              : 
    1955          370 :         if (postfunc)
    1956            9 :             (*postfunc) (rl->str);
    1957          370 :         newdiff = results_differ(test, rl->str, el->str);
    1958          370 :         if (newdiff && tl)
    1959              :         {
    1960            0 :             diag("tag: %s", tl->str);
    1961              :         }
    1962          370 :         differ |= newdiff;
    1963              :     }
    1964              : 
    1965          364 :     INSTR_TIME_SUBTRACT(stoptime, starttime);
    1966              : 
    1967          364 :     if (exit_status != 0)
    1968              :     {
    1969            0 :         test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1970            0 :         log_child_failure(exit_status);
    1971              :     }
    1972              :     else
    1973              :     {
    1974          364 :         if (differ)
    1975              :         {
    1976            0 :             test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1977              :         }
    1978              :         else
    1979              :         {
    1980          364 :             test_status_ok(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1981              :         }
    1982              :     }
    1983          364 : }
    1984              : 
    1985              : /*
    1986              :  * Create the summary-output files (making them empty if already existing)
    1987              :  */
    1988              : static void
    1989          106 : open_result_files(void)
    1990              : {
    1991              :     char        file[MAXPGPATH];
    1992              :     FILE       *difffile;
    1993              : 
    1994              :     /* create outputdir directory if not present */
    1995          106 :     if (!directory_exists(outputdir))
    1996           10 :         make_directory(outputdir);
    1997              : 
    1998              :     /* create the log file (copy of running status output) */
    1999          106 :     snprintf(file, sizeof(file), "%s/regression.out", outputdir);
    2000          106 :     logfilename = pg_strdup(file);
    2001          106 :     logfile = fopen(logfilename, "w");
    2002          106 :     if (!logfile)
    2003            0 :         bail("could not open file \"%s\" for writing: %m", logfilename);
    2004              : 
    2005              :     /* create the diffs file as empty */
    2006          106 :     snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
    2007          106 :     difffilename = pg_strdup(file);
    2008          106 :     difffile = fopen(difffilename, "w");
    2009          106 :     if (!difffile)
    2010            0 :         bail("could not open file \"%s\" for writing: %m", difffilename);
    2011              : 
    2012              :     /* we don't keep the diffs file open continuously */
    2013          106 :     fclose(difffile);
    2014              : 
    2015              :     /* also create the results directory if not present */
    2016          106 :     snprintf(file, sizeof(file), "%s/results", outputdir);
    2017          106 :     if (!directory_exists(file))
    2018          105 :         make_directory(file);
    2019          106 : }
    2020              : 
    2021              : static void
    2022            3 : drop_database_if_exists(const char *dbname)
    2023              : {
    2024            3 :     StringInfo  buf = psql_start_command();
    2025              : 
    2026              :     /* Set warning level so we don't see chatter about nonexistent DB */
    2027            3 :     psql_add_command(buf, "SET client_min_messages = warning");
    2028            3 :     psql_add_command(buf, "DROP DATABASE IF EXISTS \"%s\"", dbname);
    2029            3 :     psql_end_command(buf, "postgres");
    2030            3 : }
    2031              : 
    2032              : static void
    2033          108 : create_database(const char *dbname)
    2034              : {
    2035          108 :     StringInfo  buf = psql_start_command();
    2036              :     _stringlist *sl;
    2037              : 
    2038              :     /*
    2039              :      * We use template0 so that any installation-local cruft in template1 will
    2040              :      * not mess up the tests.
    2041              :      */
    2042          108 :     if (encoding)
    2043            1 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
    2044            1 :                          (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
    2045              :     else
    2046          107 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
    2047          107 :                          (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
    2048          108 :     psql_add_command(buf,
    2049              :                      "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
    2050              :                      "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
    2051              :                      "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
    2052              :                      "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
    2053              :                      "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
    2054              :                      "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
    2055              :                      dbname, dbname, dbname, dbname, dbname, dbname);
    2056          108 :     psql_end_command(buf, "postgres");
    2057              : 
    2058              :     /*
    2059              :      * Install any requested extensions.  We use CREATE IF NOT EXISTS so that
    2060              :      * this will work whether or not the extension is preinstalled.
    2061              :      */
    2062          114 :     for (sl = loadextension; sl != NULL; sl = sl->next)
    2063            6 :         psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
    2064          108 : }
    2065              : 
    2066              : static void
    2067            0 : drop_role_if_exists(const char *rolename)
    2068              : {
    2069            0 :     StringInfo  buf = psql_start_command();
    2070              : 
    2071              :     /* Set warning level so we don't see chatter about nonexistent role */
    2072            0 :     psql_add_command(buf, "SET client_min_messages = warning");
    2073            0 :     psql_add_command(buf, "DROP ROLE IF EXISTS \"%s\"", rolename);
    2074            0 :     psql_end_command(buf, "postgres");
    2075            0 : }
    2076              : 
    2077              : static void
    2078            8 : create_role(const char *rolename, const _stringlist *granted_dbs)
    2079              : {
    2080            8 :     StringInfo  buf = psql_start_command();
    2081              : 
    2082            8 :     psql_add_command(buf, "CREATE ROLE \"%s\" WITH LOGIN", rolename);
    2083           20 :     for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
    2084              :     {
    2085           12 :         psql_add_command(buf, "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
    2086           12 :                          granted_dbs->str, rolename);
    2087              :     }
    2088            8 :     psql_end_command(buf, "postgres");
    2089            8 : }
    2090              : 
    2091              : static void
    2092            0 : help(void)
    2093              : {
    2094            0 :     printf(_("PostgreSQL regression test driver\n"));
    2095            0 :     printf(_("\n"));
    2096            0 :     printf(_("Usage:\n  %s [OPTION]... [EXTRA-TEST]...\n"), progname);
    2097            0 :     printf(_("\n"));
    2098            0 :     printf(_("Options:\n"));
    2099            0 :     printf(_("      --bindir=BINPATH          use BINPATH for programs that are run;\n"));
    2100            0 :     printf(_("                                if empty, use PATH from the environment\n"));
    2101            0 :     printf(_("      --config-auth=DATADIR     update authentication settings for DATADIR\n"));
    2102            0 :     printf(_("      --create-role=ROLE        create the specified role before testing\n"));
    2103            0 :     printf(_("      --dbname=DB               use database DB (default \"regression\")\n"));
    2104            0 :     printf(_("      --debug                   turn on debug mode in programs that are run\n"));
    2105            0 :     printf(_("      --dlpath=DIR              look for dynamic libraries in DIR\n"));
    2106            0 :     printf(_("      --encoding=ENCODING       use ENCODING as the encoding\n"));
    2107            0 :     printf(_("      --expecteddir=DIR         take expected files from DIR (default \".\")\n"));
    2108            0 :     printf(_("  -h, --help                    show this help, then exit\n"));
    2109            0 :     printf(_("      --inputdir=DIR            take input files from DIR (default \".\")\n"));
    2110            0 :     printf(_("      --launcher=CMD            use CMD as launcher of psql\n"));
    2111            0 :     printf(_("      --load-extension=EXT      load the named extension before running the\n"));
    2112            0 :     printf(_("                                tests; can appear multiple times\n"));
    2113            0 :     printf(_("      --max-connections=N       maximum number of concurrent connections\n"));
    2114            0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2115            0 :     printf(_("      --max-concurrent-tests=N  maximum number of concurrent tests in schedule\n"));
    2116            0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2117            0 :     printf(_("      --outputdir=DIR           place output files in DIR (default \".\")\n"));
    2118            0 :     printf(_("      --schedule=FILE           use test ordering schedule from FILE\n"));
    2119            0 :     printf(_("                                (can be used multiple times to concatenate)\n"));
    2120            0 :     printf(_("      --temp-instance=DIR       create a temporary instance in DIR\n"));
    2121            0 :     printf(_("      --use-existing            use an existing installation\n"));
    2122            0 :     printf(_("  -V, --version                 output version information, then exit\n"));
    2123            0 :     printf(_("\n"));
    2124            0 :     printf(_("Options for \"temp-instance\" mode:\n"));
    2125            0 :     printf(_("      --no-locale               use C locale\n"));
    2126            0 :     printf(_("      --port=PORT               start postmaster on PORT\n"));
    2127            0 :     printf(_("      --temp-config=FILE        append contents of FILE to temporary config\n"));
    2128            0 :     printf(_("\n"));
    2129            0 :     printf(_("Options for using an existing installation:\n"));
    2130            0 :     printf(_("      --host=HOST               use postmaster running on HOST\n"));
    2131            0 :     printf(_("      --port=PORT               use postmaster running at PORT\n"));
    2132            0 :     printf(_("      --user=USER               connect as USER\n"));
    2133            0 :     printf(_("\n"));
    2134            0 :     printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
    2135            0 :     printf(_("if the tests could not be run for some reason.\n"));
    2136            0 :     printf(_("\n"));
    2137            0 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    2138            0 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    2139            0 : }
    2140              : 
    2141              : int
    2142          464 : regression_main(int argc, char *argv[],
    2143              :                 init_function ifunc,
    2144              :                 test_start_function startfunc,
    2145              :                 postprocess_result_function postfunc)
    2146              : {
    2147              :     static struct option long_options[] = {
    2148              :         {"help", no_argument, NULL, 'h'},
    2149              :         {"version", no_argument, NULL, 'V'},
    2150              :         {"dbname", required_argument, NULL, 1},
    2151              :         {"debug", no_argument, NULL, 2},
    2152              :         {"inputdir", required_argument, NULL, 3},
    2153              :         {"max-connections", required_argument, NULL, 5},
    2154              :         {"encoding", required_argument, NULL, 6},
    2155              :         {"outputdir", required_argument, NULL, 7},
    2156              :         {"schedule", required_argument, NULL, 8},
    2157              :         {"temp-instance", required_argument, NULL, 9},
    2158              :         {"no-locale", no_argument, NULL, 10},
    2159              :         {"host", required_argument, NULL, 13},
    2160              :         {"port", required_argument, NULL, 14},
    2161              :         {"user", required_argument, NULL, 15},
    2162              :         {"bindir", required_argument, NULL, 16},
    2163              :         {"dlpath", required_argument, NULL, 17},
    2164              :         {"create-role", required_argument, NULL, 18},
    2165              :         {"temp-config", required_argument, NULL, 19},
    2166              :         {"use-existing", no_argument, NULL, 20},
    2167              :         {"launcher", required_argument, NULL, 21},
    2168              :         {"load-extension", required_argument, NULL, 22},
    2169              :         {"config-auth", required_argument, NULL, 24},
    2170              :         {"max-concurrent-tests", required_argument, NULL, 25},
    2171              :         {"expecteddir", required_argument, NULL, 26},
    2172              :         {NULL, 0, NULL, 0}
    2173              :     };
    2174              : 
    2175              :     bool        use_unix_sockets;
    2176              :     _stringlist *sl;
    2177              :     int         c;
    2178              :     int         i;
    2179              :     int         option_index;
    2180              :     char        buf[MAXPGPATH * 4];
    2181              : 
    2182          464 :     pg_logging_init(argv[0]);
    2183          464 :     progname = get_progname(argv[0]);
    2184          464 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
    2185              : 
    2186          464 :     pg_initialize_timing();
    2187              : 
    2188          464 :     get_restricted_token();
    2189              : 
    2190          464 :     atexit(stop_postmaster);
    2191              : 
    2192              : #if defined(WIN32)
    2193              : 
    2194              :     /*
    2195              :      * We don't use Unix-domain sockets on Windows by default (see comment at
    2196              :      * remove_temp() for a reason).  Override at your own risk.
    2197              :      */
    2198              :     use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
    2199              : #else
    2200          464 :     use_unix_sockets = true;
    2201              : #endif
    2202              : 
    2203          464 :     if (!use_unix_sockets)
    2204            0 :         hostname = "localhost";
    2205              : 
    2206              :     /*
    2207              :      * We call the initialization function here because that way we can set
    2208              :      * default parameters and let them be overwritten by the commandline.
    2209              :      */
    2210          464 :     ifunc(argc, argv);
    2211              : 
    2212          464 :     if (getenv("PG_REGRESS_DIFF_OPTS"))
    2213            0 :         pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
    2214              : 
    2215         1333 :     while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
    2216              :     {
    2217          869 :         switch (c)
    2218              :         {
    2219            0 :             case 'h':
    2220            0 :                 help();
    2221            0 :                 exit(0);
    2222            0 :             case 'V':
    2223            0 :                 puts("pg_regress (PostgreSQL) " PG_VERSION);
    2224            0 :                 exit(0);
    2225          101 :             case 1:
    2226              : 
    2227              :                 /*
    2228              :                  * If a default database was specified, we need to remove it
    2229              :                  * before we add the specified one.
    2230              :                  */
    2231          101 :                 free_stringlist(&dblist);
    2232          101 :                 split_to_stringlist(optarg, ",", &dblist);
    2233          101 :                 break;
    2234            0 :             case 2:
    2235            0 :                 debug = true;
    2236            0 :                 break;
    2237          104 :             case 3:
    2238          104 :                 inputdir = pg_strdup(optarg);
    2239          104 :                 break;
    2240            0 :             case 5:
    2241            0 :                 max_connections = atoi(optarg);
    2242            0 :                 break;
    2243            1 :             case 6:
    2244            1 :                 encoding = pg_strdup(optarg);
    2245            1 :                 break;
    2246           13 :             case 7:
    2247           13 :                 outputdir = pg_strdup(optarg);
    2248           13 :                 break;
    2249            7 :             case 8:
    2250            7 :                 add_stringlist_item(&schedulelist, optarg);
    2251            7 :                 break;
    2252          103 :             case 9:
    2253          103 :                 temp_instance = make_absolute_path(optarg);
    2254          103 :                 break;
    2255            2 :             case 10:
    2256            2 :                 nolocale = true;
    2257            2 :                 break;
    2258            4 :             case 13:
    2259            4 :                 hostname = pg_strdup(optarg);
    2260            4 :                 break;
    2261            3 :             case 14:
    2262            3 :                 port = atoi(optarg);
    2263            3 :                 port_specified_by_user = true;
    2264            3 :                 break;
    2265            3 :             case 15:
    2266            3 :                 user = pg_strdup(optarg);
    2267            3 :                 break;
    2268          106 :             case 16:
    2269              :                 /* "--bindir=" means to use PATH */
    2270          106 :                 if (strlen(optarg))
    2271            0 :                     bindir = pg_strdup(optarg);
    2272              :                 else
    2273          106 :                     bindir = NULL;
    2274          106 :                 break;
    2275            7 :             case 17:
    2276            7 :                 dlpath = pg_strdup(optarg);
    2277            7 :                 break;
    2278           34 :             case 18:
    2279           34 :                 split_to_stringlist(optarg, ",", &extraroles);
    2280           34 :                 break;
    2281           11 :             case 19:
    2282           11 :                 add_stringlist_item(&temp_configs, optarg);
    2283           11 :                 break;
    2284            0 :             case 20:
    2285            0 :                 use_existing = true;
    2286            0 :                 break;
    2287            0 :             case 21:
    2288            0 :                 launcher = pg_strdup(optarg);
    2289            0 :                 break;
    2290            6 :             case 22:
    2291            6 :                 add_stringlist_item(&loadextension, optarg);
    2292            6 :                 break;
    2293          358 :             case 24:
    2294          358 :                 config_auth_datadir = pg_strdup(optarg);
    2295          358 :                 break;
    2296            4 :             case 25:
    2297            4 :                 max_concurrent_tests = atoi(optarg);
    2298            4 :                 break;
    2299            2 :             case 26:
    2300            2 :                 expecteddir = pg_strdup(optarg);
    2301            2 :                 break;
    2302            0 :             default:
    2303              :                 /* getopt_long already emitted a complaint */
    2304            0 :                 pg_log_error_hint("Try \"%s --help\" for more information.",
    2305              :                                   progname);
    2306            0 :                 exit(2);
    2307              :         }
    2308              :     }
    2309              : 
    2310              :     /*
    2311              :      * if we still have arguments, they are extra tests to run
    2312              :      */
    2313          828 :     while (argc - optind >= 1)
    2314              :     {
    2315          364 :         add_stringlist_item(&extra_tests, argv[optind]);
    2316          364 :         optind++;
    2317              :     }
    2318              : 
    2319              :     /*
    2320              :      * We must have a database to run the tests in; either a default name, or
    2321              :      * one supplied by the --dbname switch.
    2322              :      */
    2323          464 :     if (!(dblist && dblist->str && dblist->str[0]))
    2324              :     {
    2325            0 :         bail("no database name was specified");
    2326              :     }
    2327              : 
    2328          464 :     if (config_auth_datadir)
    2329              :     {
    2330              : #ifdef ENABLE_SSPI
    2331              :         if (!use_unix_sockets)
    2332              :             config_sspi_auth(config_auth_datadir, user);
    2333              : #endif
    2334          358 :         exit(0);
    2335              :     }
    2336              : 
    2337          106 :     if (temp_instance && !port_specified_by_user)
    2338              : 
    2339              :         /*
    2340              :          * To reduce chances of interference with parallel installations, use
    2341              :          * a port number starting in the private range (49152-65535)
    2342              :          * calculated from the version number.  This aids non-Unix socket mode
    2343              :          * systems; elsewhere, the use of a private socket directory already
    2344              :          * prevents interference.
    2345              :          */
    2346          103 :         port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
    2347              : 
    2348          106 :     inputdir = make_absolute_path(inputdir);
    2349          106 :     outputdir = make_absolute_path(outputdir);
    2350          106 :     expecteddir = make_absolute_path(expecteddir);
    2351          106 :     dlpath = make_absolute_path(dlpath);
    2352              : 
    2353              :     /*
    2354              :      * Initialization
    2355              :      */
    2356          106 :     open_result_files();
    2357              : 
    2358          106 :     initialize_environment();
    2359              : 
    2360              : #if defined(HAVE_GETRLIMIT)
    2361          106 :     unlimit_core_size();
    2362              : #endif
    2363              : 
    2364          106 :     if (temp_instance)
    2365              :     {
    2366              :         StringInfoData cmd;
    2367              :         FILE       *pg_conf;
    2368              :         const char *env_wait;
    2369              :         int         wait_seconds;
    2370              :         const char *initdb_template_dir;
    2371              :         const char *keywords[4];
    2372              :         const char *values[4];
    2373              :         PGPing      rv;
    2374              :         const char *initdb_extra_opts_env;
    2375              : 
    2376              :         /*
    2377              :          * Prepare the temp instance
    2378              :          */
    2379              : 
    2380          103 :         if (directory_exists(temp_instance))
    2381              :         {
    2382            0 :             if (!rmtree(temp_instance, true))
    2383              :             {
    2384            0 :                 bail("could not remove temp instance \"%s\"", temp_instance);
    2385              :             }
    2386              :         }
    2387              : 
    2388              :         /* make the temp instance top directory */
    2389          103 :         make_directory(temp_instance);
    2390              : 
    2391              :         /* and a directory for log files */
    2392          103 :         snprintf(buf, sizeof(buf), "%s/log", outputdir);
    2393          103 :         if (!directory_exists(buf))
    2394          102 :             make_directory(buf);
    2395              : 
    2396          103 :         initdb_extra_opts_env = getenv("PG_TEST_INITDB_EXTRA_OPTS");
    2397              : 
    2398          103 :         initStringInfo(&cmd);
    2399              : 
    2400              :         /*
    2401              :          * Create data directory.
    2402              :          *
    2403              :          * If available, use a previously initdb'd cluster as a template by
    2404              :          * copying it. For a lot of tests, that's substantially cheaper.
    2405              :          *
    2406              :          * There's very similar code in Cluster.pm, but we can't easily de
    2407              :          * duplicate it until we require perl at build time.
    2408              :          */
    2409          103 :         initdb_template_dir = getenv("INITDB_TEMPLATE");
    2410          103 :         if (initdb_template_dir == NULL || nolocale || debug || initdb_extra_opts_env)
    2411              :         {
    2412            2 :             note("initializing database system by running initdb");
    2413              : 
    2414            4 :             appendStringInfo(&cmd,
    2415              :                              "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync",
    2416            2 :                              bindir ? bindir : "",
    2417            2 :                              bindir ? "/" : "",
    2418              :                              temp_instance);
    2419            2 :             if (debug)
    2420            0 :                 appendStringInfoString(&cmd, " --debug");
    2421            2 :             if (nolocale)
    2422            2 :                 appendStringInfoString(&cmd, " --no-locale");
    2423            2 :             if (initdb_extra_opts_env)
    2424            0 :                 appendStringInfo(&cmd, " %s", initdb_extra_opts_env);
    2425            2 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2426            2 :             fflush(NULL);
    2427            2 :             if (system(cmd.data))
    2428              :             {
    2429            0 :                 bail("initdb failed\n"
    2430              :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2431              :                      "# Command was: %s",
    2432              :                      outputdir, cmd.data);
    2433              :             }
    2434              :         }
    2435              :         else
    2436              :         {
    2437              : #ifndef WIN32
    2438          101 :             const char *copycmd = "cp -RPp \"%s\" \"%s/data\"";
    2439          101 :             int         expected_exitcode = 0;
    2440              : #else
    2441              :             const char *copycmd = "robocopy /E /NJS /NJH /NFL /NDL /NP \"%s\" \"%s/data\"";
    2442              :             int         expected_exitcode = 1;  /* 1 denotes files were copied */
    2443              : #endif
    2444              : 
    2445          101 :             note("initializing database system by copying initdb template");
    2446              : 
    2447          101 :             appendStringInfo(&cmd,
    2448              :                              copycmd,
    2449              :                              initdb_template_dir,
    2450              :                              temp_instance);
    2451          101 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2452          101 :             fflush(NULL);
    2453          101 :             if (system(cmd.data) != expected_exitcode)
    2454              :             {
    2455            0 :                 bail("copying of initdb template failed\n"
    2456              :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2457              :                      "# Command was: %s",
    2458              :                      outputdir, cmd.data);
    2459              :             }
    2460              :         }
    2461              : 
    2462          103 :         pfree(cmd.data);
    2463              : 
    2464              :         /*
    2465              :          * Adjust the default postgresql.conf for regression testing. The user
    2466              :          * can specify a file to be appended; in any case we expand logging
    2467              :          * and set max_prepared_transactions to enable testing of prepared
    2468              :          * xacts.  (Note: to reduce the probability of unexpected shmmax
    2469              :          * failures, don't set max_prepared_transactions any higher than
    2470              :          * actually needed by the prepared_xacts regression test.)
    2471              :          */
    2472          103 :         snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
    2473          103 :         pg_conf = fopen(buf, "a");
    2474          103 :         if (pg_conf == NULL)
    2475            0 :             bail("could not open \"%s\" for adding extra config: %m", buf);
    2476              : 
    2477          103 :         fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
    2478          103 :         fputs("log_autovacuum_min_duration = 0\n", pg_conf);
    2479          103 :         fputs("log_autoanalyze_min_duration = 0\n", pg_conf);
    2480          103 :         fputs("log_checkpoints = on\n", pg_conf);
    2481          103 :         fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
    2482          103 :         fputs("log_lock_waits = on\n", pg_conf);
    2483          103 :         fputs("log_temp_files = 128kB\n", pg_conf);
    2484          103 :         fputs("max_prepared_transactions = 2\n", pg_conf);
    2485              : 
    2486          114 :         for (sl = temp_configs; sl != NULL; sl = sl->next)
    2487              :         {
    2488           11 :             char       *temp_config = sl->str;
    2489              :             FILE       *extra_conf;
    2490              :             char        line_buf[1024];
    2491              : 
    2492           11 :             extra_conf = fopen(temp_config, "r");
    2493           11 :             if (extra_conf == NULL)
    2494              :             {
    2495            0 :                 bail("could not open \"%s\" to read extra config: %m",
    2496              :                      temp_config);
    2497              :             }
    2498           33 :             while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
    2499           22 :                 fputs(line_buf, pg_conf);
    2500           11 :             fclose(extra_conf);
    2501              :         }
    2502              : 
    2503          103 :         fclose(pg_conf);
    2504              : 
    2505              : #ifdef ENABLE_SSPI
    2506              :         if (!use_unix_sockets)
    2507              :         {
    2508              :             /*
    2509              :              * Since we successfully used the same buffer for the much-longer
    2510              :              * "initdb" command, this can't truncate.
    2511              :              */
    2512              :             snprintf(buf, sizeof(buf), "%s/data", temp_instance);
    2513              :             config_sspi_auth(buf, NULL);
    2514              :         }
    2515              : #endif
    2516              : 
    2517              :         /*
    2518              :          * Prepare the connection params for checking the state of the server
    2519              :          * before starting the tests.
    2520              :          */
    2521          103 :         sprintf(portstr, "%d", port);
    2522          103 :         keywords[0] = "dbname";
    2523          103 :         values[0] = "postgres";
    2524          103 :         keywords[1] = "port";
    2525          103 :         values[1] = portstr;
    2526          103 :         keywords[2] = "host";
    2527          103 :         values[2] = hostname ? hostname : sockdir;
    2528          103 :         keywords[3] = NULL;
    2529          103 :         values[3] = NULL;
    2530              : 
    2531              :         /*
    2532              :          * Check if there is a postmaster running already.
    2533              :          */
    2534          103 :         for (i = 0; i < 16; i++)
    2535              :         {
    2536          103 :             rv = PQpingParams(keywords, values, 1);
    2537              : 
    2538          103 :             if (rv == PQPING_OK)
    2539              :             {
    2540            0 :                 if (port_specified_by_user || i == 15)
    2541              :                 {
    2542            0 :                     note("port %d apparently in use", port);
    2543            0 :                     if (!port_specified_by_user)
    2544            0 :                         note("could not determine an available port");
    2545            0 :                     bail("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.");
    2546              :                 }
    2547              : 
    2548            0 :                 note("port %d apparently in use, trying %d", port, port + 1);
    2549            0 :                 port++;
    2550            0 :                 sprintf(portstr, "%d", port);
    2551            0 :                 setenv("PGPORT", portstr, 1);
    2552              :             }
    2553              :             else
    2554          103 :                 break;
    2555              :         }
    2556              : 
    2557              :         /*
    2558              :          * Start the temp postmaster
    2559              :          */
    2560          515 :         snprintf(buf, sizeof(buf),
    2561              :                  "\"%s%spostgres\" -D \"%s/data\" -F%s "
    2562              :                  "-c \"listen_addresses=%s\" -k \"%s\" "
    2563              :                  "> \"%s/log/postmaster.log\" 2>&1",
    2564          103 :                  bindir ? bindir : "",
    2565          103 :                  bindir ? "/" : "",
    2566          103 :                  temp_instance, debug ? " -d 5" : "",
    2567          206 :                  hostname ? hostname : "", sockdir ? sockdir : "",
    2568              :                  outputdir);
    2569          103 :         postmaster_pid = spawn_process(buf);
    2570          103 :         if (postmaster_pid == INVALID_PID)
    2571            0 :             bail("could not spawn postmaster: %m");
    2572              : 
    2573              :         /*
    2574              :          * Wait till postmaster is able to accept connections; normally takes
    2575              :          * only a fraction of a second or so, but Cygwin is reportedly *much*
    2576              :          * slower, and test builds using Valgrind or similar tools might be
    2577              :          * too.  Hence, allow the default timeout of 60 seconds to be
    2578              :          * overridden from the PGCTLTIMEOUT environment variable.
    2579              :          */
    2580          103 :         env_wait = getenv("PGCTLTIMEOUT");
    2581          103 :         if (env_wait != NULL)
    2582              :         {
    2583            0 :             wait_seconds = atoi(env_wait);
    2584            0 :             if (wait_seconds <= 0)
    2585            0 :                 wait_seconds = 60;
    2586              :         }
    2587              :         else
    2588          103 :             wait_seconds = 60;
    2589              : 
    2590          403 :         for (i = 0; i < wait_seconds * WAIT_TICKS_PER_SECOND; i++)
    2591              :         {
    2592              :             /*
    2593              :              * It's fairly unlikely that the server is responding immediately
    2594              :              * so we start with sleeping before checking instead of the other
    2595              :              * way around.
    2596              :              */
    2597          403 :             pg_usleep(1000000L / WAIT_TICKS_PER_SECOND);
    2598              : 
    2599          403 :             rv = PQpingParams(keywords, values, 1);
    2600              : 
    2601              :             /* Done if the server is running and accepts connections */
    2602          403 :             if (rv == PQPING_OK)
    2603          103 :                 break;
    2604              : 
    2605          300 :             if (rv == PQPING_NO_ATTEMPT)
    2606            0 :                 bail("attempting to connect to postmaster failed");
    2607              : 
    2608              :             /*
    2609              :              * Fail immediately if postmaster has exited
    2610              :              */
    2611              : #ifndef WIN32
    2612          300 :             if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
    2613              : #else
    2614              :             if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
    2615              : #endif
    2616              :             {
    2617            0 :                 bail("postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
    2618              :                      outputdir);
    2619              :             }
    2620              :         }
    2621          103 :         if (i >= wait_seconds * WAIT_TICKS_PER_SECOND)
    2622              :         {
    2623            0 :             diag("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
    2624              :                  wait_seconds, outputdir);
    2625              : 
    2626              :             /*
    2627              :              * If we get here, the postmaster is probably wedged somewhere in
    2628              :              * startup.  Try to kill it ungracefully rather than leaving a
    2629              :              * stuck postmaster that might interfere with subsequent test
    2630              :              * attempts.
    2631              :              */
    2632              : #ifndef WIN32
    2633            0 :             if (kill(postmaster_pid, SIGKILL) != 0 && errno != ESRCH)
    2634            0 :                 bail("could not kill failed postmaster: %m");
    2635              : #else
    2636              :             if (TerminateProcess(postmaster_pid, 255) == 0)
    2637              :                 bail("could not kill failed postmaster: error code %lu",
    2638              :                      GetLastError());
    2639              : #endif
    2640            0 :             bail("postmaster failed");
    2641              :         }
    2642              : 
    2643          103 :         postmaster_running = true;
    2644              : 
    2645              : #ifdef _WIN64
    2646              : /* need a series of two casts to convert HANDLE without compiler warning */
    2647              : #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
    2648              : #else
    2649              : #define ULONGPID(x) (unsigned long) (x)
    2650              : #endif
    2651          103 :         note("using temp instance on port %d with PID %lu",
    2652              :              port, ULONGPID(postmaster_pid));
    2653              :     }
    2654              :     else
    2655              :     {
    2656              :         /*
    2657              :          * Using an existing installation, so may need to get rid of
    2658              :          * pre-existing database(s) and role(s)
    2659              :          */
    2660            3 :         if (!use_existing)
    2661              :         {
    2662            6 :             for (sl = dblist; sl; sl = sl->next)
    2663            3 :                 drop_database_if_exists(sl->str);
    2664            3 :             for (sl = extraroles; sl; sl = sl->next)
    2665            0 :                 drop_role_if_exists(sl->str);
    2666              :         }
    2667              :     }
    2668              : 
    2669              :     /*
    2670              :      * Create the test database(s) and role(s)
    2671              :      */
    2672          106 :     if (!use_existing)
    2673              :     {
    2674          214 :         for (sl = dblist; sl; sl = sl->next)
    2675          108 :             create_database(sl->str);
    2676          114 :         for (sl = extraroles; sl; sl = sl->next)
    2677            8 :             create_role(sl->str, dblist);
    2678              :     }
    2679              : 
    2680              :     /*
    2681              :      * Ready to run the tests
    2682              :      */
    2683          113 :     for (sl = schedulelist; sl != NULL; sl = sl->next)
    2684              :     {
    2685            7 :         run_schedule(sl->str, startfunc, postfunc);
    2686              :     }
    2687              : 
    2688          470 :     for (sl = extra_tests; sl != NULL; sl = sl->next)
    2689              :     {
    2690          364 :         run_single_test(sl->str, startfunc, postfunc);
    2691              :     }
    2692              : 
    2693              :     /*
    2694              :      * Shut down temp installation's postmaster
    2695              :      */
    2696          106 :     if (temp_instance)
    2697              :     {
    2698          103 :         stop_postmaster();
    2699              :     }
    2700              : 
    2701              :     /*
    2702              :      * If there were no errors, remove the temp instance immediately to
    2703              :      * conserve disk space.  (If there were errors, we leave the instance in
    2704              :      * place for possible manual investigation.)
    2705              :      */
    2706          106 :     if (temp_instance && fail_count == 0)
    2707              :     {
    2708          103 :         if (!rmtree(temp_instance, true))
    2709            0 :             diag("could not remove temp instance \"%s\"",
    2710              :                  temp_instance);
    2711              :     }
    2712              : 
    2713              :     /*
    2714              :      * Emit a TAP compliant Plan
    2715              :      */
    2716          106 :     plan(fail_count + success_count);
    2717              : 
    2718              :     /*
    2719              :      * Emit nice-looking summary message
    2720              :      */
    2721          106 :     if (fail_count == 0)
    2722          106 :         note("All %d tests passed.", success_count);
    2723              :     else
    2724            0 :         diag("%d of %d tests failed.", fail_count, success_count + fail_count);
    2725              : 
    2726          106 :     if (file_size(difffilename) > 0)
    2727              :     {
    2728            0 :         diag("The differences that caused some tests to fail can be viewed in the file \"%s\".",
    2729              :              difffilename);
    2730            0 :         diag("A copy of the test summary that you see above is saved in the file \"%s\".",
    2731              :              logfilename);
    2732              :     }
    2733              :     else
    2734              :     {
    2735          106 :         unlink(difffilename);
    2736          106 :         unlink(logfilename);
    2737              :     }
    2738              : 
    2739          106 :     fclose(logfile);
    2740          106 :     logfile = NULL;
    2741              : 
    2742          106 :     if (fail_count != 0)
    2743            0 :         exit(1);
    2744              : 
    2745          106 :     return 0;
    2746              : }
        

Generated by: LCOV version 2.0-1