PostgreSQL Source Code  git master
pg_regress.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include "common/logging.h"
#include "common/restricted_token.h"
#include "common/string.h"
#include "common/username.h"
#include "getopt_long.h"
#include "lib/stringinfo.h"
#include "libpq/pqcomm.h"
#include "pg_config_paths.h"
#include "pg_regress.h"
#include "portability/instr_time.h"
Include dependency graph for pg_regress.c:

Go to the source code of this file.

Data Structures

struct  _resultmap
 

Macros

#define MAX_PARALLEL_TESTS   100
 
#define ULONGPID(x)   (unsigned long) (x)
 

Typedefs

typedef struct _resultmap _resultmap
 

Functions

static bool directory_exists (const char *dir)
 
static void make_directory (const char *dir)
 
static void header (const char *fmt,...) pg_attribute_printf(1
 
static void static void status (const char *fmt,...) pg_attribute_printf(1
 
static void static void static void psql_command (const char *database, const char *query,...) pg_attribute_printf(2
 
static void static void static void void add_stringlist_item (_stringlist **listhead, const char *str)
 
static void free_stringlist (_stringlist **listhead)
 
static void split_to_stringlist (const char *s, const char *delim, _stringlist **listhead)
 
static void status_end (void)
 
static void stop_postmaster (void)
 
static bool string_matches_pattern (const char *str, const char *pattern)
 
void replace_string (StringInfo string, const char *replace, const char *replacement)
 
static void convert_sourcefiles_in (const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
 
static void convert_sourcefiles (void)
 
static void prepare_testtablespace_dir (void)
 
static void load_resultmap (void)
 
static const char * get_expectfile (const char *testname, const char *file)
 
static void initialize_environment (void)
 
PID_TYPE spawn_process (const char *cmdline)
 
static long file_size (const char *file)
 
static int file_line_count (const char *file)
 
bool file_exists (const char *file)
 
static char * get_alternative_expectfile (const char *expectfile, int i)
 
static int run_diff (const char *cmd, const char *filename)
 
static bool results_differ (const char *testname, const char *resultsfile, const char *default_expectfile)
 
static void wait_for_tests (PID_TYPE *pids, int *statuses, instr_time *stoptimes, char **names, int num_tests)
 
static void log_child_failure (int exitstatus)
 
static void run_schedule (const char *schedule, test_start_function startfunc, postprocess_result_function postfunc)
 
static void run_single_test (const char *test, test_start_function startfunc, postprocess_result_function postfunc)
 
static void open_result_files (void)
 
static void drop_database_if_exists (const char *dbname)
 
static void create_database (const char *dbname)
 
static void drop_role_if_exists (const char *rolename)
 
static void create_role (const char *rolename, const _stringlist *granted_dbs)
 
static void help (void)
 
int regression_main (int argc, char *argv[], init_function ifunc, test_start_function startfunc, postprocess_result_function postfunc)
 

Variables

char * host_platform = HOST_TUPLE
 
static char * shellprog = SHELLPROG
 
const char * basic_diff_opts = ""
 
const char * pretty_diff_opts = "-U3"
 
_stringlistdblist = NULL
 
bool debug = false
 
char * inputdir = "."
 
char * outputdir = "."
 
char * bindir = PGBINDIR
 
char * launcher = NULL
 
static _stringlistloadextension = NULL
 
static int max_connections = 0
 
static int max_concurrent_tests = 0
 
static char * encoding = NULL
 
static _stringlistschedulelist = NULL
 
static _stringlistextra_tests = NULL
 
static char * temp_instance = NULL
 
static _stringlisttemp_configs = NULL
 
static bool nolocale = false
 
static bool use_existing = false
 
static char * hostname = NULL
 
static int port = -1
 
static bool port_specified_by_user = false
 
static char * dlpath = PKGLIBDIR
 
static char * user = NULL
 
static _stringlistextraroles = NULL
 
static char * config_auth_datadir = NULL
 
static const char * progname
 
static char * logfilename
 
static FILE * logfile
 
static char * difffilename
 
static const char * sockdir
 
static _resultmapresultmap = NULL
 
static PID_TYPE postmaster_pid = INVALID_PID
 
static bool postmaster_running = false
 
static int success_count = 0
 
static int fail_count = 0
 
static int fail_ignore_count = 0
 

Macro Definition Documentation

◆ MAX_PARALLEL_TESTS

#define MAX_PARALLEL_TESTS   100

Referenced by run_schedule().

◆ ULONGPID

#define ULONGPID (   x)    (unsigned long) (x)

Referenced by regression_main().

Typedef Documentation

◆ _resultmap

typedef struct _resultmap _resultmap

Function Documentation

◆ add_stringlist_item()

static void static void static void void add_stringlist_item ( _stringlist **  listhead,
const char *  str 
)

Definition at line 157 of file pg_regress.c.

References _stringlist::next, pg_malloc(), pg_strdup(), and _stringlist::str.

Referenced by ecpg_start_test(), isolation_init(), isolation_start_test(), psql_init(), psql_start_test(), regression_main(), run_schedule(), and split_to_stringlist().

158 {
159  _stringlist *newentry = pg_malloc(sizeof(_stringlist));
160  _stringlist *oldentry;
161 
162  newentry->str = pg_strdup(str);
163  newentry->next = NULL;
164  if (*listhead == NULL)
165  *listhead = newentry;
166  else
167  {
168  for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
169  /* skip */ ;
170  oldentry->next = newentry;
171  }
172 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * str
Definition: pg_regress.h:26
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
struct _stringlist * next
Definition: pg_regress.h:27

◆ convert_sourcefiles()

static void convert_sourcefiles ( void  )
static

Definition at line 582 of file pg_regress.c.

References convert_sourcefiles_in(), and outputdir.

Referenced by initialize_environment().

583 {
584  convert_sourcefiles_in("input", outputdir, "sql", "sql");
585  convert_sourcefiles_in("output", outputdir, "expected", "out");
586 }
static void convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
Definition: pg_regress.c:476
char * outputdir
Definition: pg_regress.c:78

◆ convert_sourcefiles_in()

static void convert_sourcefiles_in ( const char *  source_subdir,
const char *  dest_dir,
const char *  dest_subdir,
const char *  suffix 
)
static

Definition at line 476 of file pg_regress.c.

References _, StringInfoData::data, directory_exists(), dlpath, fprintf, infile(), initStringInfo(), inputdir, make_directory(), MAXPGPATH, name, outfile, outputdir, pfree(), pg_get_line_buf(), pgfnames(), pgfnames_cleanup(), progname, replace_string(), snprintf, and strerror.

Referenced by convert_sourcefiles().

477 {
478  char testtablespace[MAXPGPATH];
479  char indir[MAXPGPATH];
480  char outdir_sub[MAXPGPATH];
481  char **name;
482  char **names;
483  int count = 0;
484 
485  snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
486 
487  /* Check that indir actually exists and is a directory */
488  if (!directory_exists(indir))
489  {
490  /*
491  * No warning, to avoid noise in tests that do not have these
492  * directories; for example, ecpg, contrib and src/pl.
493  */
494  return;
495  }
496 
497  names = pgfnames(indir);
498  if (!names)
499  /* Error logged in pgfnames */
500  exit(2);
501 
502  /* Create the "dest" subdirectory if not present */
503  snprintf(outdir_sub, MAXPGPATH, "%s/%s", dest_dir, dest_subdir);
504  if (!directory_exists(outdir_sub))
505  make_directory(outdir_sub);
506 
507  /* We might need to replace @testtablespace@ */
508  snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
509 
510  /* finally loop on each file and do the replacement */
511  for (name = names; *name; name++)
512  {
513  char srcfile[MAXPGPATH];
514  char destfile[MAXPGPATH];
515  char prefix[MAXPGPATH];
516  FILE *infile,
517  *outfile;
518  StringInfoData line;
519 
520  /* reject filenames not finishing in ".source" */
521  if (strlen(*name) < 8)
522  continue;
523  if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
524  continue;
525 
526  count++;
527 
528  /* build the full actual paths to open */
529  snprintf(prefix, strlen(*name) - 6, "%s", *name);
530  snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
531  snprintf(destfile, MAXPGPATH, "%s/%s/%s.%s", dest_dir, dest_subdir,
532  prefix, suffix);
533 
534  infile = fopen(srcfile, "r");
535  if (!infile)
536  {
537  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
538  progname, srcfile, strerror(errno));
539  exit(2);
540  }
541  outfile = fopen(destfile, "w");
542  if (!outfile)
543  {
544  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
545  progname, destfile, strerror(errno));
546  exit(2);
547  }
548 
549  initStringInfo(&line);
550 
551  while (pg_get_line_buf(infile, &line))
552  {
553  replace_string(&line, "@abs_srcdir@", inputdir);
554  replace_string(&line, "@abs_builddir@", outputdir);
555  replace_string(&line, "@testtablespace@", testtablespace);
556  replace_string(&line, "@libdir@", dlpath);
557  replace_string(&line, "@DLSUFFIX@", DLSUFFIX);
558  fputs(line.data, outfile);
559  }
560 
561  pfree(line.data);
562  fclose(infile);
563  fclose(outfile);
564  }
565 
566  /*
567  * If we didn't process any files, complain because it probably means
568  * somebody neglected to pass the needed --inputdir argument.
569  */
570  if (count <= 0)
571  {
572  fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
573  progname, indir);
574  exit(2);
575  }
576 
577  pgfnames_cleanup(names);
578 }
bool pg_get_line_buf(FILE *stream, StringInfo buf)
Definition: pg_get_line.c:88
static bool directory_exists(const char *dir)
Definition: pg_regress.c:1311
char ** pgfnames(const char *path)
Definition: pgfnames.c:37
static const char * progname
Definition: pg_regress.c:100
static void make_directory(const char *dir)
Definition: pg_regress.c:1324
#define fprintf
Definition: port.h:220
void pfree(void *pointer)
Definition: mcxt.c:1169
#define MAXPGPATH
static char * dlpath
Definition: pg_regress.c:94
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char * outputdir
Definition: pg_regress.c:78
char * inputdir
Definition: pg_regress.c:77
static void infile(const char *filename)
Definition: zic.c:1241
void pgfnames_cleanup(char **filenames)
Definition: pgfnames.c:86
#define strerror
Definition: port.h:229
const char * name
Definition: encode.c:515
void replace_string(StringInfo string, const char *replace, const char *replacement)
Definition: pg_regress.c:447
static char * outfile
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ create_database()

static void create_database ( const char *  dbname)
static

Definition at line 2020 of file pg_regress.c.

References _, encoding, header(), _stringlist::next, nolocale, psql_command(), and _stringlist::str.

Referenced by regression_main().

2021 {
2022  _stringlist *sl;
2023 
2024  /*
2025  * We use template0 so that any installation-local cruft in template1 will
2026  * not mess up the tests.
2027  */
2028  header(_("creating database \"%s\""), dbname);
2029  if (encoding)
2030  psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
2031  (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
2032  else
2033  psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
2034  (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
2036  "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
2037  "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
2038  "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
2039  "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
2040  "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
2041  "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
2043 
2044  /*
2045  * Install any requested extensions. We use CREATE IF NOT EXISTS so that
2046  * this will work whether or not the extension is preinstalled.
2047  */
2048  for (sl = loadextension; sl != NULL; sl = sl->next)
2049  {
2050  header(_("installing %s"), sl->str);
2051  psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
2052  }
2053 }
char * str
Definition: pg_regress.h:26
static char * encoding
Definition: pg_regress.c:84
static _stringlist * loadextension
Definition: pg_regress.c:81
static void static void static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2
Definition: pg_regress.c:1144
char * dbname
Definition: streamutil.c:51
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
struct _stringlist * next
Definition: pg_regress.h:27
static bool nolocale
Definition: pg_regress.c:89
#define _(x)
Definition: elog.c:89

◆ create_role()

static void create_role ( const char *  rolename,
const _stringlist granted_dbs 
)
static

Definition at line 2063 of file pg_regress.c.

References _, header(), _stringlist::next, psql_command(), and _stringlist::str.

Referenced by regression_main().

2064 {
2065  header(_("creating role \"%s\""), rolename);
2066  psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
2067  for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
2068  {
2069  psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
2070  granted_dbs->str, rolename);
2071  }
2072 }
char * str
Definition: pg_regress.h:26
static void static void static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2
Definition: pg_regress.c:1144
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
struct _stringlist * next
Definition: pg_regress.h:27
#define _(x)
Definition: elog.c:89

◆ directory_exists()

static bool directory_exists ( const char *  dir)
static

Definition at line 1311 of file pg_regress.c.

References S_ISDIR, stat::st_mode, and stat.

Referenced by convert_sourcefiles_in(), open_result_files(), prepare_testtablespace_dir(), and regression_main().

1312 {
1313  struct stat st;
1314 
1315  if (stat(dir, &st) != 0)
1316  return false;
1317  if (S_ISDIR(st.st_mode))
1318  return true;
1319  return false;
1320 }
#define S_ISDIR(m)
Definition: win32_port.h:316
#define stat
Definition: win32_port.h:275

◆ drop_database_if_exists()

static void drop_database_if_exists ( const char *  dbname)
static

Definition at line 2013 of file pg_regress.c.

References _, header(), and psql_command().

Referenced by regression_main().

2014 {
2015  header(_("dropping database \"%s\""), dbname);
2016  psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
2017 }
static void static void static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2
Definition: pg_regress.c:1144
char * dbname
Definition: streamutil.c:51
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
#define _(x)
Definition: elog.c:89

◆ drop_role_if_exists()

static void drop_role_if_exists ( const char *  rolename)
static

Definition at line 2056 of file pg_regress.c.

References _, header(), and psql_command().

Referenced by regression_main().

2057 {
2058  header(_("dropping role \"%s\""), rolename);
2059  psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
2060 }
static void static void static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2
Definition: pg_regress.c:1144
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
#define _(x)
Definition: elog.c:89

◆ file_exists()

bool file_exists ( const char *  file)

Definition at line 1300 of file pg_regress.c.

Referenced by results_differ().

1301 {
1302  FILE *f = fopen(file, "r");
1303 
1304  if (!f)
1305  return false;
1306  fclose(f);
1307  return true;
1308 }

◆ file_line_count()

static int file_line_count ( const char *  file)
static

Definition at line 1278 of file pg_regress.c.

References _, fprintf, progname, and strerror.

Referenced by results_differ().

1279 {
1280  int c;
1281  int l = 0;
1282  FILE *f = fopen(file, "r");
1283 
1284  if (!f)
1285  {
1286  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1287  progname, file, strerror(errno));
1288  return -1;
1289  }
1290  while ((c = fgetc(f)) != EOF)
1291  {
1292  if (c == '\n')
1293  l++;
1294  }
1295  fclose(f);
1296  return l;
1297 }
static const char * progname
Definition: pg_regress.c:100
#define fprintf
Definition: port.h:220
char * c
#define strerror
Definition: port.h:229
#define _(x)
Definition: elog.c:89

◆ file_size()

static long file_size ( const char *  file)
static

Definition at line 1257 of file pg_regress.c.

References _, fprintf, progname, and strerror.

Referenced by regression_main(), and run_diff().

1258 {
1259  long r;
1260  FILE *f = fopen(file, "r");
1261 
1262  if (!f)
1263  {
1264  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1265  progname, file, strerror(errno));
1266  return -1;
1267  }
1268  fseek(f, 0, SEEK_END);
1269  r = ftell(f);
1270  fclose(f);
1271  return r;
1272 }
static const char * progname
Definition: pg_regress.c:100
#define fprintf
Definition: port.h:220
#define strerror
Definition: port.h:229
#define _(x)
Definition: elog.c:89

◆ free_stringlist()

static void free_stringlist ( _stringlist **  listhead)
static

Definition at line 178 of file pg_regress.c.

References free.

Referenced by regression_main(), and run_schedule().

179 {
180  if (listhead == NULL || *listhead == NULL)
181  return;
182  if ((*listhead)->next != NULL)
183  free_stringlist(&((*listhead)->next));
184  free((*listhead)->str);
185  free(*listhead);
186  *listhead = NULL;
187 }
static void free_stringlist(_stringlist **listhead)
Definition: pg_regress.c:178
#define free(a)
Definition: header.h:65

◆ get_alternative_expectfile()

static char* get_alternative_expectfile ( const char *  expectfile,
int  i 
)
static

Definition at line 1338 of file pg_regress.c.

References free, malloc, and snprintf.

Referenced by results_differ().

1339 {
1340  char *last_dot;
1341  int ssize = strlen(expectfile) + 2 + 1;
1342  char *tmp;
1343  char *s;
1344 
1345  if (!(tmp = (char *) malloc(ssize)))
1346  return NULL;
1347 
1348  if (!(s = (char *) malloc(ssize)))
1349  {
1350  free(tmp);
1351  return NULL;
1352  }
1353 
1354  strcpy(tmp, expectfile);
1355  last_dot = strrchr(tmp, '.');
1356  if (!last_dot)
1357  {
1358  free(tmp);
1359  free(s);
1360  return NULL;
1361  }
1362  *last_dot = '\0';
1363  snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1364  free(tmp);
1365  return s;
1366 }
#define malloc(a)
Definition: header.h:50
#define free(a)
Definition: header.h:65
int i
#define snprintf
Definition: port.h:216

◆ get_expectfile()

static const char* get_expectfile ( const char *  testname,
const char *  file 
)
static

Definition at line 710 of file pg_regress.c.

References _resultmap::next, _resultmap::resultfile, _resultmap::test, and _resultmap::type.

Referenced by results_differ().

711 {
712  char *file_type;
713  _resultmap *rm;
714 
715  /*
716  * Determine the file type from the file name. This is just what is
717  * following the last dot in the file name.
718  */
719  if (!file || !(file_type = strrchr(file, '.')))
720  return NULL;
721 
722  file_type++;
723 
724  for (rm = resultmap; rm != NULL; rm = rm->next)
725  {
726  if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
727  {
728  return rm->resultfile;
729  }
730  }
731 
732  return NULL;
733 }
struct _resultmap * next
Definition: pg_regress.c:49
static _resultmap * resultmap
Definition: pg_regress.c:111
char * test
Definition: pg_regress.c:46
char * type
Definition: pg_regress.c:47
char * resultfile
Definition: pg_regress.c:48

◆ header()

static void header ( const char *  fmt,
  ... 
)
static

◆ help()

static void help ( void  )
static

Definition at line 2075 of file pg_regress.c.

References _, printf, and progname.

Referenced by regression_main().

2076 {
2077  printf(_("PostgreSQL regression test driver\n"));
2078  printf(_("\n"));
2079  printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
2080  printf(_("\n"));
2081  printf(_("Options:\n"));
2082  printf(_(" --bindir=BINPATH use BINPATH for programs that are run;\n"));
2083  printf(_(" if empty, use PATH from the environment\n"));
2084  printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
2085  printf(_(" --create-role=ROLE create the specified role before testing\n"));
2086  printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
2087  printf(_(" --debug turn on debug mode in programs that are run\n"));
2088  printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
2089  printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
2090  printf(_(" -h, --help show this help, then exit\n"));
2091  printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
2092  printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
2093  printf(_(" --load-extension=EXT load the named extension before running the\n"));
2094  printf(_(" tests; can appear multiple times\n"));
2095  printf(_(" --make-testtablespace-dir create testtablespace directory\n"));
2096  printf(_(" --max-connections=N maximum number of concurrent connections\n"));
2097  printf(_(" (default is 0, meaning unlimited)\n"));
2098  printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n"));
2099  printf(_(" (default is 0, meaning unlimited)\n"));
2100  printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
2101  printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
2102  printf(_(" (can be used multiple times to concatenate)\n"));
2103  printf(_(" --temp-instance=DIR create a temporary instance in DIR\n"));
2104  printf(_(" --use-existing use an existing installation\n"));
2105  printf(_(" -V, --version output version information, then exit\n"));
2106  printf(_("\n"));
2107  printf(_("Options for \"temp-instance\" mode:\n"));
2108  printf(_(" --no-locale use C locale\n"));
2109  printf(_(" --port=PORT start postmaster on PORT\n"));
2110  printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
2111  printf(_("\n"));
2112  printf(_("Options for using an existing installation:\n"));
2113  printf(_(" --host=HOST use postmaster running on HOST\n"));
2114  printf(_(" --port=PORT use postmaster running at PORT\n"));
2115  printf(_(" --user=USER connect as USER\n"));
2116  printf(_("\n"));
2117  printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
2118  printf(_("if the tests could not be run for some reason.\n"));
2119  printf(_("\n"));
2120  printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
2121  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
2122 }
static const char * progname
Definition: pg_regress.c:100
#define printf(...)
Definition: port.h:222
#define _(x)
Definition: elog.c:89

◆ initialize_environment()

static void initialize_environment ( void  )
static

Definition at line 739 of file pg_regress.c.

References _, addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_canonname, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, AI_NUMERICHOST, addrinfo::ai_protocol, addrinfo::ai_socktype, Assert, convert_sourcefiles(), encoding, fprintf, free, get_user_name(), getaddrinfo, hostname, load_resultmap(), MAXPGPATH, _stringlist::next, nolocale, pg_malloc(), pghost, pgport, port, printf, progname, psprintf(), realloc, setenv, snprintf, sockdir, sprintf, _stringlist::str, strerror, temp_instance, unsetenv, and user.

Referenced by regression_main().

740 {
741  /*
742  * Set default application_name. (The test_start_function may choose to
743  * override this, but if it doesn't, we have something useful in place.)
744  */
745  setenv("PGAPPNAME", "pg_regress", 1);
746 
747  if (nolocale)
748  {
749  /*
750  * Clear out any non-C locale settings
751  */
752  unsetenv("LC_COLLATE");
753  unsetenv("LC_CTYPE");
754  unsetenv("LC_MONETARY");
755  unsetenv("LC_NUMERIC");
756  unsetenv("LC_TIME");
757  unsetenv("LANG");
758 
759  /*
760  * Most platforms have adopted the POSIX locale as their
761  * implementation-defined default locale. Exceptions include native
762  * Windows, macOS with --enable-nls, and Cygwin with --enable-nls.
763  * (Use of --enable-nls matters because libintl replaces setlocale().)
764  * Also, PostgreSQL does not support macOS with locale environment
765  * variables unset; see PostmasterMain().
766  */
767 #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
768  setenv("LANG", "C", 1);
769 #endif
770  }
771 
772  /*
773  * Set translation-related settings to English; otherwise psql will
774  * produce translated messages and produce diffs. (XXX If we ever support
775  * translation of pg_regress, this needs to be moved elsewhere, where psql
776  * is actually called.)
777  */
778  unsetenv("LANGUAGE");
779  unsetenv("LC_ALL");
780  setenv("LC_MESSAGES", "C", 1);
781 
782  /*
783  * Set encoding as requested
784  */
785  if (encoding)
786  setenv("PGCLIENTENCODING", encoding, 1);
787  else
788  unsetenv("PGCLIENTENCODING");
789 
790  /*
791  * Set timezone and datestyle for datetime-related tests
792  */
793  setenv("PGTZ", "PST8PDT", 1);
794  setenv("PGDATESTYLE", "Postgres, MDY", 1);
795 
796  /*
797  * Likewise set intervalstyle to ensure consistent results. This is a bit
798  * more painful because we must use PGOPTIONS, and we want to preserve the
799  * user's ability to set other variables through that.
800  */
801  {
802  const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
803  const char *old_pgoptions = getenv("PGOPTIONS");
804  char *new_pgoptions;
805 
806  if (!old_pgoptions)
807  old_pgoptions = "";
808  new_pgoptions = psprintf("%s %s",
809  old_pgoptions, my_pgoptions);
810  setenv("PGOPTIONS", new_pgoptions, 1);
811  free(new_pgoptions);
812  }
813 
814  if (temp_instance)
815  {
816  /*
817  * Clear out any environment vars that might cause psql to connect to
818  * the wrong postmaster, or otherwise behave in nondefault ways. (Note
819  * we also use psql's -X switch consistently, so that ~/.psqlrc files
820  * won't mess things up.) Also, set PGPORT to the temp port, and set
821  * PGHOST depending on whether we are using TCP or Unix sockets.
822  *
823  * This list should be kept in sync with TestLib.pm.
824  */
825  unsetenv("PGCHANNELBINDING");
826  /* PGCLIENTENCODING, see above */
827  unsetenv("PGCONNECT_TIMEOUT");
828  unsetenv("PGDATA");
829  unsetenv("PGDATABASE");
830  unsetenv("PGGSSENCMODE");
831  unsetenv("PGGSSLIB");
832  /* PGHOSTADDR, see below */
833  unsetenv("PGKRBSRVNAME");
834  unsetenv("PGPASSFILE");
835  unsetenv("PGPASSWORD");
836  unsetenv("PGREQUIREPEER");
837  unsetenv("PGREQUIRESSL");
838  unsetenv("PGSERVICE");
839  unsetenv("PGSERVICEFILE");
840  unsetenv("PGSSLCERT");
841  unsetenv("PGSSLCRL");
842  unsetenv("PGSSLCRLDIR");
843  unsetenv("PGSSLKEY");
844  unsetenv("PGSSLMAXPROTOCOLVERSION");
845  unsetenv("PGSSLMINPROTOCOLVERSION");
846  unsetenv("PGSSLMODE");
847  unsetenv("PGSSLROOTCERT");
848  unsetenv("PGSSLSNI");
849  unsetenv("PGTARGETSESSIONATTRS");
850  unsetenv("PGUSER");
851  /* PGPORT, see below */
852  /* PGHOST, see below */
853 
854 #ifdef HAVE_UNIX_SOCKETS
855  if (hostname != NULL)
856  setenv("PGHOST", hostname, 1);
857  else
858  {
859  sockdir = getenv("PG_REGRESS_SOCK_DIR");
860  if (!sockdir)
861  sockdir = make_temp_sockdir();
862  setenv("PGHOST", sockdir, 1);
863  }
864 #else
865  Assert(hostname != NULL);
866  setenv("PGHOST", hostname, 1);
867 #endif
868  unsetenv("PGHOSTADDR");
869  if (port != -1)
870  {
871  char s[16];
872 
873  sprintf(s, "%d", port);
874  setenv("PGPORT", s, 1);
875  }
876  }
877  else
878  {
879  const char *pghost;
880  const char *pgport;
881 
882  /*
883  * When testing an existing install, we honor existing environment
884  * variables, except if they're overridden by command line options.
885  */
886  if (hostname != NULL)
887  {
888  setenv("PGHOST", hostname, 1);
889  unsetenv("PGHOSTADDR");
890  }
891  if (port != -1)
892  {
893  char s[16];
894 
895  sprintf(s, "%d", port);
896  setenv("PGPORT", s, 1);
897  }
898  if (user != NULL)
899  setenv("PGUSER", user, 1);
900 
901  /*
902  * However, we *don't* honor PGDATABASE, since we certainly don't wish
903  * to connect to whatever database the user might like as default.
904  * (Most tests override PGDATABASE anyway, but there are some ECPG
905  * test cases that don't.)
906  */
907  unsetenv("PGDATABASE");
908 
909  /*
910  * Report what we're connecting to
911  */
912  pghost = getenv("PGHOST");
913  pgport = getenv("PGPORT");
914 #ifndef HAVE_UNIX_SOCKETS
915  if (!pghost)
916  pghost = "localhost";
917 #endif
918 
919  if (pghost && pgport)
920  printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
921  if (pghost && !pgport)
922  printf(_("(using postmaster on %s, default port)\n"), pghost);
923  if (!pghost && pgport)
924  printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
925  if (!pghost && !pgport)
926  printf(_("(using postmaster on Unix socket, default port)\n"));
927  }
928 
930  load_resultmap();
931 }
static const char * sockdir
Definition: pg_regress.c:104
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static char * encoding
Definition: pg_regress.c:84
const char * pghost
Definition: pgbench.c:280
#define printf(...)
Definition: port.h:222
static char * temp_instance
Definition: pg_regress.c:87
static void convert_sourcefiles(void)
Definition: pg_regress.c:582
#define sprintf
Definition: port.h:218
#define setenv(x, y, z)
Definition: win32_port.h:497
static int port
Definition: pg_regress.c:92
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:804
static void load_resultmap(void)
Definition: pg_regress.c:628
static char * user
Definition: pg_regress.c:95
static bool nolocale
Definition: pg_regress.c:89
static char * hostname
Definition: pg_regress.c:91
#define _(x)
Definition: elog.c:89
const char * pgport
Definition: pgbench.c:281
#define unsetenv(x)
Definition: win32_port.h:498

◆ load_resultmap()

static void load_resultmap ( void  )
static

Definition at line 628 of file pg_regress.c.

References _, buf, fprintf, host_platform, i, inputdir, MAXPGPATH, _resultmap::next, pg_malloc(), pg_strdup(), progname, _resultmap::resultfile, resultmap, snprintf, strerror, string_matches_pattern(), _resultmap::test, and _resultmap::type.

Referenced by initialize_environment().

629 {
630  char buf[MAXPGPATH];
631  FILE *f;
632 
633  /* scan the file ... */
634  snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
635  f = fopen(buf, "r");
636  if (!f)
637  {
638  /* OK if it doesn't exist, else complain */
639  if (errno == ENOENT)
640  return;
641  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
642  progname, buf, strerror(errno));
643  exit(2);
644  }
645 
646  while (fgets(buf, sizeof(buf), f))
647  {
648  char *platform;
649  char *file_type;
650  char *expected;
651  int i;
652 
653  /* strip trailing whitespace, especially the newline */
654  i = strlen(buf);
655  while (i > 0 && isspace((unsigned char) buf[i - 1]))
656  buf[--i] = '\0';
657 
658  /* parse out the line fields */
659  file_type = strchr(buf, ':');
660  if (!file_type)
661  {
662  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
663  buf);
664  exit(2);
665  }
666  *file_type++ = '\0';
667 
668  platform = strchr(file_type, ':');
669  if (!platform)
670  {
671  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
672  buf);
673  exit(2);
674  }
675  *platform++ = '\0';
676  expected = strchr(platform, '=');
677  if (!expected)
678  {
679  fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
680  buf);
681  exit(2);
682  }
683  *expected++ = '\0';
684 
685  /*
686  * if it's for current platform, save it in resultmap list. Note: by
687  * adding at the front of the list, we ensure that in ambiguous cases,
688  * the last match in the resultmap file is used. This mimics the
689  * behavior of the old shell script.
690  */
691  if (string_matches_pattern(host_platform, platform))
692  {
693  _resultmap *entry = pg_malloc(sizeof(_resultmap));
694 
695  entry->test = pg_strdup(buf);
696  entry->type = pg_strdup(file_type);
697  entry->resultfile = pg_strdup(expected);
698  entry->next = resultmap;
699  resultmap = entry;
700  }
701  }
702  fclose(f);
703 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * host_platform
Definition: pg_regress.c:55
static const char * progname
Definition: pg_regress.c:100
struct _resultmap * next
Definition: pg_regress.c:49
static bool string_matches_pattern(const char *str, const char *pattern)
Definition: pg_regress.c:379
#define fprintf
Definition: port.h:220
static _resultmap * resultmap
Definition: pg_regress.c:111
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:68
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * test
Definition: pg_regress.c:46
char * type
Definition: pg_regress.c:47
char * inputdir
Definition: pg_regress.c:77
#define strerror
Definition: port.h:229
char * resultfile
Definition: pg_regress.c:48
int i
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ log_child_failure()

static void log_child_failure ( int  exitstatus)
static

Definition at line 1627 of file pg_regress.c.

References _, pg_strsignal(), status(), WEXITSTATUS, WIFEXITED, WIFSIGNALED, and WTERMSIG.

Referenced by run_schedule(), and run_single_test().

1628 {
1629  if (WIFEXITED(exitstatus))
1630  status(_(" (test process exited with exit code %d)"),
1631  WEXITSTATUS(exitstatus));
1632  else if (WIFSIGNALED(exitstatus))
1633  {
1634 #if defined(WIN32)
1635  status(_(" (test process was terminated by exception 0x%X)"),
1636  WTERMSIG(exitstatus));
1637 #else
1638  status(_(" (test process was terminated by signal %d: %s)"),
1639  WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
1640 #endif
1641  }
1642  else
1643  status(_(" (test process exited with unrecognized status %d)"),
1644  exitstatus);
1645 }
#define WTERMSIG(w)
Definition: win32_port.h:146
#define WIFEXITED(w)
Definition: win32_port.h:143
const char * pg_strsignal(int signum)
Definition: pgstrsignal.c:42
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define WIFSIGNALED(w)
Definition: win32_port.h:144
#define _(x)
Definition: elog.c:89
#define WEXITSTATUS(w)
Definition: win32_port.h:145

◆ make_directory()

static void make_directory ( const char *  dir)
static

Definition at line 1324 of file pg_regress.c.

References _, fprintf, mkdir, progname, S_IRWXG, S_IRWXO, S_IRWXU, and strerror.

Referenced by convert_sourcefiles_in(), open_result_files(), prepare_testtablespace_dir(), and regression_main().

1325 {
1326  if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1327  {
1328  fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
1329  progname, dir, strerror(errno));
1330  exit(2);
1331  }
1332 }
static const char * progname
Definition: pg_regress.c:100
#define fprintf
Definition: port.h:220
#define S_IRWXG
Definition: win32_port.h:301
#define strerror
Definition: port.h:229
#define S_IRWXU
Definition: win32_port.h:289
#define mkdir(a, b)
Definition: win32_port.h:63
#define _(x)
Definition: elog.c:89
#define S_IRWXO
Definition: win32_port.h:313

◆ open_result_files()

static void open_result_files ( void  )
static

Definition at line 1973 of file pg_regress.c.

References _, difffilename, directory_exists(), fprintf, logfile, logfilename, make_directory(), MAXPGPATH, outputdir, pg_strdup(), progname, snprintf, and strerror.

Referenced by regression_main().

1974 {
1975  char file[MAXPGPATH];
1976  FILE *difffile;
1977 
1978  /* create outputdir directory if not present */
1981 
1982  /* create the log file (copy of running status output) */
1983  snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1984  logfilename = pg_strdup(file);
1985  logfile = fopen(logfilename, "w");
1986  if (!logfile)
1987  {
1988  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1989  progname, logfilename, strerror(errno));
1990  exit(2);
1991  }
1992 
1993  /* create the diffs file as empty */
1994  snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1995  difffilename = pg_strdup(file);
1996  difffile = fopen(difffilename, "w");
1997  if (!difffile)
1998  {
1999  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
2000  progname, difffilename, strerror(errno));
2001  exit(2);
2002  }
2003  /* we don't keep the diffs file open continuously */
2004  fclose(difffile);
2005 
2006  /* also create the results directory if not present */
2007  snprintf(file, sizeof(file), "%s/results", outputdir);
2008  if (!directory_exists(file))
2009  make_directory(file);
2010 }
static bool directory_exists(const char *dir)
Definition: pg_regress.c:1311
static const char * progname
Definition: pg_regress.c:100
static void make_directory(const char *dir)
Definition: pg_regress.c:1324
static FILE * logfile
Definition: pg_regress.c:102
#define fprintf
Definition: port.h:220
static char * difffilename
Definition: pg_regress.c:103
#define MAXPGPATH
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * outputdir
Definition: pg_regress.c:78
static char * logfilename
Definition: pg_regress.c:101
#define strerror
Definition: port.h:229
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ prepare_testtablespace_dir()

static void prepare_testtablespace_dir ( void  )
static

Definition at line 596 of file pg_regress.c.

References _, directory_exists(), fprintf, make_directory(), MAXPGPATH, outputdir, progname, rmtree(), and snprintf.

Referenced by regression_main().

597 {
598  char testtablespace[MAXPGPATH];
599 
600  snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
601 
602  if (directory_exists(testtablespace))
603  {
604  if (!rmtree(testtablespace, true))
605  {
606  fprintf(stderr, _("\n%s: could not remove test tablespace \"%s\"\n"),
607  progname, testtablespace);
608  exit(2);
609  }
610  }
611  make_directory(testtablespace);
612 }
static bool directory_exists(const char *dir)
Definition: pg_regress.c:1311
static const char * progname
Definition: pg_regress.c:100
static void make_directory(const char *dir)
Definition: pg_regress.c:1324
#define fprintf
Definition: port.h:220
#define MAXPGPATH
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:42
char * outputdir
Definition: pg_regress.c:78
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ psql_command()

static void psql_command ( const char *  database,
const char *  query,
  ... 
)
static

Definition at line 1144 of file pg_regress.c.

References _, generate_unaccent_rules::args, bindir, fprintf, MAXPGPATH, PID_TYPE, snprintf, and vsnprintf.

Referenced by create_database(), create_role(), drop_database_if_exists(), and drop_role_if_exists().

1145 {
1146  char query_formatted[1024];
1147  char query_escaped[2048];
1148  char psql_cmd[MAXPGPATH + 2048];
1149  va_list args;
1150  char *s;
1151  char *d;
1152 
1153  /* Generate the query with insertion of sprintf arguments */
1154  va_start(args, query);
1155  vsnprintf(query_formatted, sizeof(query_formatted), query, args);
1156  va_end(args);
1157 
1158  /* Now escape any shell double-quote metacharacters */
1159  d = query_escaped;
1160  for (s = query_formatted; *s; s++)
1161  {
1162  if (strchr("\\\"$`", *s))
1163  *d++ = '\\';
1164  *d++ = *s;
1165  }
1166  *d = '\0';
1167 
1168  /* And now we can build and execute the shell command */
1169  snprintf(psql_cmd, sizeof(psql_cmd),
1170  "\"%s%spsql\" -X -c \"%s\" \"%s\"",
1171  bindir ? bindir : "",
1172  bindir ? "/" : "",
1173  query_escaped,
1174  database);
1175 
1176  if (system(psql_cmd) != 0)
1177  {
1178  /* psql probably already reported the error */
1179  fprintf(stderr, _("command failed: %s\n"), psql_cmd);
1180  exit(2);
1181  }
1182 }
#define fprintf
Definition: port.h:220
#define vsnprintf
Definition: port.h:215
#define MAXPGPATH
char * bindir
Definition: pg_regress.c:79
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ regression_main()

int regression_main ( int  argc,
char *  argv[],
init_function  ifunc,
test_start_function  startfunc,
postprocess_result_function  postfunc 
)

Definition at line 2125 of file pg_regress.c.

References _, add_stringlist_item(), bindir, buf, config_auth_datadir, create_database(), create_role(), debug, DEVNULL, difffilename, directory_exists(), dlpath, drop_database_if_exists(), drop_role_if_exists(), encoding, fail_count, fail_ignore_count, file_size(), fprintf, free_stringlist(), get_progname(), get_restricted_token(), getopt_long(), header(), help(), hostname, i, initialize_environment(), inputdir, INVALID_PID, kill, launcher, logfile, logfilename, make_absolute_path(), make_directory(), max_concurrent_tests, max_connections, MAXPGPATH, _stringlist::next, no_argument, nolocale, open_result_files(), optarg, optind, outputdir, pg_logging_init(), pg_strdup(), PG_TEXTDOMAIN, pg_usleep(), port, port_specified_by_user, postmaster_pid, postmaster_running, prepare_testtablespace_dir(), pretty_diff_opts, printf, progname, required_argument, rmtree(), run_schedule(), run_single_test(), set_pglocale_pgservice(), setenv, SIGKILL, snprintf, sockdir, spawn_process(), split_to_stringlist(), sprintf, stop_postmaster(), _stringlist::str, strerror, success_count, temp_instance, true, ULONGPID, use_existing, user, and wait_seconds.

Referenced by main().

2129 {
2130  static struct option long_options[] = {
2131  {"help", no_argument, NULL, 'h'},
2132  {"version", no_argument, NULL, 'V'},
2133  {"dbname", required_argument, NULL, 1},
2134  {"debug", no_argument, NULL, 2},
2135  {"inputdir", required_argument, NULL, 3},
2136  {"max-connections", required_argument, NULL, 5},
2137  {"encoding", required_argument, NULL, 6},
2138  {"outputdir", required_argument, NULL, 7},
2139  {"schedule", required_argument, NULL, 8},
2140  {"temp-instance", required_argument, NULL, 9},
2141  {"no-locale", no_argument, NULL, 10},
2142  {"host", required_argument, NULL, 13},
2143  {"port", required_argument, NULL, 14},
2144  {"user", required_argument, NULL, 15},
2145  {"bindir", required_argument, NULL, 16},
2146  {"dlpath", required_argument, NULL, 17},
2147  {"create-role", required_argument, NULL, 18},
2148  {"temp-config", required_argument, NULL, 19},
2149  {"use-existing", no_argument, NULL, 20},
2150  {"launcher", required_argument, NULL, 21},
2151  {"load-extension", required_argument, NULL, 22},
2152  {"config-auth", required_argument, NULL, 24},
2153  {"max-concurrent-tests", required_argument, NULL, 25},
2154  {"make-testtablespace-dir", no_argument, NULL, 26},
2155  {NULL, 0, NULL, 0}
2156  };
2157 
2158  bool use_unix_sockets;
2159  bool make_testtablespace_dir = false;
2160  _stringlist *sl;
2161  int c;
2162  int i;
2163  int option_index;
2164  char buf[MAXPGPATH * 4];
2165  char buf2[MAXPGPATH * 4];
2166 
2167  pg_logging_init(argv[0]);
2168  progname = get_progname(argv[0]);
2169  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
2170 
2172 
2173  atexit(stop_postmaster);
2174 
2175 #if !defined(HAVE_UNIX_SOCKETS)
2176  use_unix_sockets = false;
2177 #elif defined(WIN32)
2178 
2179  /*
2180  * We don't use Unix-domain sockets on Windows by default, even if the
2181  * build supports them. (See comment at remove_temp() for a reason.)
2182  * Override at your own risk.
2183  */
2184  use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
2185 #else
2186  use_unix_sockets = true;
2187 #endif
2188 
2189  if (!use_unix_sockets)
2190  hostname = "localhost";
2191 
2192  /*
2193  * We call the initialization function here because that way we can set
2194  * default parameters and let them be overwritten by the commandline.
2195  */
2196  ifunc(argc, argv);
2197 
2198  if (getenv("PG_REGRESS_DIFF_OPTS"))
2199  pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
2200 
2201  while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
2202  {
2203  switch (c)
2204  {
2205  case 'h':
2206  help();
2207  exit(0);
2208  case 'V':
2209  puts("pg_regress (PostgreSQL) " PG_VERSION);
2210  exit(0);
2211  case 1:
2212 
2213  /*
2214  * If a default database was specified, we need to remove it
2215  * before we add the specified one.
2216  */
2219  break;
2220  case 2:
2221  debug = true;
2222  break;
2223  case 3:
2225  break;
2226  case 5:
2227  max_connections = atoi(optarg);
2228  break;
2229  case 6:
2231  break;
2232  case 7:
2234  break;
2235  case 8:
2237  break;
2238  case 9:
2240  break;
2241  case 10:
2242  nolocale = true;
2243  break;
2244  case 13:
2246  break;
2247  case 14:
2248  port = atoi(optarg);
2249  port_specified_by_user = true;
2250  break;
2251  case 15:
2252  user = pg_strdup(optarg);
2253  break;
2254  case 16:
2255  /* "--bindir=" means to use PATH */
2256  if (strlen(optarg))
2257  bindir = pg_strdup(optarg);
2258  else
2259  bindir = NULL;
2260  break;
2261  case 17:
2262  dlpath = pg_strdup(optarg);
2263  break;
2264  case 18:
2266  break;
2267  case 19:
2269  break;
2270  case 20:
2271  use_existing = true;
2272  break;
2273  case 21:
2275  break;
2276  case 22:
2278  break;
2279  case 24:
2281  break;
2282  case 25:
2283  max_concurrent_tests = atoi(optarg);
2284  break;
2285  case 26:
2286  make_testtablespace_dir = true;
2287  break;
2288  default:
2289  /* getopt_long already emitted a complaint */
2290  fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
2291  progname);
2292  exit(2);
2293  }
2294  }
2295 
2296  /*
2297  * if we still have arguments, they are extra tests to run
2298  */
2299  while (argc - optind >= 1)
2300  {
2302  optind++;
2303  }
2304 
2305  if (config_auth_datadir)
2306  {
2307 #ifdef ENABLE_SSPI
2308  if (!use_unix_sockets)
2309  config_sspi_auth(config_auth_datadir, user);
2310 #endif
2311  exit(0);
2312  }
2313 
2315 
2316  /*
2317  * To reduce chances of interference with parallel installations, use
2318  * a port number starting in the private range (49152-65535)
2319  * calculated from the version number. This aids !HAVE_UNIX_SOCKETS
2320  * systems; elsewhere, the use of a private socket directory already
2321  * prevents interference.
2322  */
2323  port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2324 
2328 
2329  /*
2330  * Initialization
2331  */
2333 
2335 
2336 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
2337  unlimit_core_size();
2338 #endif
2339 
2340  if (make_testtablespace_dir)
2342 
2343  if (temp_instance)
2344  {
2345  FILE *pg_conf;
2346  const char *env_wait;
2347  int wait_seconds;
2348 
2349  /*
2350  * Prepare the temp instance
2351  */
2352 
2354  {
2355  header(_("removing existing temp instance"));
2356  if (!rmtree(temp_instance, true))
2357  {
2358  fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
2360  exit(2);
2361  }
2362  }
2363 
2364  header(_("creating temporary instance"));
2365 
2366  /* make the temp instance top directory */
2368 
2369  /* and a directory for log files */
2370  snprintf(buf, sizeof(buf), "%s/log", outputdir);
2371  if (!directory_exists(buf))
2372  make_directory(buf);
2373 
2374  /* initdb */
2375  header(_("initializing database system"));
2376  snprintf(buf, sizeof(buf),
2377  "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1",
2378  bindir ? bindir : "",
2379  bindir ? "/" : "",
2380  temp_instance,
2381  debug ? " --debug" : "",
2382  nolocale ? " --no-locale" : "",
2383  outputdir);
2384  if (system(buf))
2385  {
2386  fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
2387  exit(2);
2388  }
2389 
2390  /*
2391  * Adjust the default postgresql.conf for regression testing. The user
2392  * can specify a file to be appended; in any case we expand logging
2393  * and set max_prepared_transactions to enable testing of prepared
2394  * xacts. (Note: to reduce the probability of unexpected shmmax
2395  * failures, don't set max_prepared_transactions any higher than
2396  * actually needed by the prepared_xacts regression test.)
2397  */
2398  snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
2399  pg_conf = fopen(buf, "a");
2400  if (pg_conf == NULL)
2401  {
2402  fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
2403  exit(2);
2404  }
2405  fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2406  fputs("log_autovacuum_min_duration = 0\n", pg_conf);
2407  fputs("log_checkpoints = on\n", pg_conf);
2408  fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
2409  fputs("log_lock_waits = on\n", pg_conf);
2410  fputs("log_temp_files = 128kB\n", pg_conf);
2411  fputs("max_prepared_transactions = 2\n", pg_conf);
2412 
2413  for (sl = temp_configs; sl != NULL; sl = sl->next)
2414  {
2415  char *temp_config = sl->str;
2416  FILE *extra_conf;
2417  char line_buf[1024];
2418 
2419  extra_conf = fopen(temp_config, "r");
2420  if (extra_conf == NULL)
2421  {
2422  fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
2423  exit(2);
2424  }
2425  while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2426  fputs(line_buf, pg_conf);
2427  fclose(extra_conf);
2428  }
2429 
2430  fclose(pg_conf);
2431 
2432 #ifdef ENABLE_SSPI
2433  if (!use_unix_sockets)
2434  {
2435  /*
2436  * Since we successfully used the same buffer for the much-longer
2437  * "initdb" command, this can't truncate.
2438  */
2439  snprintf(buf, sizeof(buf), "%s/data", temp_instance);
2440  config_sspi_auth(buf, NULL);
2441  }
2442 #elif !defined(HAVE_UNIX_SOCKETS)
2443 #error Platform has no means to secure the test installation.
2444 #endif
2445 
2446  /*
2447  * Check if there is a postmaster running already.
2448  */
2449  snprintf(buf2, sizeof(buf2),
2450  "\"%s%spsql\" -X postgres <%s 2>%s",
2451  bindir ? bindir : "",
2452  bindir ? "/" : "",
2453  DEVNULL, DEVNULL);
2454 
2455  for (i = 0; i < 16; i++)
2456  {
2457  if (system(buf2) == 0)
2458  {
2459  char s[16];
2460 
2461  if (port_specified_by_user || i == 15)
2462  {
2463  fprintf(stderr, _("port %d apparently in use\n"), port);
2465  fprintf(stderr, _("%s: could not determine an available port\n"), progname);
2466  fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
2467  exit(2);
2468  }
2469 
2470  fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
2471  port++;
2472  sprintf(s, "%d", port);
2473  setenv("PGPORT", s, 1);
2474  }
2475  else
2476  break;
2477  }
2478 
2479  /*
2480  * Start the temp postmaster
2481  */
2482  header(_("starting postmaster"));
2483  snprintf(buf, sizeof(buf),
2484  "\"%s%spostgres\" -D \"%s/data\" -F%s "
2485  "-c \"listen_addresses=%s\" -k \"%s\" "
2486  "> \"%s/log/postmaster.log\" 2>&1",
2487  bindir ? bindir : "",
2488  bindir ? "/" : "",
2489  temp_instance, debug ? " -d 5" : "",
2490  hostname ? hostname : "", sockdir ? sockdir : "",
2491  outputdir);
2493  if (postmaster_pid == INVALID_PID)
2494  {
2495  fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
2496  progname, strerror(errno));
2497  exit(2);
2498  }
2499 
2500  /*
2501  * Wait till postmaster is able to accept connections; normally this
2502  * is only a second or so, but Cygwin is reportedly *much* slower, and
2503  * test builds using Valgrind or similar tools might be too. Hence,
2504  * allow the default timeout of 60 seconds to be overridden from the
2505  * PGCTLTIMEOUT environment variable.
2506  */
2507  env_wait = getenv("PGCTLTIMEOUT");
2508  if (env_wait != NULL)
2509  {
2510  wait_seconds = atoi(env_wait);
2511  if (wait_seconds <= 0)
2512  wait_seconds = 60;
2513  }
2514  else
2515  wait_seconds = 60;
2516 
2517  for (i = 0; i < wait_seconds; i++)
2518  {
2519  /* Done if psql succeeds */
2520  if (system(buf2) == 0)
2521  break;
2522 
2523  /*
2524  * Fail immediately if postmaster has exited
2525  */
2526 #ifndef WIN32
2527  if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
2528 #else
2529  if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2530 #endif
2531  {
2532  fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
2533  exit(2);
2534  }
2535 
2536  pg_usleep(1000000L);
2537  }
2538  if (i >= wait_seconds)
2539  {
2540  fprintf(stderr, _("\n%s: postmaster did not respond within %d seconds\nExamine %s/log/postmaster.log for the reason\n"),
2541  progname, wait_seconds, outputdir);
2542 
2543  /*
2544  * If we get here, the postmaster is probably wedged somewhere in
2545  * startup. Try to kill it ungracefully rather than leaving a
2546  * stuck postmaster that might interfere with subsequent test
2547  * attempts.
2548  */
2549 #ifndef WIN32
2550  if (kill(postmaster_pid, SIGKILL) != 0 &&
2551  errno != ESRCH)
2552  fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
2553  progname, strerror(errno));
2554 #else
2555  if (TerminateProcess(postmaster_pid, 255) == 0)
2556  fprintf(stderr, _("\n%s: could not kill failed postmaster: error code %lu\n"),
2557  progname, GetLastError());
2558 #endif
2559 
2560  exit(2);
2561  }
2562 
2563  postmaster_running = true;
2564 
2565 #ifdef _WIN64
2566 /* need a series of two casts to convert HANDLE without compiler warning */
2567 #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2568 #else
2569 #define ULONGPID(x) (unsigned long) (x)
2570 #endif
2571  printf(_("running on port %d with PID %lu\n"),
2573  }
2574  else
2575  {
2576  /*
2577  * Using an existing installation, so may need to get rid of
2578  * pre-existing database(s) and role(s)
2579  */
2580  if (!use_existing)
2581  {
2582  for (sl = dblist; sl; sl = sl->next)
2584  for (sl = extraroles; sl; sl = sl->next)
2585  drop_role_if_exists(sl->str);
2586  }
2587  }
2588 
2589  /*
2590  * Create the test database(s) and role(s)
2591  */
2592  if (!use_existing)
2593  {
2594  for (sl = dblist; sl; sl = sl->next)
2595  create_database(sl->str);
2596  for (sl = extraroles; sl; sl = sl->next)
2597  create_role(sl->str, dblist);
2598  }
2599 
2600  /*
2601  * Ready to run the tests
2602  */
2603  header(_("running regression test queries"));
2604 
2605  for (sl = schedulelist; sl != NULL; sl = sl->next)
2606  {
2607  run_schedule(sl->str, startfunc, postfunc);
2608  }
2609 
2610  for (sl = extra_tests; sl != NULL; sl = sl->next)
2611  {
2612  run_single_test(sl->str, startfunc, postfunc);
2613  }
2614 
2615  /*
2616  * Shut down temp installation's postmaster
2617  */
2618  if (temp_instance)
2619  {
2620  header(_("shutting down postmaster"));
2621  stop_postmaster();
2622  }
2623 
2624  /*
2625  * If there were no errors, remove the temp instance immediately to
2626  * conserve disk space. (If there were errors, we leave the instance in
2627  * place for possible manual investigation.)
2628  */
2629  if (temp_instance && fail_count == 0 && fail_ignore_count == 0)
2630  {
2631  header(_("removing temporary instance"));
2632  if (!rmtree(temp_instance, true))
2633  fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
2635  }
2636 
2637  fclose(logfile);
2638 
2639  /*
2640  * Emit nice-looking summary message
2641  */
2642  if (fail_count == 0 && fail_ignore_count == 0)
2643  snprintf(buf, sizeof(buf),
2644  _(" All %d tests passed. "),
2645  success_count);
2646  else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
2647  snprintf(buf, sizeof(buf),
2648  _(" %d of %d tests passed, %d failed test(s) ignored. "),
2649  success_count,
2652  else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
2653  snprintf(buf, sizeof(buf),
2654  _(" %d of %d tests failed. "),
2655  fail_count,
2657  else
2658  /* fail_count>0 && fail_ignore_count>0 */
2659  snprintf(buf, sizeof(buf),
2660  _(" %d of %d tests failed, %d of these failures ignored. "),
2664 
2665  putchar('\n');
2666  for (i = strlen(buf); i > 0; i--)
2667  putchar('=');
2668  printf("\n%s\n", buf);
2669  for (i = strlen(buf); i > 0; i--)
2670  putchar('=');
2671  putchar('\n');
2672  putchar('\n');
2673 
2674  if (file_size(difffilename) > 0)
2675  {
2676  printf(_("The differences that caused some tests to fail can be viewed in the\n"
2677  "file \"%s\". A copy of the test summary that you see\n"
2678  "above is saved in the file \"%s\".\n\n"),
2680  }
2681  else
2682  {
2683  unlink(difffilename);
2684  unlink(logfilename);
2685  }
2686 
2687  if (fail_count != 0)
2688  exit(1);
2689 
2690  return 0;
2691 }
char * make_absolute_path(const char *path)
Definition: path.c:608
static bool directory_exists(const char *dir)
Definition: pg_regress.c:1311
static void drop_role_if_exists(const char *rolename)
Definition: pg_regress.c:2056
static void drop_database_if_exists(const char *dbname)
Definition: pg_regress.c:2013
static int max_concurrent_tests
Definition: pg_regress.c:83
static const char * sockdir
Definition: pg_regress.c:104
static int wait_seconds
Definition: pg_ctl.c:80
static _stringlist * extra_tests
Definition: pg_regress.c:86
static void help(void)
Definition: pg_regress.c:2075
char * str
Definition: pg_regress.h:26
static void initialize_environment(void)
Definition: pg_regress.c:739
bool debug
Definition: pg_regress.c:76
const char * get_progname(const char *argv0)
Definition: path.c:453
static void static void static void void add_stringlist_item(_stringlist **listhead, const char *str)
Definition: pg_regress.c:157
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
void get_restricted_token(void)
void pg_logging_init(const char *argv0)
Definition: logging.c:81
static char * encoding
Definition: pg_regress.c:84
static const char * progname
Definition: pg_regress.c:100
static void make_directory(const char *dir)
Definition: pg_regress.c:1324
static bool use_existing
Definition: pg_regress.c:90
static bool postmaster_running
Definition: pg_regress.c:114
#define kill(pid, sig)
Definition: win32_port.h:454
#define printf(...)
Definition: port.h:222
static FILE * logfile
Definition: pg_regress.c:102
static void stop_postmaster(void)
Definition: pg_regress.c:260
#define fprintf
Definition: port.h:220
static char * temp_instance
Definition: pg_regress.c:87
char * launcher
Definition: pg_regress.c:80
static void split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
Definition: pg_regress.c:193
static void free_stringlist(_stringlist **listhead)
Definition: pg_regress.c:178
PID_TYPE spawn_process(const char *cmdline)
Definition: pg_regress.c:1190
#define SIGKILL
Definition: win32_port.h:163
#define sprintf
Definition: port.h:218
#define setenv(x, y, z)
Definition: win32_port.h:497
#define true
Definition: c.h:395
static char * difffilename
Definition: pg_regress.c:103
void pg_usleep(long microsec)
Definition: signal.c:53
#define required_argument
Definition: getopt_long.h:25
int optind
Definition: getopt.c:50
static _stringlist * loadextension
Definition: pg_regress.c:81
static void run_schedule(const char *schedule, test_start_function startfunc, postprocess_result_function postfunc)
Definition: pg_regress.c:1651
#define MAXPGPATH
_stringlist * dblist
Definition: pg_regress.c:75
static _stringlist * extraroles
Definition: pg_regress.c:96
static _stringlist * temp_configs
Definition: pg_regress.c:88
char * c
const char * pretty_diff_opts
Definition: pg_regress.c:68
static char * buf
Definition: pg_test_fsync.c:68
#define INVALID_PID
Definition: pg_regress.h:15
static void create_role(const char *rolename, const _stringlist *granted_dbs)
Definition: pg_regress.c:2063
static char * dlpath
Definition: pg_regress.c:94
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static int success_count
Definition: pg_regress.c:116
#define DEVNULL
Definition: port.h:147
static int max_connections
Definition: pg_regress.c:82
static int port
Definition: pg_regress.c:92
static PID_TYPE postmaster_pid
Definition: pg_regress.c:113
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:42
#define no_argument
Definition: getopt_long.h:24
static char * config_auth_datadir
Definition: pg_regress.c:97
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1215
static int fail_ignore_count
Definition: pg_regress.c:118
static int fail_count
Definition: pg_regress.c:117
char * outputdir
Definition: pg_regress.c:78
static void prepare_testtablespace_dir(void)
Definition: pg_regress.c:596
static char * logfilename
Definition: pg_regress.c:101
char * inputdir
Definition: pg_regress.c:77
static long file_size(const char *file)
Definition: pg_regress.c:1257
static bool port_specified_by_user
Definition: pg_regress.c:93
char * bindir
Definition: pg_regress.c:79
#define strerror
Definition: port.h:229
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
static char * user
Definition: pg_regress.c:95
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:433
char * optarg
Definition: getopt.c:52
static _stringlist * schedulelist
Definition: pg_regress.c:85
struct _stringlist * next
Definition: pg_regress.h:27
int i
static bool nolocale
Definition: pg_regress.c:89
static void open_result_files(void)
Definition: pg_regress.c:1973
static char * hostname
Definition: pg_regress.c:91
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89
static void run_single_test(const char *test, test_start_function startfunc, postprocess_result_function postfunc)
Definition: pg_regress.c:1905
#define ULONGPID(x)
static void create_database(const char *dbname)
Definition: pg_regress.c:2020

◆ replace_string()

void replace_string ( StringInfo  string,
const char *  replace,
const char *  replacement 
)

Definition at line 447 of file pg_regress.c.

References appendStringInfoString(), StringInfoData::data, free, and pg_strdup().

Referenced by convert_sourcefiles_in(), and ecpg_start_test().

448 {
449  int pos = 0;
450  char *ptr;
451 
452  while ((ptr = strstr(string->data + pos, replace)) != NULL)
453  {
454  /* Must copy the remainder of the string out of the StringInfo */
455  char *suffix = pg_strdup(ptr + strlen(replace));
456 
457  /* Truncate StringInfo at start of found string ... */
458  string->len = ptr - string->data;
459  /* ... and append the replacement (this restores the trailing '\0') */
460  appendStringInfoString(string, replacement);
461  /* Next search should start after the replacement */
462  pos = string->len;
463  /* Put back the remainder of the string */
464  appendStringInfoString(string, suffix);
465  free(suffix);
466  }
467 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define free(a)
Definition: header.h:65

◆ results_differ()

static bool results_differ ( const char *  testname,
const char *  resultsfile,
const char *  default_expectfile 
)
static

Definition at line 1405 of file pg_regress.c.

References _, basic_diff_opts, difffilename, file_exists(), file_line_count(), fprintf, free, get_alternative_expectfile(), get_expectfile(), i, MAXPGPATH, pretty_diff_opts, run_diff(), snprintf, strerror, and strlcpy().

Referenced by run_schedule(), and run_single_test().

1406 {
1407  char expectfile[MAXPGPATH];
1408  char diff[MAXPGPATH];
1409  char cmd[MAXPGPATH * 3];
1410  char best_expect_file[MAXPGPATH];
1411  FILE *difffile;
1412  int best_line_count;
1413  int i;
1414  int l;
1415  const char *platform_expectfile;
1416 
1417  /*
1418  * We can pass either the resultsfile or the expectfile, they should have
1419  * the same type (filename.type) anyway.
1420  */
1421  platform_expectfile = get_expectfile(testname, resultsfile);
1422 
1423  strlcpy(expectfile, default_expectfile, sizeof(expectfile));
1424  if (platform_expectfile)
1425  {
1426  /*
1427  * Replace everything after the last slash in expectfile with what the
1428  * platform_expectfile contains.
1429  */
1430  char *p = strrchr(expectfile, '/');
1431 
1432  if (p)
1433  strcpy(++p, platform_expectfile);
1434  }
1435 
1436  /* Name to use for temporary diff file */
1437  snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1438 
1439  /* OK, run the diff */
1440  snprintf(cmd, sizeof(cmd),
1441  "diff %s \"%s\" \"%s\" > \"%s\"",
1442  basic_diff_opts, expectfile, resultsfile, diff);
1443 
1444  /* Is the diff file empty? */
1445  if (run_diff(cmd, diff) == 0)
1446  {
1447  unlink(diff);
1448  return false;
1449  }
1450 
1451  /* There may be secondary comparison files that match better */
1452  best_line_count = file_line_count(diff);
1453  strcpy(best_expect_file, expectfile);
1454 
1455  for (i = 0; i <= 9; i++)
1456  {
1457  char *alt_expectfile;
1458 
1459  alt_expectfile = get_alternative_expectfile(expectfile, i);
1460  if (!alt_expectfile)
1461  {
1462  fprintf(stderr, _("Unable to check secondary comparison files: %s\n"),
1463  strerror(errno));
1464  exit(2);
1465  }
1466 
1467  if (!file_exists(alt_expectfile))
1468  {
1469  free(alt_expectfile);
1470  continue;
1471  }
1472 
1473  snprintf(cmd, sizeof(cmd),
1474  "diff %s \"%s\" \"%s\" > \"%s\"",
1475  basic_diff_opts, alt_expectfile, resultsfile, diff);
1476 
1477  if (run_diff(cmd, diff) == 0)
1478  {
1479  unlink(diff);
1480  free(alt_expectfile);
1481  return false;
1482  }
1483 
1484  l = file_line_count(diff);
1485  if (l < best_line_count)
1486  {
1487  /* This diff was a better match than the last one */
1488  best_line_count = l;
1489  strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
1490  }
1491  free(alt_expectfile);
1492  }
1493 
1494  /*
1495  * fall back on the canonical results file if we haven't tried it yet and
1496  * haven't found a complete match yet.
1497  */
1498 
1499  if (platform_expectfile)
1500  {
1501  snprintf(cmd, sizeof(cmd),
1502  "diff %s \"%s\" \"%s\" > \"%s\"",
1503  basic_diff_opts, default_expectfile, resultsfile, diff);
1504 
1505  if (run_diff(cmd, diff) == 0)
1506  {
1507  /* No diff = no changes = good */
1508  unlink(diff);
1509  return false;
1510  }
1511 
1512  l = file_line_count(diff);
1513  if (l < best_line_count)
1514  {
1515  /* This diff was a better match than the last one */
1516  best_line_count = l;
1517  strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
1518  }
1519  }
1520 
1521  /*
1522  * Use the best comparison file to generate the "pretty" diff, which we
1523  * append to the diffs summary file.
1524  */
1525 
1526  /* Write diff header */
1527  difffile = fopen(difffilename, "a");
1528  if (difffile)
1529  {
1530  fprintf(difffile,
1531  "diff %s %s %s\n",
1532  pretty_diff_opts, best_expect_file, resultsfile);
1533  fclose(difffile);
1534  }
1535 
1536  /* Run diff */
1537  snprintf(cmd, sizeof(cmd),
1538  "diff %s \"%s\" \"%s\" >> \"%s\"",
1539  pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1540  run_diff(cmd, difffilename);
1541 
1542  unlink(diff);
1543  return true;
1544 }
static char * get_alternative_expectfile(const char *expectfile, int i)
Definition: pg_regress.c:1338
#define fprintf
Definition: port.h:220
static char * difffilename
Definition: pg_regress.c:103
#define MAXPGPATH
const char * pretty_diff_opts
Definition: pg_regress.c:68
static int run_diff(const char *cmd, const char *filename)
Definition: pg_regress.c:1372
#define free(a)
Definition: header.h:65
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static const char * get_expectfile(const char *testname, const char *file)
Definition: pg_regress.c:710
static int file_line_count(const char *file)
Definition: pg_regress.c:1278
#define strerror
Definition: port.h:229
bool file_exists(const char *file)
Definition: pg_regress.c:1300
int i
const char * basic_diff_opts
Definition: pg_regress.c:67
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ run_diff()

static int run_diff ( const char *  cmd,
const char *  filename 
)
static

Definition at line 1372 of file pg_regress.c.

References _, file_size(), fprintf, WEXITSTATUS, and WIFEXITED.

Referenced by results_differ().

1373 {
1374  int r;
1375 
1376  r = system(cmd);
1377  if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1378  {
1379  fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
1380  exit(2);
1381  }
1382 #ifdef WIN32
1383 
1384  /*
1385  * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1386  * but produces nothing to stdout, so we check for that here.
1387  */
1388  if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1389  {
1390  fprintf(stderr, _("diff command not found: %s\n"), cmd);
1391  exit(2);
1392  }
1393 #endif
1394 
1395  return WEXITSTATUS(r);
1396 }
#define fprintf
Definition: port.h:220
#define WIFEXITED(w)
Definition: win32_port.h:143
static long file_size(const char *file)
Definition: pg_regress.c:1257
static char * filename
Definition: pg_dumpall.c:92
#define _(x)
Definition: elog.c:89
#define WEXITSTATUS(w)
Definition: win32_port.h:145

◆ run_schedule()

static void run_schedule ( const char *  schedule,
test_start_function  startfunc,
postprocess_result_function  postfunc 
)
static

Definition at line 1651 of file pg_regress.c.

References _, add_stringlist_item(), fail_count, fail_ignore_count, fprintf, free_stringlist(), i, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, log_child_failure(), max_concurrent_tests, max_connections, MAX_PARALLEL_TESTS, _stringlist::next, pg_free(), pg_strdup(), PID_TYPE, printf, progname, results_differ(), status(), status_end(), _stringlist::str, strerror, success_count, _resultmap::test, and wait_for_tests().

Referenced by regression_main().

1653 {
1654 #define MAX_PARALLEL_TESTS 100
1655  char *tests[MAX_PARALLEL_TESTS];
1656  _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1657  _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1660  instr_time starttimes[MAX_PARALLEL_TESTS];
1661  instr_time stoptimes[MAX_PARALLEL_TESTS];
1662  int statuses[MAX_PARALLEL_TESTS];
1663  _stringlist *ignorelist = NULL;
1664  char scbuf[1024];
1665  FILE *scf;
1666  int line_num = 0;
1667 
1668  memset(tests, 0, sizeof(tests));
1669  memset(resultfiles, 0, sizeof(resultfiles));
1670  memset(expectfiles, 0, sizeof(expectfiles));
1671  memset(tags, 0, sizeof(tags));
1672 
1673  scf = fopen(schedule, "r");
1674  if (!scf)
1675  {
1676  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1677  progname, schedule, strerror(errno));
1678  exit(2);
1679  }
1680 
1681  while (fgets(scbuf, sizeof(scbuf), scf))
1682  {
1683  char *test = NULL;
1684  char *c;
1685  int num_tests;
1686  bool inword;
1687  int i;
1688 
1689  line_num++;
1690 
1691  /* strip trailing whitespace, especially the newline */
1692  i = strlen(scbuf);
1693  while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1694  scbuf[--i] = '\0';
1695 
1696  if (scbuf[0] == '\0' || scbuf[0] == '#')
1697  continue;
1698  if (strncmp(scbuf, "test: ", 6) == 0)
1699  test = scbuf + 6;
1700  else if (strncmp(scbuf, "ignore: ", 8) == 0)
1701  {
1702  c = scbuf + 8;
1703  while (*c && isspace((unsigned char) *c))
1704  c++;
1705  add_stringlist_item(&ignorelist, c);
1706 
1707  /*
1708  * Note: ignore: lines do not run the test, they just say that
1709  * failure of this test when run later on is to be ignored. A bit
1710  * odd but that's how the shell-script version did it.
1711  */
1712  continue;
1713  }
1714  else
1715  {
1716  fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1717  schedule, line_num, scbuf);
1718  exit(2);
1719  }
1720 
1721  num_tests = 0;
1722  inword = false;
1723  for (c = test;; c++)
1724  {
1725  if (*c == '\0' || isspace((unsigned char) *c))
1726  {
1727  if (inword)
1728  {
1729  /* Reached end of a test name */
1730  char sav;
1731 
1732  if (num_tests >= MAX_PARALLEL_TESTS)
1733  {
1734  fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
1735  MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
1736  exit(2);
1737  }
1738  sav = *c;
1739  *c = '\0';
1740  tests[num_tests] = pg_strdup(test);
1741  num_tests++;
1742  *c = sav;
1743  inword = false;
1744  }
1745  if (*c == '\0')
1746  break; /* loop exit is here */
1747  }
1748  else if (!inword)
1749  {
1750  /* Start of a test name */
1751  test = c;
1752  inword = true;
1753  }
1754  }
1755 
1756  if (num_tests == 0)
1757  {
1758  fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1759  schedule, line_num, scbuf);
1760  exit(2);
1761  }
1762 
1763  if (num_tests == 1)
1764  {
1765  status(_("test %-28s ... "), tests[0]);
1766  pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1767  INSTR_TIME_SET_CURRENT(starttimes[0]);
1768  wait_for_tests(pids, statuses, stoptimes, NULL, 1);
1769  /* status line is finished below */
1770  }
1771  else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
1772  {
1773  fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
1774  max_concurrent_tests, schedule, line_num, scbuf);
1775  exit(2);
1776  }
1777  else if (max_connections > 0 && max_connections < num_tests)
1778  {
1779  int oldest = 0;
1780 
1781  status(_("parallel group (%d tests, in groups of %d): "),
1782  num_tests, max_connections);
1783  for (i = 0; i < num_tests; i++)
1784  {
1785  if (i - oldest >= max_connections)
1786  {
1787  wait_for_tests(pids + oldest, statuses + oldest,
1788  stoptimes + oldest,
1789  tests + oldest, i - oldest);
1790  oldest = i;
1791  }
1792  pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1793  INSTR_TIME_SET_CURRENT(starttimes[i]);
1794  }
1795  wait_for_tests(pids + oldest, statuses + oldest,
1796  stoptimes + oldest,
1797  tests + oldest, i - oldest);
1798  status_end();
1799  }
1800  else
1801  {
1802  status(_("parallel group (%d tests): "), num_tests);
1803  for (i = 0; i < num_tests; i++)
1804  {
1805  pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1806  INSTR_TIME_SET_CURRENT(starttimes[i]);
1807  }
1808  wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
1809  status_end();
1810  }
1811 
1812  /* Check results for all tests */
1813  for (i = 0; i < num_tests; i++)
1814  {
1815  _stringlist *rl,
1816  *el,
1817  *tl;
1818  bool differ = false;
1819 
1820  if (num_tests > 1)
1821  status(_(" %-28s ... "), tests[i]);
1822 
1823  /*
1824  * Advance over all three lists simultaneously.
1825  *
1826  * Compare resultfiles[j] with expectfiles[j] always. Tags are
1827  * optional but if there are tags, the tag list has the same
1828  * length as the other two lists.
1829  */
1830  for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1831  rl != NULL; /* rl and el have the same length */
1832  rl = rl->next, el = el->next,
1833  tl = tl ? tl->next : NULL)
1834  {
1835  bool newdiff;
1836 
1837  if (postfunc)
1838  (*postfunc) (rl->str);
1839  newdiff = results_differ(tests[i], rl->str, el->str);
1840  if (newdiff && tl)
1841  {
1842  printf("%s ", tl->str);
1843  }
1844  differ |= newdiff;
1845  }
1846 
1847  if (differ)
1848  {
1849  bool ignore = false;
1850  _stringlist *sl;
1851 
1852  for (sl = ignorelist; sl != NULL; sl = sl->next)
1853  {
1854  if (strcmp(tests[i], sl->str) == 0)
1855  {
1856  ignore = true;
1857  break;
1858  }
1859  }
1860  if (ignore)
1861  {
1862  status(_("failed (ignored)"));
1864  }
1865  else
1866  {
1867  status(_("FAILED"));
1868  fail_count++;
1869  }
1870  }
1871  else
1872  {
1873  status(_("ok ")); /* align with FAILED */
1874  success_count++;
1875  }
1876 
1877  if (statuses[i] != 0)
1878  log_child_failure(statuses[i]);
1879 
1880  INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
1881  status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptimes[i]));
1882 
1883  status_end();
1884  }
1885 
1886  for (i = 0; i < num_tests; i++)
1887  {
1888  pg_free(tests[i]);
1889  tests[i] = NULL;
1890  free_stringlist(&resultfiles[i]);
1891  free_stringlist(&expectfiles[i]);
1892  free_stringlist(&tags[i]);
1893  }
1894  }
1895 
1896  free_stringlist(&ignorelist);
1897 
1898  fclose(scf);
1899 }
static int max_concurrent_tests
Definition: pg_regress.c:83
static void test(void)
static void log_child_failure(int exitstatus)
Definition: pg_regress.c:1627
char * str
Definition: pg_regress.h:26
static void static void static void void add_stringlist_item(_stringlist **listhead, const char *str)
Definition: pg_regress.c:157
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
struct timeval instr_time
Definition: instr_time.h:150
static const char * progname
Definition: pg_regress.c:100
static void status_end(void)
Definition: pg_regress.c:248
#define PID_TYPE
Definition: pg_regress.h:14
#define printf(...)
Definition: port.h:222
#define fprintf
Definition: port.h:220
static bool results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
Definition: pg_regress.c:1405
static void free_stringlist(_stringlist **listhead)
Definition: pg_regress.c:178
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
char * c
#define MAX_PARALLEL_TESTS
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static int success_count
Definition: pg_regress.c:116
static int max_connections
Definition: pg_regress.c:82
static int fail_ignore_count
Definition: pg_regress.c:118
static int fail_count
Definition: pg_regress.c:117
#define strerror
Definition: port.h:229
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
struct _stringlist * next
Definition: pg_regress.h:27
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define _(x)
Definition: elog.c:89
static void wait_for_tests(PID_TYPE *pids, int *statuses, instr_time *stoptimes, char **names, int num_tests)
Definition: pg_regress.c:1555

◆ run_single_test()

static void run_single_test ( const char *  test,
test_start_function  startfunc,
postprocess_result_function  postfunc 
)
static

Definition at line 1905 of file pg_regress.c.

References _, fail_count, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, log_child_failure(), _stringlist::next, PID_TYPE, printf, results_differ(), status(), status_end(), _stringlist::str, success_count, and wait_for_tests().

Referenced by regression_main().

1907 {
1908  PID_TYPE pid;
1909  instr_time starttime;
1910  instr_time stoptime;
1911  int exit_status;
1912  _stringlist *resultfiles = NULL;
1913  _stringlist *expectfiles = NULL;
1914  _stringlist *tags = NULL;
1915  _stringlist *rl,
1916  *el,
1917  *tl;
1918  bool differ = false;
1919 
1920  status(_("test %-28s ... "), test);
1921  pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
1922  INSTR_TIME_SET_CURRENT(starttime);
1923  wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
1924 
1925  /*
1926  * Advance over all three lists simultaneously.
1927  *
1928  * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1929  * but if there are tags, the tag list has the same length as the other
1930  * two lists.
1931  */
1932  for (rl = resultfiles, el = expectfiles, tl = tags;
1933  rl != NULL; /* rl and el have the same length */
1934  rl = rl->next, el = el->next,
1935  tl = tl ? tl->next : NULL)
1936  {
1937  bool newdiff;
1938 
1939  if (postfunc)
1940  (*postfunc) (rl->str);
1941  newdiff = results_differ(test, rl->str, el->str);
1942  if (newdiff && tl)
1943  {
1944  printf("%s ", tl->str);
1945  }
1946  differ |= newdiff;
1947  }
1948 
1949  if (differ)
1950  {
1951  status(_("FAILED"));
1952  fail_count++;
1953  }
1954  else
1955  {
1956  status(_("ok ")); /* align with FAILED */
1957  success_count++;
1958  }
1959 
1960  if (exit_status != 0)
1961  log_child_failure(exit_status);
1962 
1963  INSTR_TIME_SUBTRACT(stoptime, starttime);
1964  status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptime));
1965 
1966  status_end();
1967 }
static void test(void)
static void log_child_failure(int exitstatus)
Definition: pg_regress.c:1627
char * str
Definition: pg_regress.h:26
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
struct timeval instr_time
Definition: instr_time.h:150
static void status_end(void)
Definition: pg_regress.c:248
#define PID_TYPE
Definition: pg_regress.h:14
#define printf(...)
Definition: port.h:222
static bool results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
Definition: pg_regress.c:1405
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
static int success_count
Definition: pg_regress.c:116
static int fail_count
Definition: pg_regress.c:117
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
struct _stringlist * next
Definition: pg_regress.h:27
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define _(x)
Definition: elog.c:89
static void wait_for_tests(PID_TYPE *pids, int *statuses, instr_time *stoptimes, char **names, int num_tests)
Definition: pg_regress.c:1555

◆ spawn_process()

PID_TYPE spawn_process ( const char *  cmdline)

Definition at line 1190 of file pg_regress.c.

References _, fprintf, logfile, progname, psprintf(), shellprog, generate_unaccent_rules::stdout, and strerror.

Referenced by ecpg_start_test(), isolation_start_test(), psql_start_test(), and regression_main().

1191 {
1192 #ifndef WIN32
1193  pid_t pid;
1194 
1195  /*
1196  * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
1197  * ... does anyone still care about systems where that doesn't work?
1198  */
1199  fflush(stdout);
1200  fflush(stderr);
1201  if (logfile)
1202  fflush(logfile);
1203 
1204  pid = fork();
1205  if (pid == -1)
1206  {
1207  fprintf(stderr, _("%s: could not fork: %s\n"),
1208  progname, strerror(errno));
1209  exit(2);
1210  }
1211  if (pid == 0)
1212  {
1213  /*
1214  * In child
1215  *
1216  * Instead of using system(), exec the shell directly, and tell it to
1217  * "exec" the command too. This saves two useless processes per
1218  * parallel test case.
1219  */
1220  char *cmdline2;
1221 
1222  cmdline2 = psprintf("exec %s", cmdline);
1223  execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
1224  fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
1225  progname, shellprog, strerror(errno));
1226  _exit(1); /* not exit() here... */
1227  }
1228  /* in parent */
1229  return pid;
1230 #else
1231  PROCESS_INFORMATION pi;
1232  char *cmdline2;
1233  HANDLE restrictedToken;
1234  const char *comspec;
1235 
1236  /* Find CMD.EXE location using COMSPEC, if it's set */
1237  comspec = getenv("COMSPEC");
1238  if (comspec == NULL)
1239  comspec = "CMD";
1240 
1241  memset(&pi, 0, sizeof(pi));
1242  cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
1243 
1244  if ((restrictedToken =
1245  CreateRestrictedProcess(cmdline2, &pi)) == 0)
1246  exit(2);
1247 
1248  CloseHandle(pi.hThread);
1249  return pi.hProcess;
1250 #endif
1251 }
static char * shellprog
Definition: pg_regress.c:58
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static const char * progname
Definition: pg_regress.c:100
static FILE * logfile
Definition: pg_regress.c:102
#define fprintf
Definition: port.h:220
#define strerror
Definition: port.h:229
#define _(x)
Definition: elog.c:89

◆ split_to_stringlist()

static void split_to_stringlist ( const char *  s,
const char *  delim,
_stringlist **  listhead 
)
static

Definition at line 193 of file pg_regress.c.

References add_stringlist_item(), free, and pg_strdup().

Referenced by regression_main().

194 {
195  char *sc = pg_strdup(s);
196  char *token = strtok(sc, delim);
197 
198  while (token)
199  {
200  add_stringlist_item(listhead, token);
201  token = strtok(NULL, delim);
202  }
203  free(sc);
204 }
static void static void static void void add_stringlist_item(_stringlist **listhead, const char *str)
Definition: pg_regress.c:157
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define free(a)
Definition: header.h:65

◆ status()

static void status ( const char *  fmt,
  ... 
)
static

Definition at line 227 of file pg_regress.c.

References logfile, generate_unaccent_rules::stdout, and vfprintf.

Referenced by _bt_first(), _bt_parallel_seize(), _bt_readnextpage(), _bt_steppage(), apw_start_leader_worker(), AtAbort_Portals(), AtCleanup_Portals(), AtEOSubXact_RelationCache(), AtEOXact_RelationCache(), AtPrepare_Locks(), AtSubAbort_Portals(), AtSubCleanup_Portals(), AtSubCommit_Portals(), BackendInitialize(), BaseBackup(), be_lo_lseek(), be_lo_lseek64(), bf_check_supported_key_len(), check_worker_status(), CheckForSessionAndXactLocks(), CheckMD5Auth(), ClientAuthentication(), compute_new_xmax_infomask(), dblink_get_connections(), DestroyPartitionDirectory(), do_kill(), do_lo_export(), do_lo_unlink(), DoesMultiXactIdConflict(), ecpg_process_output(), ecpg_store_result(), exec_command(), exec_command_crosstabview(), exec_command_d(), exec_command_edit(), exec_command_ef_ev(), exec_command_g(), exec_command_gdesc(), exec_command_gexec(), exec_command_gset(), exec_command_lo(), exec_command_quit(), exec_command_sf_sv(), exec_command_write(), executeQueryOrDie(), forget_invalid_pages(), forget_invalid_pages_db(), ForgetPortalSnapshots(), FreezeMultiXactId(), get_collation_actual_version(), get_xid_status(), GetLockmodeName(), GetMultiXactIdHintBits(), HandleSlashCmds(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), HoldPinnedPortals(), InvalidateAttoptCacheCallback(), InvalidateOprCacheCallBack(), InvalidateOprProofCacheCallBack(), InvalidateShippableCacheCallback(), InvalidateTableSpaceCacheCallback(), InvalidateTSCacheCallBack(), libpqrcv_connect(), ListenToWorkers(), lo_read(), lo_write(), LockReassignCurrentOwner(), LockReleaseAll(), LockReleaseCurrentOwner(), LockReleaseSession(), log_child_failure(), logicalrep_partmap_invalidate_cb(), logicalrep_relmap_invalidate_cb(), MultiXactIdCreateFromMembers(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), mxid_to_string(), parallel_restore(), parseServiceInfo(), parseWorkerResponse(), pg_collation_actual_version(), pg_cryptohash_final(), pg_cryptohash_init(), pg_cryptohash_update(), pg_hmac_final(), pg_hmac_init(), pg_hmac_update(), pg_newlocale_from_collation(), pg_prepared_xact(), pg_start_backup(), pg_stop_backup(), pg_stop_backup_v2(), pg_xact_status(), pgrowlocks(), PortalErrorCleanup(), PortalHashTableDeleteAll(), PostmasterMain(), PostPrepare_Locks(), pqFunctionCall3(), pqGetline3(), PQmakeEmptyPGresult(), PQresetPoll(), PQresStatus(), PQsetClientEncoding(), PreCommit_Portals(), RecordNewMultiXact(), rel_sync_cache_publication_cb(), RelationCacheInitializePhase3(), RelationCacheInvalidate(), RelfilenodeMapInvalidateCallback(), RememberToFreeTupleDescAtEOX(), restore_toc_entry(), run_reindex_command(), run_schedule(), run_single_test(), run_vacuum_command(), sepgsql_client_auth(), SerializeUncommittedEnums(), shm_mq_counterparty_gone(), shm_mq_wait_internal(), smgrcloseall(), StandbyReleaseAllLocks(), StandbyReleaseOldLocks(), str_numth(), test_config_settings(), test_pipelined_insert(), ThereAreNoReadyPortals(), TransactionGroupUpdateXidStatus(), TransactionIdGetStatus(), TypeCacheOpcCallback(), TypeCacheRelCallback(), TypeCacheTypCallback(), uuid_generate_internal(), varstr_abbrev_convert(), varstr_cmp(), varstrfastcmp_locale(), wait_for_postmaster(), wait_for_tests(), WaitForBackgroundWorkerShutdown(), WaitForBackgroundWorkerStartup(), WaitForCommands(), WaitForParallelWorkersToAttach(), WaitForParallelWorkersToExit(), WaitForReplicationWorkerAttach(), WaitForTerminatingWorkers(), worker_spi_launch(), write_relcache_init_file(), and XLogCheckInvalidPages().

228 {
229  va_list ap;
230 
231  va_start(ap, fmt);
232  vfprintf(stdout, fmt, ap);
233  fflush(stdout);
234  va_end(ap);
235 
236  if (logfile)
237  {
238  va_start(ap, fmt);
239  vfprintf(logfile, fmt, ap);
240  va_end(ap);
241  }
242 }
static FILE * logfile
Definition: pg_regress.c:102
#define vfprintf
Definition: port.h:219

◆ status_end()

static void status_end ( void  )
static

Definition at line 248 of file pg_regress.c.

References fprintf, logfile, and generate_unaccent_rules::stdout.

Referenced by run_schedule(), and run_single_test().

249 {
250  fprintf(stdout, "\n");
251  fflush(stdout);
252  if (logfile)
253  fprintf(logfile, "\n");
254 }
static FILE * logfile
Definition: pg_regress.c:102
#define fprintf
Definition: port.h:220

◆ stop_postmaster()

static void stop_postmaster ( void  )
static

Definition at line 260 of file pg_regress.c.

References _, Assert, bindir, buf, fprintf, MAXPGPATH, mkdtemp(), port, postmaster_running, pqsignal(), progname, psprintf(), SIG_DFL, SIGHUP, SIGPIPE, snprintf, generate_unaccent_rules::stdout, strerror, temp_instance, and UNIXSOCK_PATH.

Referenced by regression_main().

261 {
262  if (postmaster_running)
263  {
264  /* We use pg_ctl to issue the kill and wait for stop */
265  char buf[MAXPGPATH * 2];
266  int r;
267 
268  /* On Windows, system() seems not to force fflush, so... */
269  fflush(stdout);
270  fflush(stderr);
271 
272  snprintf(buf, sizeof(buf),
273  "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
274  bindir ? bindir : "",
275  bindir ? "/" : "",
276  temp_instance);
277  r = system(buf);
278  if (r != 0)
279  {
280  fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
281  progname, r);
282  _exit(2); /* not exit(), that could be recursive */
283  }
284 
285  postmaster_running = false;
286  }
287 }
static const char * progname
Definition: pg_regress.c:100
static bool postmaster_running
Definition: pg_regress.c:114
#define fprintf
Definition: port.h:220
static char * temp_instance
Definition: pg_regress.c:87
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:68
char * bindir
Definition: pg_regress.c:79
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89

◆ string_matches_pattern()

static bool string_matches_pattern ( const char *  str,
const char *  pattern 
)
static

Definition at line 379 of file pg_regress.c.

Referenced by load_resultmap().

380 {
381  while (*str && *pattern)
382  {
383  if (*pattern == '.' && pattern[1] == '*')
384  {
385  pattern += 2;
386  /* Trailing .* matches everything. */
387  if (*pattern == '\0')
388  return true;
389 
390  /*
391  * Otherwise, scan for a text position at which we can match the
392  * rest of the pattern.
393  */
394  while (*str)
395  {
396  /*
397  * Optimization to prevent most recursion: don't recurse
398  * unless first pattern char might match this text char.
399  */
400  if (*str == *pattern || *pattern == '.')
401  {
402  if (string_matches_pattern(str, pattern))
403  return true;
404  }
405 
406  str++;
407  }
408 
409  /*
410  * End of text with no match.
411  */
412  return false;
413  }
414  else if (*pattern != '.' && *str != *pattern)
415  {
416  /*
417  * Not the single-character wildcard and no explicit match? Then
418  * time to quit...
419  */
420  return false;
421  }
422 
423  str++;
424  pattern++;
425  }
426 
427  if (*pattern == '\0')
428  return true; /* end of pattern, so declare match */
429 
430  /* End of input string. Do we have matching pattern remaining? */
431  while (*pattern == '.' && pattern[1] == '*')
432  pattern += 2;
433  if (*pattern == '\0')
434  return true; /* end of pattern, so declare match */
435 
436  return false;
437 }
static bool string_matches_pattern(const char *str, const char *pattern)
Definition: pg_regress.c:379

◆ wait_for_tests()

static void wait_for_tests ( PID_TYPE pids,
int *  statuses,
instr_time stoptimes,
char **  names,
int  num_tests 
)
static

Definition at line 1555 of file pg_regress.c.

References _, fprintf, free, i, INSTR_TIME_SET_CURRENT, INVALID_PID, pg_malloc(), PID_TYPE, status(), and strerror.

Referenced by run_schedule(), and run_single_test().

1557 {
1558  int tests_left;
1559  int i;
1560 
1561 #ifdef WIN32
1562  PID_TYPE *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
1563 
1564  memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1565 #endif
1566 
1567  tests_left = num_tests;
1568  while (tests_left > 0)
1569  {
1570  PID_TYPE p;
1571 
1572 #ifndef WIN32
1573  int exit_status;
1574 
1575  p = wait(&exit_status);
1576 
1577  if (p == INVALID_PID)
1578  {
1579  fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
1580  strerror(errno));
1581  exit(2);
1582  }
1583 #else
1584  DWORD exit_status;
1585  int r;
1586 
1587  r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1588  if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1589  {
1590  fprintf(stderr, _("failed to wait for subprocesses: error code %lu\n"),
1591  GetLastError());
1592  exit(2);
1593  }
1594  p = active_pids[r - WAIT_OBJECT_0];
1595  /* compact the active_pids array */
1596  active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1597 #endif /* WIN32 */
1598 
1599  for (i = 0; i < num_tests; i++)
1600  {
1601  if (p == pids[i])
1602  {
1603 #ifdef WIN32
1604  GetExitCodeProcess(pids[i], &exit_status);
1605  CloseHandle(pids[i]);
1606 #endif
1607  pids[i] = INVALID_PID;
1608  statuses[i] = (int) exit_status;
1609  INSTR_TIME_SET_CURRENT(stoptimes[i]);
1610  if (names)
1611  status(" %s", names[i]);
1612  tests_left--;
1613  break;
1614  }
1615  }
1616  }
1617 
1618 #ifdef WIN32
1619  free(active_pids);
1620 #endif
1621 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define PID_TYPE
Definition: pg_regress.h:14
#define fprintf
Definition: port.h:220
#define INVALID_PID
Definition: pg_regress.h:15
#define free(a)
Definition: header.h:65
#define strerror
Definition: port.h:229
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define _(x)
Definition: elog.c:89

Variable Documentation

◆ basic_diff_opts

const char* basic_diff_opts = ""

Definition at line 67 of file pg_regress.c.

Referenced by results_differ().

◆ bindir

char* bindir = PGBINDIR

Definition at line 79 of file pg_regress.c.

Referenced by psql_command(), psql_start_test(), regression_main(), and stop_postmaster().

◆ config_auth_datadir

char* config_auth_datadir = NULL
static

Definition at line 97 of file pg_regress.c.

Referenced by regression_main().

◆ dblist

◆ debug

bool debug = false

Definition at line 76 of file pg_regress.c.

Referenced by regression_main().

◆ difffilename

char* difffilename
static

Definition at line 103 of file pg_regress.c.

Referenced by open_result_files(), regression_main(), and results_differ().

◆ dlpath

char* dlpath = PKGLIBDIR
static

Definition at line 94 of file pg_regress.c.

Referenced by convert_sourcefiles_in(), and regression_main().

◆ encoding

char* encoding = NULL
static

Definition at line 84 of file pg_regress.c.

Referenced by create_database(), initialize_environment(), and regression_main().

◆ extra_tests

_stringlist* extra_tests = NULL
static

Definition at line 86 of file pg_regress.c.

◆ extraroles

_stringlist* extraroles = NULL
static

Definition at line 96 of file pg_regress.c.

◆ fail_count

int fail_count = 0
static

Definition at line 117 of file pg_regress.c.

Referenced by regression_main(), run_schedule(), and run_single_test().

◆ fail_ignore_count

int fail_ignore_count = 0
static

Definition at line 118 of file pg_regress.c.

Referenced by regression_main(), and run_schedule().

◆ host_platform

char* host_platform = HOST_TUPLE

Definition at line 55 of file pg_regress.c.

Referenced by load_resultmap().

◆ hostname

char* hostname = NULL
static

Definition at line 91 of file pg_regress.c.

Referenced by initialize_environment(), pqPacketSend(), and regression_main().

◆ inputdir

◆ launcher

char* launcher = NULL

Definition at line 80 of file pg_regress.c.

Referenced by isolation_start_test(), psql_start_test(), and regression_main().

◆ loadextension

_stringlist* loadextension = NULL
static

Definition at line 81 of file pg_regress.c.

◆ logfile

FILE* logfile
static

◆ logfilename

char* logfilename
static

Definition at line 101 of file pg_regress.c.

Referenced by open_result_files(), and regression_main().

◆ max_concurrent_tests

int max_concurrent_tests = 0
static

Definition at line 83 of file pg_regress.c.

Referenced by regression_main(), and run_schedule().

◆ max_connections

int max_connections = 0
static

Definition at line 82 of file pg_regress.c.

Referenced by regression_main(), and run_schedule().

◆ nolocale

bool nolocale = false
static

Definition at line 89 of file pg_regress.c.

Referenced by create_database(), initialize_environment(), and regression_main().

◆ outputdir

◆ port

◆ port_specified_by_user

bool port_specified_by_user = false
static

Definition at line 93 of file pg_regress.c.

Referenced by regression_main().

◆ postmaster_pid

PID_TYPE postmaster_pid = INVALID_PID
static

Definition at line 113 of file pg_regress.c.

Referenced by regression_main().

◆ postmaster_running

bool postmaster_running = false
static

Definition at line 114 of file pg_regress.c.

Referenced by regression_main(), and stop_postmaster().

◆ pretty_diff_opts

const char* pretty_diff_opts = "-U3"

Definition at line 68 of file pg_regress.c.

Referenced by regression_main(), and results_differ().

◆ progname

◆ resultmap

_resultmap* resultmap = NULL
static

Definition at line 111 of file pg_regress.c.

Referenced by load_resultmap().

◆ schedulelist

_stringlist* schedulelist = NULL
static

Definition at line 85 of file pg_regress.c.

◆ shellprog

char* shellprog = SHELLPROG
static

Definition at line 58 of file pg_regress.c.

Referenced by spawn_process().

◆ sockdir

const char* sockdir
static

Definition at line 104 of file pg_regress.c.

Referenced by initialize_environment(), and regression_main().

◆ success_count

int success_count = 0
static

Definition at line 116 of file pg_regress.c.

Referenced by regression_main(), run_schedule(), and run_single_test().

◆ temp_configs

_stringlist* temp_configs = NULL
static

Definition at line 88 of file pg_regress.c.

◆ temp_instance

char* temp_instance = NULL
static

Definition at line 87 of file pg_regress.c.

Referenced by initialize_environment(), regression_main(), and stop_postmaster().

◆ use_existing

bool use_existing = false
static

Definition at line 90 of file pg_regress.c.

Referenced by regression_main().

◆ user