From 9a2452678e8bfce2a335a923682e8a6f24dba796 Mon Sep 17 00:00:00 2001 From: Mark Dilger Date: Tue, 30 Mar 2021 13:36:12 -0700 Subject: [PATCH v1] Extending PostgresNode cross-version functionality Extending the recently introduced functionality that allows a PostgresNode to be formed using an older installation. First, adding functions that allow nodes to be compared, such as if ($some_node->newer_than_version($some_other_node)) { ... } if ($node_node->at_least_version("12.2")) { ... } and also fixing PostgresNode::init() to work with versions older than 9.3. --- src/test/perl/PostgresNode.pm | 144 +++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 1e96357d7e..7a0db74ddd 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -438,7 +438,8 @@ sub init mkdir $self->backup_dir; mkdir $self->archive_dir; - TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N', + TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', + $self->at_least_version("9.3") ? '-N' : (), @{ $params{extra} }); TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata, @{ $params{auth_extra} }); @@ -1196,9 +1197,150 @@ sub get_new_node # Add node to list of nodes push(@all_nodes, $node); + # Get information about the node + $node->_read_pg_config; + return $node; } +# Private routine to run the pg_config binary found in our environment and +# collect all fields that matter to us. +# +sub _read_pg_config +{ + my ($self) = @_; + + local %ENV = $self->_get_env(); + + # We only care about 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 + [ @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. -- 2.21.1 (Apple Git-122.3)