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;