aboutsummaryrefslogtreecommitdiff
path: root/src/test/perl/PostgresVersion.pm
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2021-04-22 10:56:28 -0400
committerAndrew Dunstan <andrew@dunslane.net>2021-04-22 10:56:28 -0400
commit4c4eaf3d19201c5e2d9efebc590903dfaba0d3e5 (patch)
treef67176ca36e554e384f8c4efce8055e0f59a854d /src/test/perl/PostgresVersion.pm
parentf3b141c482552a57866c72919007d6481cd59ee3 (diff)
downloadpostgresql-4c4eaf3d19201c5e2d9efebc590903dfaba0d3e5.tar.gz
postgresql-4c4eaf3d19201c5e2d9efebc590903dfaba0d3e5.zip
Make PostgresNode version aware
A new PostgresVersion object type is created and this is used in PostgresNode using the output of `pg_config --version` and the result stored in the PostgresNode object. This object can be compared to other PostgresVersion objects, or to a number or string. PostgresNode is currently believed to be compatible with versions down to release 12, so PostgresNode will issue a warning if used with a version prior to that. No attempt has been made to deal with incompatibilities in older versions - that remains work to be undertaken in a subsequent development cycle. Based on code from Mark Dilger and Jehan-Guillaume de Rorthais. Discussion: https://postgr.es/m/a80421c0-3d7e-def1-bcfe-24777f15e344@dunslane.net
Diffstat (limited to 'src/test/perl/PostgresVersion.pm')
-rw-r--r--src/test/perl/PostgresVersion.pm137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/test/perl/PostgresVersion.pm b/src/test/perl/PostgresVersion.pm
new file mode 100644
index 00000000000..14750365acf
--- /dev/null
+++ b/src/test/perl/PostgresVersion.pm
@@ -0,0 +1,137 @@
+############################################################################
+#
+# PostgresVersion.pm
+#
+# Module encapsulating Postgres Version numbers
+#
+# Copyright (c) 2021, PostgreSQL Global Development Group
+#
+############################################################################
+
+=pod
+
+=head1 NAME
+
+PostgresVersion - class representing PostgreSQL version numbers
+
+=head1 SYNOPSIS
+
+ use PostgresVersion;
+
+ my $version = PostgresVersion->new($version_arg);
+
+ # compare two versions
+ my $bool = $version1 <= $version2;
+
+ # or compare with a number
+ $bool = $version < 12;
+
+ # or with a string
+ $bool = $version lt "13.1";
+
+ # interpolate in a string
+ my $stringyval = "version: $version";
+
+=head1 DESCRIPTION
+
+PostgresVersion encapsulated Postgres version numbers, providing parsing
+of common version formats and comparison operations.
+
+=cut
+
+package PostgresVersion;
+
+use strict;
+use warnings;
+
+use Scalar::Util qw(blessed);
+
+use overload
+ '<=>' => \&_version_cmp,
+ 'cmp' => \&_version_cmp,
+ '""' => \&_stringify;
+
+=pod
+
+=head1 METHODS
+
+=over
+
+=item PostgresVersion->new($version)
+
+Create a new PostgresVersion instance.
+
+The argument can be a number like 12, or a string like '12.2' or the output
+of a Postgres command like `psql --version` or `pg_config --version`;
+
+=back
+
+=cut
+
+sub new
+{
+ my $class = shift;
+ my $arg = shift;
+
+ # 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);
+ }
+
+ my $res = [@result];
+ bless $res, $class;
+ return $res;
+}
+
+
+# Routine which compares the _pg_version_array obtained for the two
+# arguments and returns -1, 0, or 1, allowing comparison between two
+# PostgresVersion objects or a PostgresVersion and a version string or number.
+#
+# If the second argument is not a blessed object we call the constructor
+# to make one.
+#
+# Because we're overloading '<=>' and 'cmp' this function supplies us with
+# all the comparison operators ('<' and friends, 'gt' and friends)
+#
+sub _version_cmp
+{
+ my ($a, $b) = @_;
+
+ $b = __PACKAGE__->new($b) unless blessed($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]);
+ }
+}
+
+# Render the version number in the standard "joined by dots" notation if
+# interpolated into a string. Put back 'devel' if we previously turned it
+# into a -1.
+sub _stringify
+{
+ my $self = shift;
+ my @sections = @$self;
+ if ($sections[-1] == -1)
+ {
+ pop @sections;
+ $sections[-1] = "$sections[-1]devel";
+ }
+ return join('.', @sections);
+}
+
+1;