1034
1034
# ###########################################################################
1036
1036
# ###########################################################################
1038
# This package is a copy without comments from the original. The original
1039
# with comments and its test file can be found in the Bazaar repository at,
1042
# See https://launchpad.net/percona-toolkit for more information.
1043
# ###########################################################################
1046
$INC{"Mo.pm"} = __FILE__;
1048
our $VERSION = '0.30_Percona'; # Forked from 0.30 of Mo.
1057
return \%{ shift() . "::" };
1062
use warnings qw( FATAL all );
1065
use Scalar::Util ();
1068
Bool => sub { !$_[0] || (defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == 1) },
1069
Num => sub { defined $_[0] && &Scalar::Util::looks_like_number },
1070
Int => sub { defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == int $_[0] },
1071
Str => sub { defined $_[0] },
1072
Object => sub { defined $_[0] && &Scalar::Util::blessed },
1073
FileHandle => sub { local $@; require IO::Handle; fileno($_[0]) && $_[0]->opened },
1076
my $type = /R/ ? $_ : uc $_;
1077
$_ . "Ref" => sub { ref $_[0] eq $type }
1078
} qw(Array Code Hash Regexp Glob Scalar)
1087
my $args = $class->BUILDARGS(@_);
1090
while ( my ($attr, $meta) = each %{$metadata_for{$class}} ) {
1091
next unless exists $meta->{init_arg};
1092
my $init_arg = $meta->{init_arg};
1094
if ( defined $init_arg ) {
1095
$args->{$attr} = delete $args->{$init_arg};
1098
push @args_to_delete, $attr;
1102
delete $args->{$_} for @args_to_delete;
1104
for my $attribute ( keys %$args ) {
1105
if ( my $coerce = $metadata_for{$class}{$attribute}{coerce} ) {
1106
$args->{$attribute} = $coerce->($args->{$attribute});
1108
if ( my $I = $metadata_for{$class}{$attribute}{isa} ) {
1109
( (my $I_name), $I ) = @{$I};
1110
Mo::_check_type_constaints($attribute, $I, $I_name, $args->{$attribute});
1114
while ( my ($attribute, $meta) = each %{$metadata_for{$class}} ) {
1115
next unless $meta->{required};
1116
Carp::confess("Attribute ($attribute) is required for $class")
1117
if ! exists $args->{$attribute}
1121
my $self = bless $args, $class;
1124
my $linearized_isa = mro::get_linear_isa($class);
1126
for my $isa_class ( @$linearized_isa ) {
1127
unshift @build_subs, *{ Mo::_glob_for "${isa_class}::BUILD" }{CODE};
1129
exists &$_ && $_->( $self, @_ ) for grep { defined } @build_subs;
1136
if ( @_ == 1 && ref($_[0]) ) {
1137
Carp::confess("Single parameters to new() must be a HASH ref")
1138
unless ref($_[0]) eq ref({});
1139
$ref = {%{$_[0]}} # We want a new reference, always
1150
warnings->import(qw(FATAL all));
1153
my $caller = scalar caller(); # Caller's package
1154
my $caller_pkg = $caller . "::"; # Caller's package with :: at the end
1155
my (%exports, %options);
1157
my (undef, @features) = @_;
1158
my %ignore = ( map { $_ => 1 } qw( is isa init_arg builder buildargs clearer predicate build handles default required ) );
1159
for my $feature (grep { !$ignore{$_} } @features) {
1160
{ local $@; require "Mo/$feature.pm"; }
1163
&{"Mo::${feature}::e"}(
1172
return if $exports{M};
1176
for my $class ( map { "$_" } @_ ) {
1177
$class =~ s{::|'}{/}g;
1178
{ local $@; eval { require "$class.pm" } } # or warn $@;
1180
_set_package_isa($caller, @_);
1181
_set_inherited_metadata($caller);
1185
for my $attribute ( ref $names ? @$names : $names ) {
1187
my $method = ($args{is} || '') eq 'ro'
1189
Carp::confess("Cannot assign a value to a read-only accessor at reader ${caller_pkg}${attribute}")
1191
return $_[0]{$attribute};
1195
? $_[0]{$attribute} = $_[1]
1196
: $_[0]{$attribute};
1199
$metadata_for{$caller}{$attribute} = ();
1201
if ( my $I = $args{isa} ) {
1204
if ( $I =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
1205
$I = _nested_constraints($attribute, $1, $2);
1207
$metadata_for{$caller}{$attribute}{isa} = [$orig_I, $I];
1208
my $orig_method = $method;
1211
Mo::_check_type_constaints($attribute, $I, $orig_I, $_[1]);
1217
if ( my $builder = $args{builder} ) {
1218
my $original_method = $method;
1221
? goto &$original_method
1222
: ! exists $_[0]{$attribute}
1223
? $_[0]{$attribute} = $_[0]->$builder
1224
: goto &$original_method
1228
if ( my $code = $args{default} ) {
1229
Carp::confess("${caller}::${attribute}'s default is $code, but should be a coderef")
1230
unless ref($code) eq 'CODE';
1231
my $original_method = $method;
1234
? goto &$original_method
1235
: ! exists $_[0]{$attribute}
1236
? $_[0]{$attribute} = $_[0]->$code
1237
: goto &$original_method
1241
if ( my $role = $args{does} ) {
1242
my $original_method = $method;
1245
Carp::confess(qq<Attribute ($attribute) doesn't consume a '$role' role">)
1246
unless blessed($_[1]) && $_[1]->does($role)
1248
goto &$original_method
1252
if ( my $coercion = $args{coerce} ) {
1253
$metadata_for{$caller}{$attribute}{coerce} = $coercion;
1254
my $original_method = $method;
1257
return $original_method->($_[0], $coercion->($_[1]))
1259
goto &$original_method;
1263
$method = $options{$_}->($method, $attribute, @_)
1264
for sort keys %options;
1266
*{ _glob_for "${caller}::$attribute" } = $method;
1268
if ( $args{required} ) {
1269
$metadata_for{$caller}{$attribute}{required} = 1;
1272
if ($args{clearer}) {
1273
*{ _glob_for "${caller}::$args{clearer}" }
1274
= sub { delete shift->{$attribute} }
1277
if ($args{predicate}) {
1278
*{ _glob_for "${caller}::$args{predicate}" }
1279
= sub { exists shift->{$attribute} }
1282
if ($args{handles}) {
1283
_has_handles($caller, $attribute, \%args);
1286
if (exists $args{init_arg}) {
1287
$metadata_for{$caller}{$attribute}{init_arg} = $args{init_arg};
1294
$export_for{$caller} = [ keys %exports ];
1296
for my $keyword ( keys %exports ) {
1297
*{ _glob_for "${caller}::$keyword" } = $exports{$keyword}
1299
*{ _glob_for "${caller}::extends" }{CODE}->( "Mo::Object" )
1300
unless @{ *{ _glob_for "${caller}::ISA" }{ARRAY} || [] };
1303
sub _check_type_constaints {
1304
my ($attribute, $I, $I_name, $val) = @_;
1308
|| ($val && $val eq $I)
1309
|| (exists $TYPES{$I} && $TYPES{$I}->($val)))
1312
qq<Attribute ($attribute) does not pass the type constraint because: >
1313
. qq<Validation failed for '$I_name' with value >
1314
. (defined $val ? Mo::Dumper($val) : 'undef') )
1318
my ($caller, $attribute, $args) = @_;
1319
my $handles = $args->{handles};
1321
my $ref = ref $handles;
1323
if ( $ref eq ref [] ) {
1324
$kv = { map { $_,$_ } @{$handles} };
1326
elsif ( $ref eq ref {} ) {
1329
elsif ( $ref eq ref qr// ) {
1330
Carp::confess("Cannot delegate methods based on a Regexp without a type constraint (isa)")
1331
unless $args->{isa};
1332
my $target_class = $args->{isa};
1335
grep { $_ =~ $handles }
1336
grep { !exists $Mo::Object::{$_} && $target_class->can($_) }
1337
grep { $_ ne 'has' && $_ ne 'extends' }
1338
keys %{ _stash_for $target_class }
1342
Carp::confess("handles for $ref not yet implemented");
1345
while ( my ($method, $target) = each %{$kv} ) {
1346
my $name = _glob_for "${caller}::$method";
1347
Carp::confess("You cannot overwrite a locally defined method ($method) with a delegation")
1350
my ($target, @curried_args) = ref($target) ? @$target : $target;
1353
my $delegate_to = $self->$attribute();
1354
my $error = "Cannot delegate $method to $target because the value of $attribute";
1355
Carp::confess("$error is not defined") unless $delegate_to;
1356
Carp::confess("$error is not an object (got '$delegate_to')")
1357
unless Scalar::Util::blessed($delegate_to) || (!ref($delegate_to) && $delegate_to->can($target));
1358
return $delegate_to->$target(@curried_args, @_);
1363
sub _nested_constraints {
1364
my ($attribute, $aggregate_type, $type) = @_;
1367
if ( $type =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
1368
$inner_types = _nested_constraints($1, $2);
1371
$inner_types = $TYPES{$type};
1374
if ( $aggregate_type eq 'ArrayRef' ) {
1377
return unless ref($val) eq ref([]);
1380
for my $value ( @{$val} ) {
1381
return unless $inner_types->($value)
1385
for my $value ( @{$val} ) {
1386
return unless $value && ($value eq $type
1387
|| (Scalar::Util::blessed($value) && $value->isa($type)));
1393
elsif ( $aggregate_type eq 'Maybe' ) {
1396
return 1 if ! defined($value);
1398
return unless $inner_types->($value)
1401
return unless $value eq $type
1402
|| (Scalar::Util::blessed($value) && $value->isa($type));
1408
Carp::confess("Nested aggregate types are only implemented for ArrayRefs and Maybe");
1412
sub _set_package_isa {
1413
my ($package, @new_isa) = @_;
1415
*{ _glob_for "${package}::ISA" } = [@new_isa];
1418
sub _set_inherited_metadata {
1420
my $linearized_isa = mro::get_linear_isa($class);
1423
for my $isa_class (reverse @$linearized_isa) {
1426
%{ $metadata_for{$isa_class} || {} },
1429
$metadata_for{$class} = \%new_metadata;
1433
my $caller = scalar caller();
1434
my $stash = _stash_for( $caller );
1436
delete $stash->{$_} for @{$export_for{$caller}};
1440
require Data::Dumper;
1441
local $Data::Dumper::Indent = 0;
1442
local $Data::Dumper::Sortkeys = 0;
1443
local $Data::Dumper::Quotekeys = 0;
1444
local $Data::Dumper::Terse = 1;
1446
Data::Dumper::Dumper(@_)
1451
{ local $@; require mro; }
1456
require MRO::Compat;
1458
*mro::get_linear_isa = *mro::get_linear_isa_dfs = sub {
1461
my $classname = shift;
1463
my @lin = ($classname);
1465
foreach my $parent (@{"$classname\::ISA"}) {
1466
my $plin = mro::get_linear_isa_dfs($parent);
1468
next if exists $stored{$_};
1482
# ###########################################################################
1484
# ###########################################################################
1486
# ###########################################################################
1037
1487
# DSNParser package
1038
1488
# This package is a copy without comments from the original. The original
1039
1489
# with comments and its test file can be found in the Bazaar repository at,
2314
2759
package VersionParser;
2317
use warnings FATAL => 'all';
2762
use Scalar::Util qw(blessed);
2318
2763
use English qw(-no_match_vars);
2319
2764
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2327
my ( $self, $str ) = @_;
2328
my @version_parts = $str =~ m/(\d+)/g;
2329
@version_parts = map { $_ || 0 } @version_parts[0..2];
2330
my $result = sprintf('%03d%03d%03d', @version_parts);
2331
PTDEBUG && _d($str, 'parses to', $result);
2336
my ($self, $dbh, $target, $cmp) = @_;
2337
my $version = $self->version($dbh);
2340
if ( $cmp eq 'ge' ) {
2341
$result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
2343
elsif ( $cmp eq 'gt' ) {
2344
$result = $self->{$dbh} gt $self->parse($target) ? 1 : 0;
2346
elsif ( $cmp eq 'eq' ) {
2347
$result = $self->{$dbh} eq $self->parse($target) ? 1 : 0;
2349
elsif ( $cmp eq 'ne' ) {
2350
$result = $self->{$dbh} ne $self->parse($target) ? 1 : 0;
2352
elsif ( $cmp eq 'lt' ) {
2353
$result = $self->{$dbh} lt $self->parse($target) ? 1 : 0;
2355
elsif ( $cmp eq 'le' ) {
2356
$result = $self->{$dbh} le $self->parse($target) ? 1 : 0;
2359
die "Asked for an unknown comparizon: $cmp"
2362
PTDEBUG && _d($self->{$dbh}, $cmp, $target, ':', $result);
2367
my ( $self, $dbh, $target ) = @_;
2368
return $self->version_cmp($dbh, $target, 'ge');
2372
my ( $self, $dbh, $target ) = @_;
2373
return $self->version_cmp($dbh, $target, 'gt');
2377
my ( $self, $dbh, $target ) = @_;
2378
return $self->version_cmp($dbh, $target, 'eq');
2382
my ( $self, $dbh, $target ) = @_;
2383
return $self->version_cmp($dbh, $target, 'ne');
2387
my ( $self, $dbh, $target ) = @_;
2388
return $self->version_cmp($dbh, $target, 'lt');
2392
my ( $self, $dbh, $target ) = @_;
2393
return $self->version_cmp($dbh, $target, 'le');
2775
our $VERSION = 0.01;
2783
has [qw( minor revision )] => (
2791
default => sub { 'Unknown' },
2794
has innodb_version => (
2797
default => sub { 'NO' },
2802
return $self->_join_version($self->major, $self->minor);
2397
my ( $self, $dbh ) = @_;
2398
if ( !$self->{$dbh} ) {
2399
$self->{$dbh} = $self->parse(
2400
$dbh->selectrow_array('SELECT VERSION()'));
2402
return $self->{$dbh};
2405
sub innodb_version {
2807
return $self->_join_version($self->major, $self->minor, $self->revision);
2811
my ($self, $target) = @_;
2813
return $self eq $target;
2817
my ($self, @parts) = @_;
2819
return join ".", map { my $c = $_; $c =~ s/^0\./0/; $c } grep defined, @parts;
2821
sub _split_version {
2822
my ($self, $str) = @_;
2823
my @version_parts = map { s/^0(?=\d)/0./; $_ } $str =~ m/(\d+)/g;
2824
return @version_parts[0..2];
2827
sub normalized_version {
2829
my $result = sprintf('%d%02d%02d', map { $_ || 0 } $self->major,
2832
PTDEBUG && _d($self->version, 'normalizes to', $result);
2837
my ( $self, $cmd ) = @_;
2838
my $v = $self->normalized_version();
2840
return "/*!$v $cmd */"
2843
my @methods = qw(major minor revision);
2845
my ($left, $right) = @_;
2846
my $right_obj = (blessed($right) && $right->isa(ref($left)))
2848
: ref($left)->new($right);
2851
for my $m ( @methods ) {
2852
last unless defined($left->$m) && defined($right_obj->$m);
2853
$retval = $left->$m <=> $right_obj->$m;
2864
if ( blessed($_[0]) && $_[0]->can("selectrow_hashref") ) {
2865
PTDEBUG && _d("VersionParser got a dbh, trying to get the version");
2867
local $dbh->{FetchHashKeyName} = 'NAME_lc';
2869
$dbh->selectall_arrayref(q/SHOW VARIABLES LIKE 'version%'/, { Slice => {} })
2872
$query = { map { $_->{variable_name} => $_->{value} } @$query };
2873
@args{@methods} = $self->_split_version($query->{version});
2874
$args{flavor} = delete $query->{version_comment}
2875
if $query->{version_comment};
2877
elsif ( eval { ($query) = $dbh->selectrow_array(q/SELECT VERSION()/) } ) {
2878
@args{@methods} = $self->_split_version($query);
2881
Carp::confess("Couldn't get the version from the dbh while "
2882
. "creating a VersionParser object: $@");
2884
$args{innodb_version} = eval { $self->_innodb_version($dbh) };
2886
elsif ( !ref($_[0]) ) {
2887
@args{@methods} = $self->_split_version($_[0]);
2890
for my $method (@methods) {
2891
delete $args{$method} unless defined $args{$method};
2893
@_ = %args if %args;
2896
return $self->SUPER::BUILDARGS(@_);
2899
sub _innodb_version {
2406
2900
my ( $self, $dbh ) = @_;
2407
2901
return unless $dbh;
2408
2902
my $innodb_version = "NO";