22
22
# VersionParser parses a MySQL version string.
23
23
package VersionParser;
26
use warnings FATAL => 'all';
26
use Scalar::Util qw(blessed);
27
27
use English qw(-no_match_vars);
28
28
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
36
my ( $self, $str ) = @_;
37
my @version_parts = $str =~ m/(\d+)/g;
38
# Turn a version like 5.5 into 5.5.0
39
@version_parts = map { $_ || 0 } @version_parts[0..2];
40
my $result = sprintf('%03d%03d%03d', @version_parts);
41
PTDEBUG && _d($str, 'parses to', $result);
45
# Compares versions like 5.0.27 and 4.1.15-standard-log. Caches version number
46
# for each DBH for later use.
48
my ($self, $dbh, $target, $cmp) = @_;
49
my $version = $self->version($dbh);
53
$result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
55
elsif ( $cmp eq 'gt' ) {
56
$result = $self->{$dbh} gt $self->parse($target) ? 1 : 0;
58
elsif ( $cmp eq 'eq' ) {
59
$result = $self->{$dbh} eq $self->parse($target) ? 1 : 0;
61
elsif ( $cmp eq 'ne' ) {
62
$result = $self->{$dbh} ne $self->parse($target) ? 1 : 0;
64
elsif ( $cmp eq 'lt' ) {
65
$result = $self->{$dbh} lt $self->parse($target) ? 1 : 0;
67
elsif ( $cmp eq 'le' ) {
68
$result = $self->{$dbh} le $self->parse($target) ? 1 : 0;
71
die "Asked for an unknown comparizon: $cmp"
74
PTDEBUG && _d($self->{$dbh}, $cmp, $target, ':', $result);
79
my ( $self, $dbh, $target ) = @_;
80
return $self->version_cmp($dbh, $target, 'ge');
84
my ( $self, $dbh, $target ) = @_;
85
return $self->version_cmp($dbh, $target, 'gt');
89
my ( $self, $dbh, $target ) = @_;
90
return $self->version_cmp($dbh, $target, 'eq');
94
my ( $self, $dbh, $target ) = @_;
95
return $self->version_cmp($dbh, $target, 'ne');
99
my ( $self, $dbh, $target ) = @_;
100
return $self->version_cmp($dbh, $target, 'lt');
104
my ( $self, $dbh, $target ) = @_;
105
return $self->version_cmp($dbh, $target, 'le');
32
# All the other operators are defined through these
48
has [qw( minor revision )] => (
56
default => sub { 'Unknown' },
59
has innodb_version => (
62
default => sub { 'NO' },
67
return $self->_join_version($self->major, $self->minor);
109
my ( $self, $dbh ) = @_;
110
if ( !$self->{$dbh} ) {
111
$self->{$dbh} = $self->parse(
112
$dbh->selectrow_array('SELECT VERSION()'));
114
return $self->{$dbh};
72
return $self->_join_version($self->major, $self->minor, $self->revision);
76
my ($self, $target) = @_;
78
return $self eq $target;
82
# The crux of these two versions is to transform a version like 5.1.01 into
83
# 5, 1, and 0.1, and then reverse the process. This is so that the version
84
# above and 5.1.1 are differentiated.
86
my ($self, @parts) = @_;
88
return join ".", map { my $c = $_; $c =~ s/^0\./0/; $c } grep defined, @parts;
92
my ($self, $str) = @_;
93
my @version_parts = map { s/^0(?=\d)/0./; $_ } $str =~ m/(\d+)/g;
94
return @version_parts[0..2];
97
# Returns the version formatted as %d%02d%02d; that is, 5.1.20 would become
98
# 50120, 5.1.2 would become 50102, and 5.1.02 would become 50100
99
sub normalized_version {
101
my $result = sprintf('%d%02d%02d', map { $_ || 0 } $self->major,
104
PTDEBUG && _d($self->version, 'normalizes to', $result);
108
# Returns a comment in the form of /*!$self->normalized_version $cmd */
110
my ( $self, $cmd ) = @_;
111
my $v = $self->normalized_version();
113
return "/*!$v $cmd */"
116
my @methods = qw(major minor revision);
118
my ($left, $right) = @_;
119
# If the first object is blessed and ->isa( self's class ), then
120
# just use that; Otherwise, contruct a new VP object from it.
121
my $right_obj = (blessed($right) && $right->isa(ref($left)))
123
: ref($left)->new($right);
126
for my $m ( @methods ) {
127
last unless defined($left->$m) && defined($right_obj->$m);
128
$retval = $left->$m <=> $right_obj->$m;
139
if ( blessed($_[0]) && $_[0]->can("selectrow_hashref") ) {
140
PTDEBUG && _d("VersionParser got a dbh, trying to get the version");
142
local $dbh->{FetchHashKeyName} = 'NAME_lc';
144
$dbh->selectall_arrayref(q/SHOW VARIABLES LIKE 'version%'/, { Slice => {} })
147
$query = { map { $_->{variable_name} => $_->{value} } @$query };
148
@args{@methods} = $self->_split_version($query->{version});
149
$args{flavor} = delete $query->{version_comment}
150
if $query->{version_comment};
152
elsif ( eval { ($query) = $dbh->selectrow_array(q/SELECT VERSION()/) } ) {
153
@args{@methods} = $self->_split_version($query);
156
Carp::confess("Couldn't get the version from the dbh while "
157
. "creating a VersionParser object: $@");
159
$args{innodb_version} = eval { $self->_innodb_version($dbh) };
161
elsif ( !ref($_[0]) ) {
162
@args{@methods} = $self->_split_version($_[0]);
165
for my $method (@methods) {
166
delete $args{$method} unless defined $args{$method};
171
return $self->SUPER::BUILDARGS(@_);
117
174
# Returns DISABLED if InnoDB doesn't appear as YES or DEFAULT in SHOW ENGINES,
118
175
# BUILTIN if there is no innodb_version variable in SHOW VARIABLES, or
119
176
# <value> if there is an innodb_version variable in SHOW VARIABLES, or
120
177
# NO if SHOW ENGINES is broken or InnDB doesn't appear in it.
178
sub _innodb_version {
122
179
my ( $self, $dbh ) = @_;
123
180
return unless $dbh;
124
181
my $innodb_version = "NO";