On 4/7/21 5:06 PM, Alvaro Herrera wrote:
> On 2021-Apr-07, Andrew Dunstan wrote:
>
>> Oh, you want to roll them all up into one file? That could work. It's a
>> bit frowned on by perl purists, but I've done similar (see PGBuild/SCM.pm).
> Ah! Yeah, pretty much exactly like that, including the "no critic" flag ...
>
OK, here's an attempt at that. There is almost certainly more work to
do, but it does pass my basic test (set up a node, start it, talk to it,
shut it down) on some very old versions down as low as 7.2.
Is this is more to your liking?
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index e26b2b3f30..e48379e3fd 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -127,6 +127,11 @@ INIT
$last_port_assigned = int(rand() * 16384) + 49152;
}
+# Current dev version, for which we have no subclass
+# When a new stable branch is made this and the subclass hierarchy below
+# need to be adjusted.
+my $devtip = 14;
+
=pod
=head1 METHODS
@@ -347,9 +352,12 @@ about this node.
sub info
{
my ($self) = @_;
+ my $varr = $self->{_pg_version};
+ my $vstr = join('.', @$varr) if ref $varr;
my $_info = '';
open my $fh, '>', \$_info or die;
print $fh "Name: " . $self->name . "\n";
+ print $fh "Version: " . $vstr . "\n" if $vstr;
print $fh "Data directory: " . $self->data_dir . "\n";
print $fh "Backup directory: " . $self->backup_dir . "\n";
print $fh "Archive directory: " . $self->archive_dir . "\n";
@@ -797,7 +805,7 @@ sub start
# Note: We set the cluster_name here, not in postgresql.conf (in
# sub init) so that it does not get copied to standbys.
- $ret = TestLib::system_log('pg_ctl', '-D', $self->data_dir, '-l',
+ $ret = TestLib::system_log('pg_ctl', '-w', '-D', $self->data_dir, '-l',
$self->logfile, '-o', "--cluster-name=$name", 'start');
if ($ret != 0)
@@ -911,7 +919,7 @@ sub restart
print "### Restarting node \"$name\"\n";
- TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
+ TestLib::system_or_bail('pg_ctl', '-w', '-D', $pgdata, '-l', $logfile,
'restart');
$self->_update_pid(1);
@@ -1196,9 +1204,188 @@ sub get_new_node
# Add node to list of nodes
push(@all_nodes, $node);
+ # Get information about the node
+ $node->_read_pg_config;
+
+ # bless the object into the appropriate subclass,
+ # according to the found version
+ if (ref $node->{_pg_version} && $node->{_pg_version}->[0] <= $devtip )
+ {
+ my $maj = $node->{_pg_version}->[0];
+ my $subclass = __PACKAGE__ . "V_$maj";
+ if ($maj < 10)
+ {
+ $maj = $node->{_pg_version}->[1];
+ $subclass .= "_$maj";
+ }
+ bless $node, $subclass;
+ }
+
return $node;
}
+# Private routine to run the pg_config binary found in our environment (or in
+# our install_path, if we have one), and collect all fields that matter to us.
+#
+sub _read_pg_config
+{
+ my ($self) = @_;
+ my $inst = $self->{_install_path};
+ my $pg_config = "pg_config";
+
+ if (defined $inst)
+ {
+ # If the _install_path is invalid, our PATH variables might find an
+ # unrelated pg_config executable elsewhere. Sanity check the
+ # directory.
+ BAIL_OUT("directory not found: $inst")
+ unless -d $inst;
+
+ # If the directory exists but is not the root of a postgresql
+ # installation, or if the user configured using
+ # --bindir=$SOMEWHERE_ELSE, we're not going to find pg_config, so
+ # complain about that, too.
+ $pg_config = "$inst/bin/pg_config";
+ BAIL_OUT("pg_config not found: $pg_config")
+ unless -e $pg_config;
+ BAIL_OUT("pg_config not executable: $pg_config")
+ unless -x $pg_config;
+
+ # Leave $pg_config install_path qualified, to be sure we get the right
+ # version information, below, or die trying
+ }
+
+ local %ENV = $self->_get_env();
+
+ # We only want the version field
+ open my $fh, "-|", $pg_config, "--version"
+ or
+ BAIL_OUT("$pg_config failed: $!");
+ my $version_line = <$fh>;
+ close $fh or die;
+
+ $self->{_pg_version} = _pg_version_array($version_line);
+
+ BAIL_OUT("could not parse pg_config --version output: $version_line")
+ unless defined $self->{_pg_version};
+}
+
+# Private routine which returns a reference to an array of integers
+# representing the pg_version of a PostgresNode, or parsed from a postgres
+# version string. Development versions (such as "14devel") are converted
+# to an array with minus one as the last value (such as [14, -1]).
+#
+# For idempotency, will return the argument back to the caller if handed an
+# array reference.
+sub _pg_version_array
+{
+ my ($arg) = @_;
+
+ # accept node arguments
+ return _pg_version_array($arg->{_pg_version})
+ if (blessed($arg) && $arg->isa("PostgresNode"));
+
+ # idempotency
+ return $arg
+ if (ref($arg) && ref($arg) =~ /ARRAY/);
+
+ # Accept standard formats, in case caller has handed us the output of a
+ # postgres command line tool
+ $arg = $1
+ if ($arg =~ m/\(?PostgreSQL\)? (\d+(?:\.\d+)*(?:devel)?)/);
+
+ # Split into an array
+ my @result = split(/\./, $arg);
+
+ # Treat development versions as having a minor/micro version one less than
+ # the first released version of that branch.
+ if ($result[$#result] =~ m/^(\d+)devel$/)
+ {
+ pop(@result);
+ push(@result, $1, -1);
+ }
+
+ # Return an array reference
+ return \@result;
+}
+
+# Private routine which compares the _pg_version_array obtained for the two
+# arguments and returns -1, 0, or 1, allowing comparison between two
+# PostgresNodes or a PostgresNode and a version string.
+#
+# To achieve intuitive behavior when comparing a PostgresNode against a version
+# string, "X" is equal to "X.Y" for any value of Y. This allows calls like
+#
+# $node->newer_than_version("14")
+#
+# to return true starting with "15devel", but false for "14devel", "14.0",
+# "14.1", etc. It also allows
+#
+# $node->at_least_version("14")
+#
+# to work for a node of version "14devel", where comparing against "14.0" would
+# fail.
+#
+sub _pg_version_cmp
+{
+ my ($a, $b) = @_;
+
+ $a = _pg_version_array($a);
+ $b = _pg_version_array($b);
+
+ for (my $idx = 0; ; $idx++)
+ {
+ return 0 unless (defined $a->[$idx] && defined $b->[$idx]);
+ return $a->[$idx] <=> $b->[$idx]
+ if ($a->[$idx] <=> $b->[$idx]);
+ }
+}
+
+=pod
+
+=item $node->older_than_version(other)
+
+Returns whether this node's postgres version is older than "other", which can be
+either another PostgresNode or a version string.
+
+=cut
+
+sub older_than_version
+{
+ my ($node, $pg_version) = @_;
+ return _pg_version_cmp($node->{_pg_version}, $pg_version) < 0;
+}
+
+=pod
+
+=item $node->newer_than_version(other)
+
+Returns whether this node's postgres version is newer than "other", which can
+be either another PostgresNode or a version string.
+
+=cut
+
+sub newer_than_version
+{
+ my ($node, $pg_version) = @_;
+ return _pg_version_cmp($node->{_pg_version}, $pg_version) > 0;
+}
+
+=pod
+
+=item $node->at_least_version(other)
+
+Returns whether this node's postgres version is at least as new as "other",
+which can be either another PostgresNode or a version string.
+
+=cut
+
+sub at_least_version
+{
+ my ($node, $pg_version) = @_;
+ return _pg_version_cmp($node->{_pg_version}, $pg_version) >= 0;
+}
+
# Private routine to return a copy of the environment with the PATH and
# (DY)LD_LIBRARY_PATH correctly set when there is an install path set for
# the node.
@@ -1271,6 +1458,28 @@ sub _get_env
return (%inst_env);
}
+# Private routine to get an installation path qualified command.
+#
+# IPC::Run maintains a cache, %cmd_cache, mapping commands to paths. Tests
+# which use nodes spanning more than one postgres installation path need to
+# avoid confusing which installation's binaries get run. Setting $ENV{PATH} is
+# insufficient, as IPC::Run does not check to see if the path has changed since
+# caching a command.
+sub installed_command
+{
+ my ($self, $cmd) = @_;
+
+ # Nodes using alternate installation locations use their installation's
+ # bin/ directory explicitly
+ return join('/', $self->{_install_path}, 'bin', $cmd)
+ if defined $self->{_install_path};
+
+ # Nodes implicitly using the default installation location rely on IPC::Run
+ # to find the right binary, which should not cause %cmd_cache confusion,
+ # because no nodes with other installation paths do it that way.
+ return $cmd;
+}
+
=pod
=item get_free_port()
@@ -1516,6 +1725,14 @@ is set to true if the psql call times out.
If set, use this as the connection string for the connection to the
backend.
+=item host => B<value>
+
+If this parameter is set, this host is used for the connection attempt.
+
+=item port => B<port>
+
+If this parameter is set, this port is used for the connection attempt.
+
=item replication => B<value>
If set, add B<replication=value> to the conninfo string.
@@ -1568,7 +1785,23 @@ sub psql
}
$psql_connstr .= defined $replication ? " replication=$replication" : "";
- my @psql_params = ('psql', '-XAtq', '-d', $psql_connstr, '-f', '-');
+ my @no_password = ('-w') if ($params{no_password});
+
+ my @host = ('-h', $params{host})
+ if defined $params{host};
+ my @port = ('-p', $params{port})
+ if defined $params{port};
+
+ my @psql_params = (
+ $self->installed_command('psql'),
+ '-XAtq',
+ @no_password,
+ @host,
+ @port,
+ '-d',
+ $psql_connstr,
+ '-f',
+ '-');
# If the caller wants an array and hasn't passed stdout/stderr
# references, allocate temporary ones to capture them so we
@@ -1754,7 +1987,7 @@ sub background_psql
my $replication = $params{replication};
my @psql_params = (
- 'psql',
+ $self->installed_command('psql'),
'-XAtq',
'-d',
$self->connstr($dbname)
@@ -1831,7 +2064,11 @@ sub interactive_psql
local %ENV = $self->_get_env();
- my @psql_params = ('psql', '-XAt', '-d', $self->connstr($dbname));
+ my @psql_params = (
+ $self->installed_command('psql'),
+ '-XAt',
+ '-d',
+ $self->connstr($dbname));
push @psql_params, @{ $params{extra_params} }
if defined $params{extra_params};
@@ -1888,6 +2125,14 @@ If given, it must be an array reference containing a list of regular
expressions that must NOT match against the server log. They will be
passed to C<Test::More::unlike()>.
+=item host => B<value>
+
+If this parameter is set, this host is used for the connection attempt.
+
+=item port => B<port>
+
+If this parameter is set, this port is used for the connection attempt.
+
=back
=cut
@@ -1938,7 +2183,9 @@ sub connect_ok
my ($ret, $stdout, $stderr) = $self->psql(
'postgres',
$sql,
- extra_params => ['-w'],
+ no_password => 1,
+ host => $params{host},
+ port => $params{port},
connstr => "$connstr",
on_error_stop => 0);
@@ -2067,7 +2314,13 @@ sub poll_query_until
$expected = 't' unless defined($expected); # default value
- my $cmd = [ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ];
+ my $cmd = [
+ $self->installed_command('psql'),
+ '-XAt',
+ '-c',
+ $query,
+ '-d',
+ $self->connstr($dbname) ];
my ($stdout, $stderr);
my $max_attempts = 180 * 10;
my $attempts = 0;
@@ -2489,7 +2742,8 @@ sub pg_recvlogical_upto
croak 'endpos must be specified' unless defined($endpos);
my @cmd = (
- 'pg_recvlogical', '-S', $slot_name, '--dbname',
+ $self->installed_command('pg_recvlogical'),
+ '-S', $slot_name, '--dbname',
$self->connstr($dbname));
push @cmd, '--endpos', $endpos;
push @cmd, '-f', '-', '--no-loop', '--start';
@@ -2556,4 +2810,738 @@ sub pg_recvlogical_upto
=cut
+package PostgresNodeV_13; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNode);
+
+package PostgresNodeV_12; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_13);
+
+package PostgresNodeV_11; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_12);
+
+package PostgresNodeV_10; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_11);
+
+package PostgresNodeV_9_6; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_10);
+
+package PostgresNodeV_9_5; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_6);
+
+package PostgresNodeV_9_4; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_5);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ $params{allows_streaming} = 0 unless defined $params{allows_streaming};
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my @initdb_nosync_opt = ('-N');
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt, @initdb_nosync_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "restart_after_crash = off\n";
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ # XXX Neutralize any stats_temp_directory in TEMP_CONFIG. Nodes running
+ # concurrently must not share a stats_temp_directory.
+ print $conf "stats_temp_directory = 'pg_stat_tmp'\n";
+
+ if ($params{allows_streaming})
+ {
+ if ($params{allows_streaming} eq "logical")
+ {
+ print $conf "wal_level = logical\n";
+ }
+ else
+ {
+ print $conf "wal_level = replica\n";
+ }
+ print $conf "max_wal_senders = 10\n";
+ print $conf "max_replication_slots = 10\n";
+ print $conf "wal_log_hints = on\n";
+ print $conf "hot_standby = on\n";
+ # conservative settings to ensure we can run multiple postmasters:
+ print $conf "shared_buffers = 1MB\n";
+ print $conf "max_connections = 10\n";
+ # limit disk space consumption, too:
+ print $conf "max_wal_size = 128MB\n";
+ }
+ else
+ {
+ print $conf "wal_level = minimal\n";
+ print $conf "max_wal_senders = 0\n";
+ }
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directories = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directories = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->set_replication_conf if $params{allows_streaming};
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+sub start
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $name = $self->name;
+ my $ret;
+
+ BAIL_OUT("node \"$name\" is already running") if defined $self->{_pid};
+
+ print("### Starting node \"$name\"\n");
+
+ # Temporarily unset PGAPPNAME so that the server doesn't
+ # inherit it. Otherwise this could affect libpqwalreceiver
+ # connections in confusing ways.
+ local %ENV = $self->_get_env(PGAPPNAME => undef);
+
+ $ret = TestLib::system_log('pg_ctl', '-w', '-D', $self->data_dir, '-l',
+ $self->logfile,
+ 'start');
+
+ if ($ret != 0)
+ {
+ print "# pg_ctl start failed; logfile:\n";
+ print TestLib::slurp_file($self->logfile);
+ BAIL_OUT("pg_ctl start failed") unless $params{fail_ok};
+ return 0;
+ }
+
+ $self->_update_pid(1);
+ return 1;
+}
+
+package PostgresNodeV_9_3; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_4);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported");
+
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ # initdb option -N/--no-sync was added in version 9.3. If the server
+ # version is new enough, we can use this option to make the tests run
+ # faster by not waiting for the disks to sync.
+ my @initdb_nosync_opt = ('-N');
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt, @initdb_nosync_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ # "restart_after_crash" was introduced in version 9.1. Older versions
+ # always restart after crash.
+ print $conf "restart_after_crash = off\n";
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ # XXX Neutralize any stats_temp_directory in TEMP_CONFIG. Nodes running
+ # concurrently must not share a stats_temp_directory.
+ print $conf "stats_temp_directory = 'pg_stat_tmp'\n";
+
+ print $conf "wal_level = minimal\n";
+ print $conf "max_wal_senders = 0\n";
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directories = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directories = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+package PostgresNodeV_9_2; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_3);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "restart_after_crash = off\n";
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ # XXX Neutralize any stats_temp_directory in TEMP_CONFIG. Nodes running
+ # concurrently must not share a stats_temp_directory.
+ print $conf "stats_temp_directory = 'pg_stat_tmp'\n";
+
+ print $conf "wal_level = minimal\n";
+ print $conf "max_wal_senders = 0\n";
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+sub init_from_backup
+{
+ my ($self, $root_node, $backup_name, %params) = @_;
+ my $backup_path = $root_node->backup_dir . '/' . $backup_name;
+ my $host = $self->host;
+ my $port = $self->port;
+ my $node_name = $self->name;
+ my $root_name = $root_node->name;
+
+ BAIL_OUT("Server version too old: 'has_streaming' option not supported")
+ if ($params{has_streaming});
+
+ $params{has_restoring} = 0 unless defined $params{has_restoring};
+ $params{standby} = 1 unless defined $params{standby};
+
+ print
+ "# Initializing node \"$node_name\" from backup \"$backup_name\" of node \"$root_name\"\n";
+# croak "Backup \"$backup_name\" does not exist at $backup_path"
+# unless -d $backup_path;
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my $data_path = $self->data_dir;
+ if (defined $params{tar_program})
+ {
+ mkdir($data_path);
+ TestLib::system_or_bail($params{tar_program}, 'xf',
+ $backup_path . '/base.tar',
+ '-C', $data_path);
+ TestLib::system_or_bail($params{tar_program}, 'xf',
+ $backup_path . '/pg_wal.tar',
+ '-C', $data_path . '/pg_wal');
+ }
+ else
+ {
+ rmdir($data_path);
+ RecursiveCopy::copypath($backup_path, $data_path);
+ }
+ chmod(0700, $data_path);
+
+ # Base configuration for this node
+ $self->append_conf(
+ 'postgresql.conf',
+ qq(
+port = $port
+));
+ if ($use_tcp)
+ {
+ $self->append_conf('postgresql.conf', "listen_addresses = '$host'");
+ }
+ else
+ {
+ $self->append_conf('postgresql.conf',
+ "unix_socket_directory = '$host'");
+ }
+ $self->enable_restoring($root_node, $params{standby})
+ if $params{has_restoring};
+ return;
+}
+
+package PostgresNodeV_9_1; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_2);
+
+package PostgresNodeV_9_0; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_1);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ # XXX Neutralize any stats_temp_directory in TEMP_CONFIG. Nodes running
+ # concurrently must not share a stats_temp_directory.
+ print $conf "stats_temp_directory = 'pg_stat_tmp'\n";
+
+ print $conf "wal_level = minimal\n";
+ print $conf "max_wal_senders = 0\n";
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+sub backup
+{
+ BAIL_OUT("Server version too old for backup function");
+}
+
+sub init_from_backup
+{
+ BAIL_OUT("Server version too old for init_from_backup function");
+}
+
+package PostgresNodeV_8_4; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_9_0);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ # XXX Neutralize any stats_temp_directory in TEMP_CONFIG. Nodes running
+ # concurrently must not share a stats_temp_directory.
+ print $conf "stats_temp_directory = 'pg_stat_tmp'\n";
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+package PostgresNodeV_8_3; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_8_4);
+
+sub psql
+{
+ my ($self, $dbname, $sql, %params) = @_;
+
+ BAIL_OUT("Node version too old: 'no_password' option not supported")
+ if ($params{no_password});
+
+ $self->SUPER::psql($dbname, $sql, %params);
+
+}
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ $params{has_archiving} = 0 unless defined $params{has_archiving};
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my @trust_opt = ('-A', 'trust');
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @trust_opt,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "log_line_prefix = '%m [%p] %q%a '\n";
+ print $conf "log_statement = all\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ $self->enable_archiving if $params{has_archiving};
+ return;
+}
+
+package PostgresNodeV_8_2; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_8_3);
+
+package PostgresNodeV_8_1; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_8_2);
+
+package PostgresNodeV_8_0; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_8_1);
+
+package PostgresNodeV_7_4; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_8_0);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ BAIL_OUT("Server version too old: 'has_archiving' option not supported")
+ if ($params{has_archiving});
+
+ mkdir $self->backup_dir;
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ print $conf "log_statement = on\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "tcpip_socket = true\n";
+ print $conf "virtual_host = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "tcpip_socket = false\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ return;
+}
+
+package PostgresNodeV_7_3; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_7_4);
+
+package PostgresNodeV_7_2; ## no critic (ProhibitMultiplePackages)
+
+use parent -norequire, qw(PostgresNodeV_7_3);
+
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ local %ENV = $self->_get_env();
+
+ # Check version support for requested features
+ BAIL_OUT("Server version too old: 'allows_streaming' option not supported")
+ if ($params{allows_streaming});
+
+ BAIL_OUT("Server version too old: 'has_archiving' option not supported")
+ if ($params{has_archiving});
+
+ mkdir $self->backup_dir;
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata,
+ @{ $params{extra} });
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
+ @{ $params{auth_extra} });
+
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm\n";
+ print $conf "fsync = off\n";
+
+ # If a setting tends to affect whether tests pass or fail, print it after
+ # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
+ # overrides. Settings that merely improve performance or ease debugging
+ # belong before TEMP_CONFIG.
+ print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
+ if defined $ENV{TEMP_CONFIG};
+
+ print $conf "port = $port\n";
+
+ if ($use_tcp)
+ {
+ print $conf "unix_socket_directory = ''\n";
+ print $conf "tcpip_socket = true\n";
+ print $conf "virtual_host = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directory = '$host'\n";
+ print $conf "tcpip_socket = false\n";
+ }
+ close $conf;
+
+ chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
+ or die("unable to set permissions for $pgdata/postgresql.conf");
+
+ return;
+}
+
+
1;