Merge release-2.2.4.

This commit is contained in:
Daniel Nichter
2013-08-03 10:37:45 -07:00
76 changed files with 1770 additions and 9331 deletions

View File

@@ -1,5 +1,22 @@
Changelog for Percona Toolkit
* Implemented pt-query-digest anonymous JSON output
* Implemented pt-online-schema-change timestamp output
* Fixed bug 1182856: Zero values causes "Invalid --set-vars value: var=0"
* Fixed bug 1195034: pt-deadlock-logger error: Use of uninitialized value $ts in pattern match (m//)
* Fixed bug 1137556: pt-heartbeat docs don't account for --utc
* Fixed bug 1188264: pt-online-schema-change error copying rows: Undefined subroutine &pt_online_schema_change::get
* Fixed bug 1171968: pt-query-digest docs don't mention --type=rawlog
* Fixed bug 1176010: pt-query-digest doesn't group db and `db` together
* Fixed bug 1174956: pt-query-digest and pt-fingerprint don't strip some multi-line comments
* Fixed bug 1172317: pt-sift does not work if pt-stalk did not collect due to a full disk
* Fixed bug 1136559: pt-table-checksum: Deep recursion on subroutine "SchemaIterator::_iterate_dbh"
* Fixed bug 1199591: pt-table-checksum doesn't use non-unique index with highest cardinality
* Fixed bug 1163735: pt-table-checksum fails if explicit_defaults_for_timestamp is enabled in 5.6
* Fixed bug 1168434: pt-upgrade reports differences on NULL
* Fixed bug 1168106: pt-variable-advisor has the wrong default value for innodb_max_dirty_pages_pct in 5.5 and 5.6
* Fixed bug 1168110: pt-variable-advisor shows key_buffer_size in 5.6 as unconfigured (even though it is)
v2.2.3 released 2013-06-17
* Added new tool: pt-agent

View File

@@ -52,7 +52,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -3560,7 +3560,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -3574,7 +3574,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -1028,7 +1028,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1042,7 +1042,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -43,7 +43,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1755,7 +1755,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1769,7 +1769,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -43,7 +43,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1755,7 +1755,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1769,7 +1769,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -42,7 +42,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1105,7 +1105,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1119,7 +1119,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -4804,6 +4804,11 @@ sub parse_deadlocks {
# Extract some miscellaneous data from the deadlock.
my ( $ts ) = $dl_text =~ m/^$s$/m;
if ( !$ts ) {
# https://bugs.launchpad.net/percona-toolkit/+bug/1195034
# 130624 17:39:24TOO DEEP OR LONG SEARCH IN THE LOCK TABLE ...
($ts) = $dl_text =~ m/^${s}TOO DEEP/m;
}
my ( $year, $mon, $day, $hour, $min, $sec ) = $ts =~ m/^((?:\d\d)?\d\d)-?(\d\d)-?(\d\d) +(\d+):(\d+):(\d+)$/;
if ( length($year) == 2 ) {
$year += 2000;

View File

@@ -38,7 +38,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1101,7 +1101,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1115,7 +1115,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -39,7 +39,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -2087,7 +2087,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -2101,7 +2101,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -3297,58 +3297,63 @@ sub _iterate_dbh {
$self->{dbs} = \@dbs;
}
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
PTDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
DATABASE:
while ( $self->{db} || defined(my $db = shift @{$self->{dbs}}) ) {
if ( !$self->{db} ) {
PTDEBUG && _d('Next database:', $db);
$self->{db} = $db;
}
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("Skipping $table_name because it no longer exists");
if ( !$self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
next;
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database',$self->{db});
$self->{tbls} = \@tbls;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
TABLE:
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("$table_name no longer exists");
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
}
next TABLE;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
}
}
}
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
} # DATABASE
return $self->_iterate_dbh();
PTDEBUG && _d('No more databases');
return;
}
sub database_is_allowed {

View File

@@ -1029,7 +1029,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1043,7 +1043,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -35,7 +35,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1521,7 +1521,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1535,7 +1535,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -1030,7 +1030,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1044,7 +1044,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -1532,8 +1532,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -1600,9 +1600,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;

View File

@@ -37,7 +37,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1100,7 +1100,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1114,7 +1114,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -38,7 +38,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1837,7 +1837,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1851,7 +1851,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -5688,6 +5688,10 @@ be created with the following MAGIC_create_heartbeat table definition:
The heartbeat table requires at least one row. If you manually create the
heartbeat table, then you must insert a row by doing:
INSERT INTO heartbeat (ts, server_id) VALUES (NOW(), N);
or if using L<"--utc">:
INSERT INTO heartbeat (ts, server_id) VALUES (UTC_TIMESTAMP(), N);
where C<N> is the server's ID; do not use @@server_id because it will replicate
@@ -5706,6 +5710,10 @@ Legacy tables do not support L<"--update"> instances on each slave
of a multi-slave hierarchy like "master -> slave1 -> slave2".
To manually insert the one required row into a legacy table:
INSERT INTO heartbeat (id, ts) VALUES (1, NOW());
or if using L<"--utc">:
INSERT INTO heartbeat (id, ts) VALUES (1, UTC_TIMESTAMP());
The tool automatically detects if the heartbeat table is legacy.
@@ -6003,9 +6011,14 @@ Ignore system time zones and use only UTC. By default pt-heartbeat does
not check or adjust for different system or MySQL time zones which can
cause the tool to compute the lag incorrectly. Specifying this option is
a good idea because it ensures that the tool works correctly regardless of
time zones, but it also makes the tool backwards-incompatible with
pt-heartbeat 2.2.3 and older (unless the older version of pt-heartbeat
is running on a system that uses UTC).
time zones.
If used, this option must be used for all pt-heartbeat instances:
L<"--update">, L<"--monitor">, L<"--check">, etc. You should probably
set the option in a L<"--config"> file. Mixing this option with pt-heartbeat
instances not using this option will cause false-positive lag readings
due to different time zones (unless all your systems are set to use UTC,
in which case this option isn't required).
=item --version

View File

@@ -45,7 +45,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1682,7 +1682,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1696,7 +1696,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -2377,8 +2377,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -2445,9 +2445,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;
@@ -4131,58 +4131,63 @@ sub _iterate_dbh {
$self->{dbs} = \@dbs;
}
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
PTDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
DATABASE:
while ( $self->{db} || defined(my $db = shift @{$self->{dbs}}) ) {
if ( !$self->{db} ) {
PTDEBUG && _d('Next database:', $db);
$self->{db} = $db;
}
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("Skipping $table_name because it no longer exists");
if ( !$self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
next;
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database',$self->{db});
$self->{tbls} = \@tbls;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
TABLE:
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("$table_name no longer exists");
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
}
next TABLE;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
}
}
}
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
} # DATABASE
return $self->_iterate_dbh();
PTDEBUG && _d('No more databases');
return;
}
sub database_is_allowed {

View File

@@ -47,7 +47,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1110,7 +1110,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1124,7 +1124,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -4655,8 +4655,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -4723,9 +4723,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;

View File

@@ -54,7 +54,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1117,7 +1117,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1131,7 +1131,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -5495,7 +5495,7 @@ sub _find_best_index {
}
@possible_indexes = sort {
my $cmp
= $indexes->{$b}->{cardinality} <=> $indexes->{$b}->{cardinality};
= $indexes->{$b}->{cardinality} <=> $indexes->{$a}->{cardinality};
if ( $cmp == 0 ) {
$cmp = scalar @{$indexes->{$b}->{cols}}
<=> scalar @{$indexes->{$a}->{cols}};
@@ -8477,17 +8477,17 @@ sub main {
. " doesn't exist\".\n";
}
else {
print "Dropping new table...\n";
print ts("Dropping new table...\n");
print $sql, "\n" if $o->get('print');
PTDEBUG && _d($sql);
eval {
$cxn->dbh()->do($sql);
};
if ( $EVAL_ERROR ) {
warn "Error dropping new table $new_tbl->{name}: $EVAL_ERROR\n"
. "To try dropping the new table again, execute:\n$sql\n";
warn ts("Error dropping new table $new_tbl->{name}: $EVAL_ERROR\n"
. "To try dropping the new table again, execute:\n$sql\n");
}
print "Dropped new table OK.\n";
print ts("Dropped new table OK.\n");
}
};
@@ -8737,8 +8737,8 @@ sub main {
return;
}
else {
print "Copying approximately ", $nibble_iter->row_estimate(),
" rows...\n";
print ts("Copying approximately "
. $nibble_iter->row_estimate() . " rows...\n");
}
}
@@ -8784,7 +8784,7 @@ sub main {
. ($tbl->{chunk_size} * $limit)
. " rows (chunk size=$tbl->{chunk_size}"
. " * chunk size limit=$limit).\n";
die $msg;
die ts($msg);
}
}
else { # chunking the table
@@ -8797,20 +8797,20 @@ sub main {
n_index_cols => $o->get('chunk-index-columns'),
);
if ( !$key || lc($key) ne lc($nibble_iter->nibble_index()) ) {
die "Cannot determine the key_len of the chunk index "
die ts("Cannot determine the key_len of the chunk index "
. "because MySQL chose "
. ($key ? "the $key" : "no") . " index "
. "instead of the " . $nibble_iter->nibble_index()
. " index for the first lower boundary statement. "
. "See --[no]check-plan in the documentation for more "
. "information.";
. "information.");
}
elsif ( !$key_len ) {
die "The key_len of the $key index is "
die ts("The key_len of the $key index is "
. (defined $key_len ? "zero" : "NULL")
. ", but this should not be possible. "
. "See --[no]check-plan in the documentation for more "
. "information.";
. "information.");
}
$tbl->{key_len} = $key_len;
}
@@ -8852,7 +8852,7 @@ sub main {
. join(", ", map { defined $_ ? $_ : "NULL" }
(@{$boundary->{lower}}, $nibble_iter->limit()))
. "\n";
die $msg;
die ts($msg);
}
# Once nibbling begins for a table, control does not return to this
@@ -8926,13 +8926,13 @@ sub main {
# This warning is printed once per table.
if ( !$tbl->{warned_slow} ) {
warn "Rows are copying very slowly. "
warn ts("Rows are copying very slowly. "
. "--chunk-size has been automatically reduced to 1. "
. "Check that the server is not being overloaded, "
. "or increase --chunk-time. The last chunk "
. "selected $cnt rows and took "
. sprintf('%.3f', $tbl->{nibble_time})
. " seconds to execute.\n";
. " seconds to execute.\n");
$tbl->{warned_slow} = 1;
}
}
@@ -8960,7 +8960,7 @@ sub main {
},
done => sub {
if ( $o->get('execute') ) {
print "Copied rows OK.\n";
print ts("Copied rows OK.\n");
}
},
};
@@ -9027,8 +9027,8 @@ sub main {
1 while $nibble_iter->next();
};
if ( $EVAL_ERROR ) {
die "Error copying rows from $orig_tbl->{name} to "
. "$new_tbl->{name}: $EVAL_ERROR\n";
die ts("Error copying rows from $orig_tbl->{name} to "
. "$new_tbl->{name}: $EVAL_ERROR\n");
}
$orig_tbl->{copied} = 1; # flag for cleanup tasks
@@ -9097,10 +9097,10 @@ sub main {
};
if ( $EVAL_ERROR ) {
# TODO: one of these values can be undefined
die "Error swapping tables: $EVAL_ERROR\n"
die ts("Error swapping tables: $EVAL_ERROR\n"
. "To clean up, first verify that the original table "
. "$orig_tbl->{name} has not been modified or renamed, "
. "then drop the new table $new_tbl->{name} if it exists.\n";
. "then drop the new table $new_tbl->{name} if it exists.\n");
}
}
$orig_tbl->{swapped} = 1; # flag for cleanup tasks
@@ -9192,7 +9192,7 @@ sub main {
$plugin->before_drop_old_table();
}
print "Dropping old table...\n";
print ts("Dropping old table...\n");
if ( $alter_fk_method eq 'none' ) {
# Child tables still reference the old table, but the user
@@ -9211,9 +9211,9 @@ sub main {
$cxn->dbh()->do($sql);
};
if ( $EVAL_ERROR ) {
die "Error dropping the old table: $EVAL_ERROR\n";
die ts("Error dropping the old table: $EVAL_ERROR\n");
}
print "Dropped old table $old_tbl->{name} OK.\n";
print ts("Dropped old table $old_tbl->{name} OK.\n");
# --plugin hook
if ( $plugin && $plugin->can('after_drop_old_table') ) {
@@ -9453,10 +9453,10 @@ sub nibble_is_safe {
if ( !$nibble_iter->one_nibble()
&& lc($expl->{key} || '') ne lc($nibble_iter->nibble_index() || '') )
{
die "Error copying rows at chunk " . $nibble_iter->nibble_number()
die ts("Error copying rows at chunk " . $nibble_iter->nibble_number()
. " of $tbl->{db}.$tbl->{tbl} because MySQL chose "
. ($expl->{key} ? "the $expl->{key}" : "no") . " index "
. " instead of the " . $nibble_iter->nibble_index() . "index.\n";
. " instead of the " . $nibble_iter->nibble_index() . "index.\n");
}
# Ensure that the chunk isn't too large if there's a --chunk-size-limit.
@@ -9471,14 +9471,14 @@ sub nibble_is_safe {
&& $nibble_iter->identical_boundaries($boundary->{upper},
$boundary->{next_lower}) )
{
die "Error copying rows at chunk " . $nibble_iter->nibble_number()
die ts("Error copying rows at chunk " . $nibble_iter->nibble_number()
. " of $tbl->{db}.$tbl->{tbl} because it is oversized. "
. "The current chunk size limit is "
. ($tbl->{chunk_size} * $limit)
. " rows (chunk size=$tbl->{chunk_size}"
. " * chunk size limit=$limit), but MySQL estimates "
. "that there are " . ($expl->{rows} || 0)
. " rows in the chunk.\n";
. " rows in the chunk.\n");
}
}
@@ -9488,12 +9488,12 @@ sub nibble_is_safe {
&& $tbl->{key_len}
&& ($expl->{key_len} || 0) < $tbl->{key_len} )
{
die "Error copying rows at chunk " . $nibble_iter->nibble_number()
die ts("Error copying rows at chunk " . $nibble_iter->nibble_number()
. " of $tbl->{db}.$tbl->{tbl} because MySQL used "
. "only " . ($expl->{key_len} || 0) . " bytes "
. "of the " . ($expl->{key} || '?') . " index instead of "
. $tbl->{key_len} . ". See the --[no]check-plan documentation "
. "for more information.\n";
. "for more information.\n");
}
return 1; # safe
@@ -9613,22 +9613,20 @@ sub swap_tables {
return $orig_tbl;
}
elsif ( $o->get('execute') ) {
print "Swapping tables...\n";
print ts("Swapping tables...\n");
while ( $name_tries-- ) {
$table_name = $prefix . $table_name;
if ( length($table_name) > 64 ) {
my $truncated_table_name = substr($table_name, 0, 64);
PTDEBUG && _d($table_name, 'is over 64 characters long, truncating to',
PTDEBUG && _d($table_name, 'is > 64 chars, truncating to',
$truncated_table_name);
$table_name = $truncated_table_name;
}
my $sql = "RENAME TABLE $orig_tbl->{name} "
. "TO " . $q->quote($orig_tbl->{db}, $table_name)
. ", $new_tbl->{name} TO $orig_tbl->{name}";
my $sql = "RENAME TABLE $orig_tbl->{name} "
. "TO " . $q->quote($orig_tbl->{db}, $table_name)
. ", $new_tbl->{name} TO $orig_tbl->{name}";
eval {
osc_retry(
Cxn => $cxn,
@@ -9655,11 +9653,12 @@ sub swap_tables {
PTDEBUG && _d($e);
next;
}
die $e;
die ts($e);
}
print $sql, "\n" if $o->get('print');
print "Swapped original and new tables OK.\n";
print ts("Swapped original and new tables OK.\n");
return { # success
db => $orig_tbl->{db},
tbl => $table_name,
@@ -9670,7 +9669,8 @@ sub swap_tables {
# This shouldn't happen.
# Here and in the attempt to find a new table name we probably ought to
# use --tries (and maybe a Retry object?)
die "Failed to find a unique old table name after serveral attempts.\n";
die ts("Failed to find a unique old table name after "
. "serveral attempts.\n");
}
}
@@ -9794,10 +9794,10 @@ sub determine_alter_fk_method {
# and doesn't cause the orig table to go missing for a moment.
my $method = 'rebuild_constraints';
print "Max rows for the rebuild_constraints method: $max_rows\n",
"Determining the method to update foreign keys...\n";
print ts("Max rows for the rebuild_constraints method: $max_rows\n"
. "Determining the method to update foreign keys...\n");
foreach my $child_tbl ( @$child_tables ) {
print " $child_tbl->{name}: ";
print ts(" $child_tbl->{name}: ");
my ($n_rows) = NibbleIterator::get_row_estimate(
Cxn => $cxn,
tbl => $child_tbl,
@@ -9846,7 +9846,7 @@ sub rebuild_constraints {
print "Not rebuilding foreign key constraints because this is a dry run.\n";
}
else {
print "Rebuilding foreign key constraints...\n";
print ts("Rebuilding foreign key constraints...\n");
}
CHILD_TABLE:
@@ -9858,8 +9858,8 @@ sub rebuild_constraints {
);
my @constraints = $table_def =~ m/$constraint/g;
if ( !@constraints ) {
warn "$child_tbl->{name} has no foreign key "
. "constraints referencing $old_tbl->{name}.\n";
warn ts("$child_tbl->{name} has no foreign key "
. "constraints referencing $old_tbl->{name}.\n");
next CHILD_TABLE;
}
@@ -9913,7 +9913,7 @@ sub rebuild_constraints {
}
if ( $o->get('execute') ) {
print "Rebuilt foreign key constraints OK.\n";
print ts("Rebuilt foreign key constraints OK.\n");
}
return;
@@ -9931,7 +9931,7 @@ sub drop_swap {
print "Not drop-swapping tables because this is a dry run.\n";
}
else {
print "Drop-swapping tables...\n";
print ts("Drop-swapping tables...\n");
}
my @sqls = (
@@ -9958,7 +9958,7 @@ sub drop_swap {
}
if ( $o->get('execute') ) {
print "Dropped and swapped tables OK.\n";
print ts("Dropped and swapped tables OK.\n");
}
return;
@@ -9979,7 +9979,7 @@ sub create_triggers {
print "Not creating triggers because this is a dry run.\n";
}
else {
print "Creating triggers...\n";
print ts("Creating triggers...\n");
}
# Create a unique trigger name prefix based on the orig table name
@@ -10059,7 +10059,7 @@ sub create_triggers {
}
if ( $o->get('execute') ) {
print "Created triggers OK.\n";
print ts("Created triggers OK.\n");
}
return @trigger_names;
@@ -10080,7 +10080,7 @@ sub drop_triggers {
print "Not dropping triggers because this is a dry run.\n";
}
else {
print "Dropping triggers...\n";
print ts("Dropping triggers...\n");
}
foreach my $sql ( @drop_trigger_sqls ) {
@@ -10099,7 +10099,7 @@ sub drop_triggers {
);
};
if ( $EVAL_ERROR ) {
warn "Error dropping trigger: $EVAL_ERROR\n";
warn ts("Error dropping trigger: $EVAL_ERROR\n");
push @triggers_not_dropped, $sql;
$exit_status = 1;
}
@@ -10108,11 +10108,11 @@ sub drop_triggers {
if ( $o->get('execute') ) {
if ( !@triggers_not_dropped ) {
print "Dropped triggers OK.\n";
print ts("Dropped triggers OK.\n");
}
else {
warn "To try dropping the triggers again, execute:\n"
. join("\n", @triggers_not_dropped) . "\n";
warn ts("To try dropping the triggers again, execute:\n"
. join("\n", @triggers_not_dropped) . "\n");
}
}
@@ -10192,7 +10192,7 @@ sub osc_retry {
# the tool will stop, which is probably good because by this
# point the error or warning indicates that something is wrong.
$stats->{ error_event($error) }++;
die $error;
die ts($error);
}
);
}
@@ -10285,22 +10285,14 @@ sub exec_nibble {
|| $message =~ m/$warn_code{$code}->{pattern}/) )
{
if ( !$stats->{"mysql_warning_$code"}++ ) { # warn once
my $err
= "Copying rows caused a MySQL error $code: "
warn "Copying rows caused a MySQL error $code: "
. ($warn_code{$code}->{message}
? $warn_code{$code}->{message}
: $message)
. "\nThis MySQL error is being ignored ";
if ( get('statistics') ) {
$err .= "but further occurrences will be reported "
. "by --statistics when the tool finishes.\n";
}
else {
$err .= "and further occurrences will not be reported. "
. "Specify --statistics to see a count of all "
. "suppressed warnings and errors.\n";
}
warn $err;
. "\nNo more warnings about this MySQL error will be "
. "reported. If --statistics was specified, "
. "mysql_warning_$code will list the total count of "
. "this MySQL error.\n";
}
}
else {
@@ -10354,6 +10346,12 @@ sub explain_statement {
return $expl;
}
sub ts {
my ($msg) = @_;
my $ts = $ENV{PTTEST_FAKE_TS} ? 'TS' : Transformers::ts(int(time));
return $msg ? "$ts $msg" : $ts;
}
# Catches signals so we can exit gracefully.
sub sig_int {
my ( $signal ) = @_;

View File

@@ -64,7 +64,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -2350,7 +2350,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -2364,7 +2364,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -2802,8 +2802,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -2870,9 +2870,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;
@@ -7900,10 +7900,12 @@ override query_report => sub {
distillate => $distill,
attribute => $groupby,
query_count => $times_seen,
example => {
query => substr($sample->{arg}, 0, $self->max_query_length),
ts => $sample->{ts} ? parse_timestamp($sample->{ts}) : undef,
},
$args{anon} ? () : (
example => {
query => substr($sample->{arg}, 0, $self->max_query_length),
ts => $sample->{ts} ? parse_timestamp($sample->{ts}) : undef,
},
),
};
my %metrics;
@@ -7981,19 +7983,21 @@ override query_report => sub {
push @tables, { status => $status, create => $create };
}
if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) {
if ( $item =~ m/^(?:insert|replace)/ ) {
if ( !$args{anon} ) {
if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) {
if ( $item =~ m/^(?:insert|replace)/ ) {
}
else {
}
}
else {
}
}
else {
my $converted = $qr->convert_to_select(
$sample->{arg} || '',
);
if ( $converted && $converted =~ m/^[\(\s]*select/i ) {
$class->{example}->{as_select} = $converted;
my $converted = $qr->convert_to_select(
$sample->{arg} || '',
);
if ( $converted && $converted =~ m/^[\(\s]*select/i ) {
$class->{example}->{as_select} = $converted;
}
}
}
}
@@ -13252,7 +13256,10 @@ sub main {
process => sub {
my ( $args ) = @_;
my $event = $pl->parse_event(code => $code);
$args->{event} = $event if $event;
if ( $event ) {
sanitize_event($event);
$args->{event} = $event;
}
return $args;
},
);
@@ -13313,6 +13320,7 @@ sub main {
stats => $args->{stats},
);
if ( $event ) {
sanitize_event($event);
$args->{event} = $event;
return $args;
}
@@ -14151,7 +14159,7 @@ sub print_reports {
$print_header = 1;
}
my $report_class = $o->get('output') =~ m/\Ajson\z/i
my $report_class = $o->get('output') =~ m/^json/i
? 'JSONReportFormatter'
: 'QueryReportFormatter';
my $qrf = $report_class->new(
@@ -14178,6 +14186,7 @@ sub print_reports {
variations => $o->get('variations'),
group => { map { $_=>1 } qw(rusage date hostname files header) },
resume => $resume,
anon => $o->get('output') eq 'json-anon',
);
}
@@ -14567,6 +14576,23 @@ sub save_resume_offset {
return;
}
sub sanitize_event {
my ($event) = @_;
# Quoted and unquoted values should be treated the same
# https://bugs.launchpad.net/percona-toolkit/+bug/1176010
if ( $event->{db} ) {
$event->{db} =~ s/^`//;
$event->{db} =~ s/`$//;
}
if ( $event->{Schema} ) {
$event->{Schema} =~ s/^`//;
$event->{Schema} =~ s/`$//;
}
return;
}
sub _d {
my ($package, undef, $line) = caller 0;
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
@@ -15590,11 +15616,12 @@ type: string; default: report
How to format and print the query analysis results. Accepted values are:
VALUE FORMAT
======= ==============================
report Standard query analysis report
slowlog MySQL slow log
json JSON, on array per query class
VALUE FORMAT
======= ==============================
report Standard query analysis report
slowlog MySQL slow log
json JSON, on array per query class
json-anon JSON without example queries
The entire C<report> output can be disabled by specifying C<--no-report>
(see L<"--[no]report">), and its sections can be disabled or rearranged
@@ -16051,6 +16078,23 @@ database.
Server-side prepared statements are supported. SSL-encrypted traffic cannot be
inspected and decoded.
=item rawlog
Raw logs are not MySQL logs but simple text files with one SQL statement
per line, like:
SELECT c FROM t WHERE id=1
/* Hello, world! */ SELECT * FROM t2 LIMIT 1
INSERT INTO t (a, b) VALUES ('foo', 'bar')
INSERT INTO t SELECT * FROM monkeys
Since raw logs do not have any metrics, many options and features of
pt-query-digest do not work with them.
One use case for raw logs is ranking queries by count when the only
information available is a list of queries, from polling C<SHOW PROCESSLIST>
for example.
=back
=item --until

View File

@@ -1030,7 +1030,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1044,7 +1044,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -545,7 +545,7 @@ main() {
if [ -d "$1" ]; then
BASEDIR="$1"
PREFIX=""
elif [ -f "$1" -o -f "$1-df" -o -f "$1df" ]; then
elif [ -f "$1" -o -f "$1-output" -o -f "$1output" ]; then
BASEDIR="$(dirname "$1")"
PREFIX="$(echo "$1" | perl -ne '$_ =~ m/([\d_]+)/; print $1;')"
else
@@ -578,10 +578,10 @@ main() {
done
# We need to generate a list of timestamps, and ask the user to choose one if
# there is no PREFIX yet. NOTE: we rely on the "-df" files here.
# there is no PREFIX yet. NOTE: we rely on the "-output" files here.
(
cd "$BASEDIR"
ls *-df 2>/dev/null | cut -d- -f1 | sort > "$PT_TMPDIR/pt-sift.prefixes"
ls *-output 2>/dev/null | cut -d- -f1 | sort > "$PT_TMPDIR/pt-sift.prefixes"
)
if [ ! -s "$PT_TMPDIR/pt-sift.prefixes" ]; then
echo "Error: There are no pt-stalk files in $BASEDIR" >&2

View File

@@ -40,7 +40,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1103,7 +1103,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1117,7 +1117,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -1038,7 +1038,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1052,7 +1052,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -41,7 +41,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1255,7 +1255,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1269,7 +1269,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -57,7 +57,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -2784,7 +2784,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -2798,7 +2798,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -6479,7 +6479,7 @@ sub _find_best_index {
}
@possible_indexes = sort {
my $cmp
= $indexes->{$b}->{cardinality} <=> $indexes->{$b}->{cardinality};
= $indexes->{$b}->{cardinality} <=> $indexes->{$a}->{cardinality};
if ( $cmp == 0 ) {
$cmp = scalar @{$indexes->{$b}->{cols}}
<=> scalar @{$indexes->{$a}->{cols}};
@@ -7344,58 +7344,63 @@ sub _iterate_dbh {
$self->{dbs} = \@dbs;
}
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
PTDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
DATABASE:
while ( $self->{db} || defined(my $db = shift @{$self->{dbs}}) ) {
if ( !$self->{db} ) {
PTDEBUG && _d('Next database:', $db);
$self->{db} = $db;
}
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("Skipping $table_name because it no longer exists");
if ( !$self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
next;
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database',$self->{db});
$self->{tbls} = \@tbls;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
TABLE:
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("$table_name no longer exists");
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
}
next TABLE;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
}
}
}
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
} # DATABASE
return $self->_iterate_dbh();
PTDEBUG && _d('No more databases');
return;
}
sub database_is_allowed {
@@ -12037,7 +12042,7 @@ structure (MAGIC_create_replicate):
this_cnt int NOT NULL,
master_crc char(40) NULL,
master_cnt int NULL,
ts timestamp NOT NULL,
ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (db, tbl, chunk),
INDEX ts_db_tbl (ts, db, tbl)
) ENGINE=InnoDB;

View File

@@ -55,7 +55,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1118,7 +1118,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1132,7 +1132,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -7690,58 +7690,63 @@ sub _iterate_dbh {
$self->{dbs} = \@dbs;
}
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
PTDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
DATABASE:
while ( $self->{db} || defined(my $db = shift @{$self->{dbs}}) ) {
if ( !$self->{db} ) {
PTDEBUG && _d('Next database:', $db);
$self->{db} = $db;
}
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("Skipping $table_name because it no longer exists");
if ( !$self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
next;
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database',$self->{db});
$self->{tbls} = \@tbls;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
TABLE:
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("$table_name no longer exists");
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
}
next TABLE;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
}
}
}
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
} # DATABASE
return $self->_iterate_dbh();
PTDEBUG && _d('No more databases');
return;
}
sub database_is_allowed {

View File

@@ -1467,7 +1467,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1481,7 +1481,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -2115,8 +2115,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -2183,9 +2183,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;

View File

@@ -61,7 +61,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -2347,7 +2347,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -2361,7 +2361,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -4579,8 +4579,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -4647,9 +4647,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;
@@ -10255,6 +10255,10 @@ sub identical_rows {
my $n_vals = $size_array1 - 1; # arrays are zero-indexed
for my $i ( 0..$n_vals ) {
# NULL == NULL
# https://bugs.launchpad.net/percona-toolkit/+bug/1168434
next if !defined $array1->[$i] && !defined $array2->[$i];
if ( defined $array1->[$i] && defined $array2->[$i] ) {
return 0 unless $array1->[$i] eq $array2->[$i];
}

View File

@@ -44,7 +44,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';
@@ -1107,7 +1107,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1121,7 +1121,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,
@@ -3376,7 +3376,9 @@ sub get_rules {
id => 'innodb_max_dirty_pages_pct',
code => sub {
my ( %args ) = @_;
return _var_lt($args{variables}->{innodb_max_dirty_pages_pct}, 90);
my $mysql_version = $args{mysql_version};
return _var_lt($args{variables}->{innodb_max_dirty_pages_pct},
($mysql_version < '5.5' ? 90 : 75));
},
},
{
@@ -5519,9 +5521,9 @@ flush_time seconds.
severity: warn
The key buffer size is unconfigured. In a production
environment it should always be configured explicitly, and the default
8MB size is not good.
The key buffer size is set to its default value, which is not good
for most production systems. In a production environment, key_buffer_size
should be larger than the default 8MB size.
=item large_pages

View File

@@ -1704,7 +1704,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1718,7 +1718,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -50,7 +50,7 @@ copyright = u'2013, Percona Ireland Ltd'
# The short X.Y version.
version = '2.2'
# The full version, including alpha/beta/rc tags.
release = '2.2.3'
release = '2.2.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -562,6 +562,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA.
=head1 VERSION
Percona Toolkit v2.2.3 released 2013-06-17
Percona Toolkit v2.2.4 released 2013-07-17
=cut

View File

@@ -1,6 +1,52 @@
Release Notes
*************
v2.2.4 released 2013-07-17
==========================
Percona Toolkit 2.2.4 has been released. This release two new features and number of bugfixes.
pt-query-digest --output json includes query examples as of v2.2.3. Some people might not want this because it exposes real data. New option, --output json-anon, has been implemented. This option will provide the same data without query examples. It's "anonymous" in the sense that there's no identifying data; nothing more than schema and table structs can be inferred from fingerprints.
When using drop swap with pt-online-schema-change there is some production impact. This impact can be measured because tool outputs the current timestamp on lines for operations that may take awhile.
* Fixed bug #1163735: pt-table-checksum fails if explicit_defaults_for_timestamp is enabled in 5.6
pt-table-checksum would fail if variable explicit_defaults_for_timestamp was enabled in MySQL 5.6.
* Fixed bug #1182856: Zero values causes "Invalid --set-vars value: var=0"
Trying to assign 0 to any variable by using --set-vars option would cause “Invalid --set-vars value” message.
* Fixed bug #1188264: pt-online-schema-change error copying rows: Undefined subroutine &pt_online_schema_change::get
Fixed the typo in the pt-online-schema-change code that could lead to a tool crash when copying the rows.
* Fixed bug #1199591: pt-table-checksum doesn't use non-unique index with highest cardinality
pt-table-checksum was using the first non-unique index instead of the one with the highest cardinality due to a sorting bug.
Percona Toolkit packages can be downloaded from
http://www.percona.com/downloads/percona-toolkit/ or the Percona Software
Repositories (http://www.percona.com/software/repositories
Changelog
---------
* Added pt-query-digest anonymous JSON output
* Added pt-online-schema-change timestamp output
* Fixed bug #1136559: pt-table-checksum: Deep recursion on subroutine "SchemaIterator::_iterate_dbh"
* Fixed bug #1163735: pt-table-checksum fails if explicit_defaults_for_timestamp is enabled in 5.6
* Fixed bug #1182856: Zero values causes "Invalid --set-vars value: var=0"
* Fixed bug #1188264: pt-online-schema-change error copying rows: Undefined subroutine &pt_online_schema_change::get
* Fixed bug #1195034: pt-deadlock-logger error: Use of uninitialized value $ts in pattern match (m//)
* Fixed bug #1199591: pt-table-checksum doesn't use non-unique index with highest cardinality
* Fixed bug #1168434: pt-upgrade reports differences on NULL
* Fixed bug #1172317: pt-sift does not work if pt-stalk did not collect due to a full disk
* Fixed bug #1176010: pt-query-digest doesn't group db and `db` together
* Fixed bug #1137556: pt-heartbeat docs don't account for --utc
* Fixed bug #1168106: pt-variable-advisor has the wrong default value for innodb_max_dirty_pages_pct in 5.5 and 5.6
* Fixed bug #1168110: pt-variable-advisor shows key_buffer_size in 5.6 as unconfigured (even though it is)
* Fixed bug #1171968: pt-query-digest docs don't mention --type=rawlog
* Fixed bug #1174956: pt-query-digest and pt-fingerprint don't strip some multi-line comments
v2.2.3 released 2013-06-17
==========================

View File

@@ -228,10 +228,12 @@ override query_report => sub {
distillate => $distill,
attribute => $groupby,
query_count => $times_seen,
example => {
query => substr($sample->{arg}, 0, $self->max_query_length),
ts => $sample->{ts} ? parse_timestamp($sample->{ts}) : undef,
},
$args{anon} ? () : (
example => {
query => substr($sample->{arg}, 0, $self->max_query_length),
ts => $sample->{ts} ? parse_timestamp($sample->{ts}) : undef,
},
),
};
my %metrics;
@@ -340,26 +342,28 @@ override query_report => sub {
push @tables, { status => $status, create => $create };
}
# Convert possible non-SELECTs for EXPLAIN.
if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) {
if ( $item =~ m/^(?:insert|replace)/ ) {
# Cannot convert or EXPLAIN INSERT or REPLACE queries.
if ( !$args{anon} ) {
# Convert possible non-SELECTs for EXPLAIN.
if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) {
if ( $item =~ m/^(?:insert|replace)/ ) {
# Cannot convert or EXPLAIN INSERT or REPLACE queries.
}
else {
# SELECT queries don't need to converted for EXPLAIN.
# TODO: return the actual EXPLAIN plan
# $self->explain_report($query, $vals->{default_db});
}
}
else {
# SELECT queries don't need to converted for EXPLAIN.
# TODO: return the actual EXPLAIN plan
# $self->explain_report($query, $vals->{default_db});
}
}
else {
# Query is not SELECT, INSERT, or REPLACE, so we can convert
# it for EXPLAIN.
my $converted = $qr->convert_to_select(
$sample->{arg} || '',
);
if ( $converted && $converted =~ m/^[\(\s]*select/i ) {
$class->{example}->{as_select} = $converted;
# Query is not SELECT, INSERT, or REPLACE, so we can convert
# it for EXPLAIN.
my $converted = $qr->convert_to_select(
$sample->{arg} || '',
);
if ( $converted && $converted =~ m/^[\(\s]*select/i ) {
$class->{example}->{as_select} = $converted;
}
}
}
}

View File

@@ -554,7 +554,7 @@ sub _find_best_index {
@possible_indexes = sort {
# Prefer the index with the highest cardinality.
my $cmp
= $indexes->{$b}->{cardinality} <=> $indexes->{$b}->{cardinality};
= $indexes->{$b}->{cardinality} <=> $indexes->{$a}->{cardinality};
if ( $cmp == 0 ) {
# Indexes have the same cardinality; prefer the one with
# more columns.

View File

@@ -1289,7 +1289,7 @@ sub set_vars {
if ( $user_vars ) {
foreach my $var_val ( @$user_vars ) {
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$user_vars{$var} = {
val => $val,
default => 0,
@@ -1303,7 +1303,7 @@ sub set_vars {
%default_vars = map {
my $var_val = $_;
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
die "Invalid --set-vars value: $var_val\n" unless $var && $val;
die "Invalid --set-vars value: $var_val\n" unless $var && defined $val;
$var => {
val => $val,
default => 1,

View File

@@ -19,7 +19,7 @@
# ###########################################################################
package Percona::Toolkit;
our $VERSION = '2.2.3';
our $VERSION = '2.2.4';
use strict;
use warnings FATAL => 'all';

View File

@@ -62,8 +62,8 @@ sub new {
sub strip_comments {
my ( $self, $query ) = @_;
return unless $query;
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
if ( $query =~ m/$vlc_rf/i ) { # contains show + version
$query =~ s/$vlc_re//go;
}
@@ -166,9 +166,9 @@ sub fingerprint {
if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) {
$query = $beginning; # Shorten multi-value INSERT statements ASAP
}
$query =~ s/$olc_re//go;
$query =~ s/$mlc_re//go;
$query =~ s/$olc_re//go;
$query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE
&& return $query;

View File

@@ -334,64 +334,67 @@ sub _iterate_dbh {
$self->{dbs} = \@dbs;
}
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
PTDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
DATABASE:
while ( $self->{db} || defined(my $db = shift @{$self->{dbs}}) ) {
if ( !$self->{db} ) {
PTDEBUG && _d('Next database:', $db);
$self->{db} = $db;
}
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
# SHOW CREATE TABLE failed. This is a bit puzzling;
# maybe the table got dropped, or crashed. Not much we can
# do about it; If the table is missing, just PTDEBUG it, but
# otherwise, warn with the error.
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("Skipping $table_name because it no longer exists");
if ( !$self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
PTDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
grep {
my ($tbl, $type) = @$_;
(!$type || ($type ne 'VIEW'))
&& $self->_resume_from_table($tbl)
&& $self->table_is_allowed($self->{db}, $tbl);
}
next;
@{$dbh->selectall_arrayref($sql)};
PTDEBUG && _d('Found', scalar @tbls, 'tables in database',$self->{db});
$self->{tbls} = \@tbls;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
TABLE:
while ( my $tbl = shift @{$self->{tbls}} ) {
my $ddl = eval { $tp->get_create_table($dbh, $self->{db}, $tbl) };
if ( my $e = $EVAL_ERROR ) {
my $table_name = "$self->{db}.$tbl";
# SHOW CREATE TABLE failed. This is a bit puzzling;
# maybe the table got dropped, or crashed. Not much we can
# do about it; If the table is missing, just PTDEBUG it, but
# otherwise, warn with the error.
if ( $e =~ /\QTable '$table_name' doesn't exist/ ) {
PTDEBUG && _d("$table_name no longer exists");
}
else {
warn "Skipping $table_name because SHOW CREATE TABLE failed: $e";
}
next TABLE;
}
my $tbl_struct = $tp->parse($ddl);
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_struct => $tbl_struct,
};
}
}
}
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
PTDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
} # DATABASE
# Recurse to get the next database. If there's no next db, then the
# call will return undef and we'll return undef, too.
return $self->_iterate_dbh();
PTDEBUG && _d('No more databases');
return;
}
sub database_is_allowed {

View File

@@ -214,7 +214,9 @@ sub get_rules {
id => 'innodb_max_dirty_pages_pct',
code => sub {
my ( %args ) = @_;
return _var_lt($args{variables}->{innodb_max_dirty_pages_pct}, 90);
my $mysql_version = $args{mysql_version};
return _var_lt($args{variables}->{innodb_max_dirty_pages_pct},
($mysql_version < '5.5' ? 90 : 75));
},
},
{

View File

@@ -113,6 +113,10 @@ make_sandbox() {
echo "query_cache_size=$QUERY_CACHE_SIZE" >> /tmp/$port/my.sandbox.cnf
fi
if [ -n "$EXTRA_DEFAULTS_FILE" ]; then
cat "$EXTRA_DEFAULTS_FILE" >> /tmp/$port/my.sandbox.cnf
fi
# If the sandbox is a slave, set it read_only.
if [ "$type" = "slave" ]; then
echo "read_only" >> /tmp/$port/my.sandbox.cnf

View File

@@ -38,9 +38,6 @@ my $dbh = $sb->get_dbh_for('master');
if ( !$dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
else {
plan tests => 54;
}
my $q = new Quoter();
my $tp = new TableParser(Quoter=>$q);
@@ -831,6 +828,26 @@ is_deeply(
"Bug 995274: nibble iter works"
);
# #############################################################################
# pt-table-checksum doesn't use non-unique index with highest cardinality
# https://bugs.launchpad.net/percona-toolkit/+bug/1199591
# #############################################################################
diag(`/tmp/12345/use < $trunk/t/lib/samples/cardinality.sql >/dev/null`);
$ni = make_nibble_iter(
db => 'cardb',
tbl => 't',
argv => [qw(--databases cardb --chunk-size 2)],
);
is(
$ni->{index},
'b',
"Use non-unique index with highest cardinality (bug 1199591)"
);
# #############################################################################
# Done.
# #############################################################################
@@ -846,4 +863,4 @@ like(
);
$sb->wipe_clean($dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;
done_testing;

View File

@@ -2021,6 +2021,48 @@ is(
"Non-zero exit status on error parsing options (bug 1039074)"
);
# #############################################################################
# --set-vars/set_vars()
# #############################################################################
@ARGV = qw();
$o = new OptionParser(file => "$trunk/bin/pt-archiver");
$o->get_specs();
$o->get_opts();
my $vars = $o->set_vars("$trunk/bin/pt-archiver");
is_deeply(
$vars,
{
wait_timeout => {
default => 1,
val => '10000',
},
},
"set_vars(): 1 default from docs"
) or diag(Dumper($vars));
# Bug 1182856: Zero values causes "Invalid --set-vars value: var=0"
@ARGV = qw(--set-vars SQL_LOG_BIN=0);
$o->get_opts();
$vars = $o->set_vars("$trunk/bin/pt-archiver");
is_deeply(
$vars,
{
wait_timeout => {
default => 1,
val => '10000',
},
SQL_LOG_BIN => {
default => 0,
val => '0',
},
},
"set_vars(): var=0 (bug 1182856)"
) or diag(Dumper($vars));
# #############################################################################
# Done.
# #############################################################################

View File

@@ -10,7 +10,7 @@ BEGIN {
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More tests => 271;
use Test::More;
use QueryRewriter;
use QueryParser;
@@ -407,6 +407,15 @@ is(
"Fingerprint db.tbl<number>name (preserve number)"
);
is(
$qr->fingerprint(
"/* -- S++ SU ABORTABLE -- spd_user: rspadim */SELECT SQL_SMALL_RESULT SQL_CACHE DISTINCT centro_atividade FROM est_dia WHERE unidade_id=1001 AND item_id=67 AND item_id_red=573"
),
"select sql_small_result sql_cache distinct centro_atividade from est_dia where unidade_id=? and item_id=? and item_id_red=?",
"Fingerprint /* -- comment */ SELECT (bug 1174956)"
);
# #############################################################################
# convert_to_select()
# #############################################################################
@@ -1406,4 +1415,4 @@ is(
# #############################################################################
# Done.
# #############################################################################
exit;
done_testing;

View File

@@ -547,10 +547,24 @@ eval {
diag(`$trunk/sandbox/stop-sandbox $master3_port >/dev/null`);
# #############################################################################
# Bug 1136559: Deep recursion on subroutine "SchemaIterator::_iterate_dbh"
# #############################################################################
$sb->wipe_clean($dbh);
diag(`/tmp/12345/use < $trunk/t/lib/samples/100-dbs.sql`);
test_so(
filters => [],
result => "foo001.bar001 ",
lives_ok => 1,
test_name => "Bug 1136559: Deep recursion on subroutine SchemaIterator::_iterate_dbh",
);
diag(`/tmp/12345/use < $trunk/t/lib/samples/100-dbs-drop.sql`);
# #############################################################################
# Done.
# #############################################################################
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;
exit;

View File

@@ -0,0 +1,100 @@
DROP DATABASE IF EXISTS foo001;
DROP DATABASE IF EXISTS foo002;
DROP DATABASE IF EXISTS foo003;
DROP DATABASE IF EXISTS foo004;
DROP DATABASE IF EXISTS foo005;
DROP DATABASE IF EXISTS foo006;
DROP DATABASE IF EXISTS foo007;
DROP DATABASE IF EXISTS foo008;
DROP DATABASE IF EXISTS foo009;
DROP DATABASE IF EXISTS foo010;
DROP DATABASE IF EXISTS foo011;
DROP DATABASE IF EXISTS foo012;
DROP DATABASE IF EXISTS foo013;
DROP DATABASE IF EXISTS foo014;
DROP DATABASE IF EXISTS foo015;
DROP DATABASE IF EXISTS foo016;
DROP DATABASE IF EXISTS foo017;
DROP DATABASE IF EXISTS foo018;
DROP DATABASE IF EXISTS foo019;
DROP DATABASE IF EXISTS foo020;
DROP DATABASE IF EXISTS foo021;
DROP DATABASE IF EXISTS foo022;
DROP DATABASE IF EXISTS foo023;
DROP DATABASE IF EXISTS foo024;
DROP DATABASE IF EXISTS foo025;
DROP DATABASE IF EXISTS foo026;
DROP DATABASE IF EXISTS foo027;
DROP DATABASE IF EXISTS foo028;
DROP DATABASE IF EXISTS foo029;
DROP DATABASE IF EXISTS foo030;
DROP DATABASE IF EXISTS foo031;
DROP DATABASE IF EXISTS foo032;
DROP DATABASE IF EXISTS foo033;
DROP DATABASE IF EXISTS foo034;
DROP DATABASE IF EXISTS foo035;
DROP DATABASE IF EXISTS foo036;
DROP DATABASE IF EXISTS foo037;
DROP DATABASE IF EXISTS foo038;
DROP DATABASE IF EXISTS foo039;
DROP DATABASE IF EXISTS foo040;
DROP DATABASE IF EXISTS foo041;
DROP DATABASE IF EXISTS foo042;
DROP DATABASE IF EXISTS foo043;
DROP DATABASE IF EXISTS foo044;
DROP DATABASE IF EXISTS foo045;
DROP DATABASE IF EXISTS foo046;
DROP DATABASE IF EXISTS foo047;
DROP DATABASE IF EXISTS foo048;
DROP DATABASE IF EXISTS foo049;
DROP DATABASE IF EXISTS foo050;
DROP DATABASE IF EXISTS foo051;
DROP DATABASE IF EXISTS foo052;
DROP DATABASE IF EXISTS foo053;
DROP DATABASE IF EXISTS foo054;
DROP DATABASE IF EXISTS foo055;
DROP DATABASE IF EXISTS foo056;
DROP DATABASE IF EXISTS foo057;
DROP DATABASE IF EXISTS foo058;
DROP DATABASE IF EXISTS foo059;
DROP DATABASE IF EXISTS foo060;
DROP DATABASE IF EXISTS foo061;
DROP DATABASE IF EXISTS foo062;
DROP DATABASE IF EXISTS foo063;
DROP DATABASE IF EXISTS foo064;
DROP DATABASE IF EXISTS foo065;
DROP DATABASE IF EXISTS foo066;
DROP DATABASE IF EXISTS foo067;
DROP DATABASE IF EXISTS foo068;
DROP DATABASE IF EXISTS foo069;
DROP DATABASE IF EXISTS foo070;
DROP DATABASE IF EXISTS foo071;
DROP DATABASE IF EXISTS foo072;
DROP DATABASE IF EXISTS foo073;
DROP DATABASE IF EXISTS foo074;
DROP DATABASE IF EXISTS foo075;
DROP DATABASE IF EXISTS foo076;
DROP DATABASE IF EXISTS foo077;
DROP DATABASE IF EXISTS foo078;
DROP DATABASE IF EXISTS foo079;
DROP DATABASE IF EXISTS foo080;
DROP DATABASE IF EXISTS foo081;
DROP DATABASE IF EXISTS foo082;
DROP DATABASE IF EXISTS foo083;
DROP DATABASE IF EXISTS foo084;
DROP DATABASE IF EXISTS foo085;
DROP DATABASE IF EXISTS foo086;
DROP DATABASE IF EXISTS foo087;
DROP DATABASE IF EXISTS foo088;
DROP DATABASE IF EXISTS foo089;
DROP DATABASE IF EXISTS foo090;
DROP DATABASE IF EXISTS foo091;
DROP DATABASE IF EXISTS foo092;
DROP DATABASE IF EXISTS foo093;
DROP DATABASE IF EXISTS foo094;
DROP DATABASE IF EXISTS foo095;
DROP DATABASE IF EXISTS foo096;
DROP DATABASE IF EXISTS foo097;
DROP DATABASE IF EXISTS foo098;
DROP DATABASE IF EXISTS foo099;
DROP DATABASE IF EXISTS foo100;

105
t/lib/samples/100-dbs.sql Normal file
View File

@@ -0,0 +1,105 @@
CREATE DATABASE IF NOT EXISTS foo001;
CREATE DATABASE IF NOT EXISTS foo002;
CREATE DATABASE IF NOT EXISTS foo003;
CREATE DATABASE IF NOT EXISTS foo004;
CREATE DATABASE IF NOT EXISTS foo005;
CREATE DATABASE IF NOT EXISTS foo006;
CREATE DATABASE IF NOT EXISTS foo007;
CREATE DATABASE IF NOT EXISTS foo008;
CREATE DATABASE IF NOT EXISTS foo009;
CREATE DATABASE IF NOT EXISTS foo010;
CREATE DATABASE IF NOT EXISTS foo011;
CREATE DATABASE IF NOT EXISTS foo012;
CREATE DATABASE IF NOT EXISTS foo013;
CREATE DATABASE IF NOT EXISTS foo014;
CREATE DATABASE IF NOT EXISTS foo015;
CREATE DATABASE IF NOT EXISTS foo016;
CREATE DATABASE IF NOT EXISTS foo017;
CREATE DATABASE IF NOT EXISTS foo018;
CREATE DATABASE IF NOT EXISTS foo019;
CREATE DATABASE IF NOT EXISTS foo020;
CREATE DATABASE IF NOT EXISTS foo021;
CREATE DATABASE IF NOT EXISTS foo022;
CREATE DATABASE IF NOT EXISTS foo023;
CREATE DATABASE IF NOT EXISTS foo024;
CREATE DATABASE IF NOT EXISTS foo025;
CREATE DATABASE IF NOT EXISTS foo026;
CREATE DATABASE IF NOT EXISTS foo027;
CREATE DATABASE IF NOT EXISTS foo028;
CREATE DATABASE IF NOT EXISTS foo029;
CREATE DATABASE IF NOT EXISTS foo030;
CREATE DATABASE IF NOT EXISTS foo031;
CREATE DATABASE IF NOT EXISTS foo032;
CREATE DATABASE IF NOT EXISTS foo033;
CREATE DATABASE IF NOT EXISTS foo034;
CREATE DATABASE IF NOT EXISTS foo035;
CREATE DATABASE IF NOT EXISTS foo036;
CREATE DATABASE IF NOT EXISTS foo037;
CREATE DATABASE IF NOT EXISTS foo038;
CREATE DATABASE IF NOT EXISTS foo039;
CREATE DATABASE IF NOT EXISTS foo040;
CREATE DATABASE IF NOT EXISTS foo041;
CREATE DATABASE IF NOT EXISTS foo042;
CREATE DATABASE IF NOT EXISTS foo043;
CREATE DATABASE IF NOT EXISTS foo044;
CREATE DATABASE IF NOT EXISTS foo045;
CREATE DATABASE IF NOT EXISTS foo046;
CREATE DATABASE IF NOT EXISTS foo047;
CREATE DATABASE IF NOT EXISTS foo048;
CREATE DATABASE IF NOT EXISTS foo049;
CREATE DATABASE IF NOT EXISTS foo050;
CREATE DATABASE IF NOT EXISTS foo051;
CREATE DATABASE IF NOT EXISTS foo052;
CREATE DATABASE IF NOT EXISTS foo053;
CREATE DATABASE IF NOT EXISTS foo054;
CREATE DATABASE IF NOT EXISTS foo055;
CREATE DATABASE IF NOT EXISTS foo056;
CREATE DATABASE IF NOT EXISTS foo057;
CREATE DATABASE IF NOT EXISTS foo058;
CREATE DATABASE IF NOT EXISTS foo059;
CREATE DATABASE IF NOT EXISTS foo060;
CREATE DATABASE IF NOT EXISTS foo061;
CREATE DATABASE IF NOT EXISTS foo062;
CREATE DATABASE IF NOT EXISTS foo063;
CREATE DATABASE IF NOT EXISTS foo064;
CREATE DATABASE IF NOT EXISTS foo065;
CREATE DATABASE IF NOT EXISTS foo066;
CREATE DATABASE IF NOT EXISTS foo067;
CREATE DATABASE IF NOT EXISTS foo068;
CREATE DATABASE IF NOT EXISTS foo069;
CREATE DATABASE IF NOT EXISTS foo070;
CREATE DATABASE IF NOT EXISTS foo071;
CREATE DATABASE IF NOT EXISTS foo072;
CREATE DATABASE IF NOT EXISTS foo073;
CREATE DATABASE IF NOT EXISTS foo074;
CREATE DATABASE IF NOT EXISTS foo075;
CREATE DATABASE IF NOT EXISTS foo076;
CREATE DATABASE IF NOT EXISTS foo077;
CREATE DATABASE IF NOT EXISTS foo078;
CREATE DATABASE IF NOT EXISTS foo079;
CREATE DATABASE IF NOT EXISTS foo080;
CREATE DATABASE IF NOT EXISTS foo081;
CREATE DATABASE IF NOT EXISTS foo082;
CREATE DATABASE IF NOT EXISTS foo083;
CREATE DATABASE IF NOT EXISTS foo084;
CREATE DATABASE IF NOT EXISTS foo085;
CREATE DATABASE IF NOT EXISTS foo086;
CREATE DATABASE IF NOT EXISTS foo087;
CREATE DATABASE IF NOT EXISTS foo088;
CREATE DATABASE IF NOT EXISTS foo089;
CREATE DATABASE IF NOT EXISTS foo090;
CREATE DATABASE IF NOT EXISTS foo091;
CREATE DATABASE IF NOT EXISTS foo092;
CREATE DATABASE IF NOT EXISTS foo093;
CREATE DATABASE IF NOT EXISTS foo094;
CREATE DATABASE IF NOT EXISTS foo095;
CREATE DATABASE IF NOT EXISTS foo096;
CREATE DATABASE IF NOT EXISTS foo097;
CREATE DATABASE IF NOT EXISTS foo098;
CREATE DATABASE IF NOT EXISTS foo099;
CREATE DATABASE IF NOT EXISTS foo100;
CREATE TABLE IF NOT EXISTS foo001.bar001 (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`value` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@@ -0,0 +1,49 @@
DROP DATABASE IF EXISTS cardb;
CREATE DATABASE cardb;
USE cardb;
CREATE TABLE t (
high INT UNSIGNED NOT NULL,
low INT UNSIGNED NOT NULL,
INDEX a (low),
INDEX b (high),
INDEX c (low)
) ENGINE=InnoDB;
INSERT INTO t VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 1),
(7, 1),
(8, 1),
(9, 1),
(10, 1),
(11, 1),
(12, 1),
(13, 1),
(14, 1),
(15, 1),
(16, 1),
(17, 1),
(18, 1),
(19, 1),
(20, 1),
(21, 2),
(22, 2),
(23, 2),
(24, 2),
(25, 2),
(26, 2),
(27, 2),
(28, 2),
(29, 2),
(30, 2),
(31, 2),
(32, 2),
(33, 2),
(34, 2),
(35, 2),
(36, 2),
(37, 2);
ANALYZE TABLE t;

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,8 @@ use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-deadlock-logger";
use Data::Dumper;
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/903443
# pt-deadlock-logger crashes on MySQL 5.5
@@ -119,6 +121,21 @@ is_deeply(
"Bug 1082104: pt-deadlock-logger shows host as user when the username has a dash in the name",
);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1195034
# pt-deadlock-logger error: Use of uninitialized value $ts in pattern match
# #############################################################################
$innodb_status_sample = load_file("t/pt-deadlock-logger/samples/bug_1195034.txt");
my $deadlocks = pt_deadlock_logger::parse_deadlocks($innodb_status_sample);
is_deeply(
$deadlocks,
{
},
"Bug 1195034: TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH"
) or diag(Dumper($deadlocks));
# #############################################################################
# Done.
# #############################################################################

View File

@@ -0,0 +1,14 @@
------------------------
LATEST DETECTED DEADLOCK
------------------------
130624 17:39:24TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION
*** TRANSACTION:
TRANSACTION 3BF88F886, ACTIVE 0 sec setting auto-inc lock
mysql tables in use 1, locked 1
1 lock struct(s), heap size 376, 0 row lock(s)
MySQL thread id 23512694, OS thread handle 0x5055b940, query id 734303798 10.10.10.1 host update
INSERT INTO gr_v3_response_log (query_key, time_received, time_to_respond, status, raw_response, api_host, api_path, api_client) VALUES ('...
*** WAITING FOR THIS LOCK TO BE GRANTED:
TABLE LOCK table `db`.`gr_v3_response_log` trx id 3BF88F886 lock mode AUTO-INC waiting

View File

@@ -12,6 +12,8 @@ use English qw(-no_match_vars);
use Test::More;
use Time::HiRes qw(sleep);
$ENV{PTTEST_FAKE_TS} = 1;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-online-schema-change";
@@ -696,7 +698,7 @@ ok(
"$sample/stats-dry-run.txt",
),
"--statistics --dry-run"
);
) or diag($test_diff);
ok(
no_diff(
@@ -709,7 +711,7 @@ ok(
: "$sample/stats-execute.txt"),
),
"--statistics --execute"
);
) or diag($test_diff);
# #############################################################################
# --default-engine

View File

@@ -77,9 +77,11 @@ $sb->load_file('master', "$sample/bug-1002448.sql");
);
unlike $output,
qr/\QThe new table `test1002448`.`_table_name_new` does not have a PRIMARY KEY or a unique index which is required for the DELETE trigger/,
"Bug 1002448: mistakenly uses indexes instead of keys";
unlike(
$output,
qr/\QThe new table `test1002448`.`_table_name_new` does not have a PRIMARY KEY or a unique index which is required for the DELETE trigger/,
"Bug 1002448: mistakenly uses indexes instead of keys"
);
# ############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1003315
@@ -95,19 +97,26 @@ $sb->load_file('master', "$sample/bug-1003315.sql");
"--alter-foreign-keys-method", "auto",
"--dry-run",
qw(--chunk-size 2 --dry-run --print))
},
);
is $exit_status, 0, "Bug 1003315: Correct exit value for a dry run";
is(
$exit_status,
0,
"Bug 1003315: Correct exit value for a dry run"
);
unlike $output,
unlike(
$output,
qr/\QError updating foreign key constraints: Invalid --alter-foreign-keys-method:/,
"Bug 1003315: No error when combining --alter-foreign-keys-method auto and --dry-run";
"Bug 1003315: No error when combining --alter-foreign-keys-method auto and --dry-run"
);
like $output,
qr/\QNot updating foreign key constraints because this is a dry run./,
"Bug 1003315: But now we do get an explanation from --dry-run";
like(
$output,
qr/\QNot updating foreign key constraints because this is a dry run./,
"Bug 1003315: But now we do get an explanation from --dry-run"
);
# ############################################################################
# This fakes the conditions to trigger the chunk index error
@@ -174,9 +183,11 @@ for my $i ( 0..4 ) {
$master_dbh->do(qq{create table `bug_1041372`.$tbl (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY )});
$master_dbh->do(qq{insert into `bug_1041372`.$tbl values (1), (2), (3), (4), (5)});
($output) = full_output(sub { pt_online_schema_change::main(@args,
'--alter', "ADD COLUMN ptosc INT",
'--execute', "$master_dsn,D=bug_1041372,t=$tbl")});
($output) = full_output(sub {
pt_online_schema_change::main(@args,
'--alter', "ADD COLUMN ptosc INT",
'--execute', "$master_dsn,D=bug_1041372,t=$tbl")
});
like(
$output,
@@ -261,7 +272,6 @@ $sb->load_file('master', "$sample/del-trg-bug-1062324.sql");
undef,
"Delete trigger works after altering PK (bug 1103672)"
);
}
# #############################################################################
@@ -293,6 +303,72 @@ else {
);
}
# ############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1171653
#
# ############################################################################
$sb->load_file('master', "$sample/utf8_charset_tbl.sql");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args,
"$master_dsn,D=test1171653,t=t",
"--alter", "drop column foo",
qw(--execute --print))
},
);
my $row = $master_dbh->selectrow_arrayref("SHOW CREATE TABLE test1171653.t");
like(
$row->[1],
qr/DEFAULT CHARSET=utf8/,
"Bug 1171653: table charset is not preserved"
);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1188264
# pt-online-schema-change error copying rows: Undefined subroutine
# &pt_online_schema_change::get
# #############################################################################
# In exec_nibble() we had:
# if ( get('statistics') ) {
# $err .= "but further occurrences will be reported "
# . "by --statistics when the tool finishes.\n";
# }
# which is called when copying rows causes a MySQL warning
# for the first time. So to test this code path, we need to
# cause a MySQL warning while copying rows.
$sb->load_file('master', "$sample/basic_no_fks_innodb.sql");
$master_dbh->do("INSERT INTO pt_osc.t VALUES (null, 'This string will be too long after we modify the table so it will cause a warning about the value being truncated in the new table. The other column values are a single character.', NOW())");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args,
"$master_dsn,D=pt_osc,t=t",
"--alter", "modify c varchar(8)",
qw(--execute --print))
},
);
is(
$exit_status,
0,
"Bug 1188264: 0 exit"
);
unlike(
$output,
qr/Undefined subroutine/i,
"Bug 1188264: no undefined subroutine"
);
like(
$output,
qr/error 1265/, # Data truncated for column 'c' at row 21
"Bug 1188264: warning about expected MySQL error 1265"
);
# #############################################################################
# Done.
# #############################################################################

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-online-schema-change";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $slave_dbh = $sb->get_dbh_for('slave1');
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
elsif ( !$slave_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave1';
}
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
# so we need to specify --set-vars innodb_lock_wait_timeout=3 else the
# tool will die.
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
my @args = (qw(--set-vars innodb_lock_wait_timeout=3));
my $sample = "t/pt-online-schema-change/samples/";
my $plugin = "$trunk/$sample/plugins";
my $output;
my $exit_status;
# ############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1171653
#
# ############################################################################
$sb->load_file('master', "$sample/basic_no_fks.sql");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args,
"$master_dsn,D=pt_osc,t=t",
"--alter", "CHARACTER SET utf8, MODIFY c CHAR(128) CHARACTER SET utf8",
'--plugin', "$plugin/show_create_new_table.pm",
qw(--quiet --execute)) },
);
my @create = split("\n\n", $output);
like(
$create[1],
qr/DEFAULT CHARSET=utf8/,
"Can alter charset of new table"
);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,30 @@
package pt_online_schema_change_plugin;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub new {
my ($class, %args) = @_;
my $self = { %args };
return bless $self, $class;
}
sub after_create_new_table {
my ($self, %args) = @_;
my $new_tbl = $args{new_tbl};
my $dbh = $self->{cxn}->dbh;
my $row = $dbh->selectrow_arrayref("SHOW CREATE TABLE $new_tbl->{name}");
warn "after_create_new_table: $row->[1]\n\n";
}
sub after_alter_new_table {
my ($self, %args) = @_;
my $new_tbl = $args{new_tbl};
my $dbh = $self->{cxn}->dbh;
my $row = $dbh->selectrow_arrayref("SHOW CREATE TABLE $new_tbl->{name}");
warn "after_alter_new_table: $row->[1]\n\n";
}
1;

View File

@@ -6,8 +6,8 @@ Operation, tries, wait:
update_foreign_keys, 10, 1
Starting a dry run. `bug_1045317`.`bits` will not be altered. Specify --execute instead of --dry-run to alter the table.
Not dropping triggers because this is a dry run.
Dropping new table...
Dropped new table OK.
TS Dropping new table...
TS Dropped new table OK.
# Event Count
# ====== =====
# INSERT 0

View File

@@ -5,8 +5,8 @@ Operation, tries, wait:
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `bug_1045317`.`bits`...
Dropping triggers...
Dropped triggers OK.
TS Dropping triggers...
TS Dropped triggers OK.
# Event Count
# ================== =====
# INSERT 1
@@ -16,11 +16,11 @@ Creating new table...
Created new table bug_1045317._bits_new OK.
Altering new table...
Altered `bug_1045317`.`_bits_new` OK.
Creating triggers...
Created triggers OK.
Copying approximately 3 rows...
Copied rows OK.
Swapping tables...
Swapped original and new tables OK.
Dropping old table...
Dropped old table `bug_1045317`.`_bits_old` OK.
TS Creating triggers...
TS Created triggers OK.
TS Copying approximately 3 rows...
TS Copied rows OK.
TS Swapping tables...
TS Swapped original and new tables OK.
TS Dropping old table...
TS Dropped old table `bug_1045317`.`_bits_old` OK.

View File

@@ -0,0 +1,11 @@
drop database if exists test1171653;
create database test1171653;
use test1171653;
CREATE TABLE `t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`foo` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t` VALUES (1,'bar'), (2,'bar2'), (3,'bar3');

View File

@@ -20,12 +20,12 @@ local $JSONReportFormatter::pretty_json = 1;
my @args = qw(--output json);
my $sample = "$trunk/t/lib/samples";
my $results = "t/pt-query-digest/samples";
my $results = "t/pt-query-digest/samples/json";
ok(
no_diff(
sub { pt_query_digest::main(@args, "$sample/slowlogs/empty") },
"$results/empty_report.txt",
"t/pt-query-digest/samples/empty_report.txt",
),
'json output for empty log'
) or diag($test_diff);
@@ -33,18 +33,30 @@ ok(
ok(
no_diff(
sub { pt_query_digest::main(@args, "$sample/slowlogs/slow002.txt") },
"$results/output_json_slow002.txt"
"$results/slow002.txt",
sed => [ qq/'s!$trunk!TRUNK!'/ ],
),
'json output for slow002'
) or diag($test_diff);
ok(
no_diff(
sub { pt_query_digest::main(qw(--output json-anon),
"$sample/slowlogs/slow002.txt") },
"$results/slow002-anon.txt",
sed => [ qq/'s!$trunk!TRUNK!'/ ],
),
'json-anon output for slow002'
) or diag($test_diff);
# --type tcpdump
ok(
no_diff(
sub { pt_query_digest::main(qw(--type tcpdump --limit 10 --watch-server 127.0.0.1:12345),
@args, "$sample/tcpdump/tcpdump021.txt") },
"$results/output_json_tcpdump021.txt",
"$results/tcpdump021.txt",
sed => [ qq/'s!$trunk!TRUNK!'/ ],
),
'json output for for tcpdump021',
) or diag($test_diff);

View File

@@ -1,2 +0,0 @@
# No events processed.

View File

@@ -0,0 +1,257 @@
{
"classes" : [
{
"attribute" : "fingerprint",
"checksum" : "66825DDC008FFA89",
"distillate" : "UPDATE db?.tuningdetail_?_? db?.gonzo",
"fingerprint" : "update d?tuningdetail_?_? n inner join d?gonzo a using(gonzo) set n.column? = a.column?, n.word? = a.word?",
"metrics" : {
"Filesort" : {
"yes" : "0"
},
"Filesort_on_disk" : {
"yes" : "0"
},
"Full_join" : {
"yes" : "0"
},
"Full_scan" : {
"yes" : "1"
},
"Lock_time" : {
"avg" : "0.000091",
"max" : "0.000091",
"median" : "0.000091",
"min" : "0.000091",
"pct" : "0.125000",
"pct_95" : "0.000091",
"stddev" : "0.000000",
"sum" : "0.000091"
},
"Merge_passes" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"QC_Hit" : {
"yes" : "0"
},
"Query_length" : {
"avg" : "129",
"max" : "129",
"median" : "129",
"min" : "129",
"pct" : "0",
"pct_95" : "129",
"stddev" : "0",
"sum" : "129"
},
"Query_time" : {
"avg" : "0.726052",
"max" : "0.726052",
"median" : "0.726052",
"min" : "0.726052",
"pct" : "0.125000",
"pct_95" : "0.726052",
"stddev" : "0.000000",
"sum" : "0.726052"
},
"Rows_examined" : {
"avg" : "62951",
"max" : "62951",
"median" : "62951",
"min" : "62951",
"pct" : "0",
"pct_95" : "62951",
"stddev" : "0",
"sum" : "62951"
},
"Rows_sent" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"Tmp_table" : {
"yes" : "0"
},
"Tmp_table_on_disk" : {
"yes" : "0"
},
"db" : {
"value" : "db1"
},
"host" : {
"value" : ""
},
"user" : {
"value" : "[SQL_SLAVE]"
}
},
"query_count" : 1,
"tables" : [
{
"create" : "SHOW CREATE TABLE `db2`.`tuningdetail_21_265507`\\G",
"status" : "SHOW TABLE STATUS FROM `db2` LIKE 'tuningdetail_21_265507'\\G"
},
{
"create" : "SHOW CREATE TABLE `db1`.`gonzo`\\G",
"status" : "SHOW TABLE STATUS FROM `db1` LIKE 'gonzo'\\G"
}
],
"ts_max" : "2007-12-18 11:48:27",
"ts_min" : "2007-12-18 11:48:27"
}
],
"global" : {
"files" : [
{
"name" : "TRUNK/t/lib/samples/slowlogs/slow002.txt",
"size" : 3841
}
],
"metrics" : {
"Filesort" : {
"cnt" : "0"
},
"Filesort_on_disk" : {
"cnt" : "0"
},
"Full_join" : {
"cnt" : "0"
},
"Full_scan" : {
"cnt" : "1"
},
"InnoDB_IO_r_bytes" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"InnoDB_IO_r_ops" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"InnoDB_IO_r_wait" : {
"avg" : "0.000000",
"max" : "0.000000",
"median" : "0.000000",
"min" : "0.000000",
"pct_95" : "0.000000",
"stddev" : "0.000000",
"sum" : "0.000000"
},
"InnoDB_pages_distinct" : {
"avg" : "17",
"max" : "24",
"median" : "17",
"min" : "11",
"pct_95" : "23",
"stddev" : "3",
"sum" : "107"
},
"InnoDB_queue_wait" : {
"avg" : "0.000000",
"max" : "0.000000",
"median" : "0.000000",
"min" : "0.000000",
"pct_95" : "0.000000",
"stddev" : "0.000000",
"sum" : "0.000000"
},
"InnoDB_rec_lock_wait" : {
"avg" : "0.000000",
"max" : "0.000000",
"median" : "0.000000",
"min" : "0.000000",
"pct_95" : "0.000000",
"stddev" : "0.000000",
"sum" : "0.000000"
},
"Lock_time" : {
"avg" : "0.000038",
"max" : "0.000091",
"median" : "0.000026",
"min" : "0.000000",
"pct_95" : "0.000089",
"stddev" : "0.000028",
"sum" : "0.000304"
},
"Merge_passes" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"QC_Hit" : {
"cnt" : "0"
},
"Query_length" : {
"avg" : "62",
"max" : "129",
"median" : "62",
"min" : "5",
"pct_95" : "124",
"stddev" : "34",
"sum" : "502"
},
"Query_time" : {
"avg" : "0.095260",
"max" : "0.726052",
"median" : "0.000516",
"min" : "0.000012",
"pct_95" : "0.705093",
"stddev" : "0.231765",
"sum" : "0.762080"
},
"Rows_examined" : {
"avg" : "7868",
"max" : "62951",
"median" : "0",
"min" : "0",
"pct_95" : "61003",
"stddev" : "20174",
"sum" : "62951"
},
"Rows_sent" : {
"avg" : "0",
"max" : "0",
"median" : "0",
"min" : "0",
"pct_95" : "0",
"stddev" : "0",
"sum" : "0"
},
"Tmp_table" : {
"cnt" : "0"
},
"Tmp_table_on_disk" : {
"cnt" : "0"
}
},
"query_count" : 8,
"unique_query_count" : 7
}
}

View File

@@ -121,7 +121,7 @@
"global" : {
"files" : [
{
"name" : "/Users/daniel/p/release-2.2.3/t/lib/samples/slowlogs/slow002.txt",
"name" : "TRUNK/t/lib/samples/slowlogs/slow002.txt",
"size" : 3841
}
],

View File

@@ -187,7 +187,7 @@
"global" : {
"files" : [
{
"name" : "/Users/daniel/p/release-2.2.3/t/lib/samples/tcpdump/tcpdump021.txt",
"name" : "TRUNK/t/lib/samples/tcpdump/tcpdump021.txt",
"size" : 2827
}
],

View File

@@ -0,0 +1,29 @@
# ########################################################################
# Report grouped by db
# ########################################################################
# Item 1: 0 QPS, 0x concurrency, ID 0x585AC494268B351B at byte 434 _______
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.01
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 100 4
# Exec time 100 21ms 2us 19ms 5ms 18ms 8ms 881us
# Lock time 100 9ms 0 9ms 2ms 9ms 4ms 0
# Rows sent 0 0 0 0 0 0 0 0
# Rows examine 0 0 0 0 0 0 0 0
# Query size 100 82 14 27 20.50 26.08 6.12 26.08
# String:
# Hosts
# Users meow
# Query_time distribution
# 1us ################################
# 10us
# 100us ################################################################
# 1ms
# 10ms ################################
# 100ms
# 1s
# 10s+
db

View File

@@ -393,6 +393,19 @@ ok(
'Analysis for slow056 (no query bug 1082599)'
);
# #############################################################################
# Bug 1176010: pt-query-digest should know how to group quoted and unquoted database names
# https://bugs.launchpad.net/percona-toolkit/+bug/1176010
#############################################################################
ok(
no_diff(
sub { pt_query_digest::main(@args, $sample.'slow057.txt',
qw(--group-by db)) },
"t/pt-query-digest/samples/slow057.txt",
),
'Analysis for slow057 (no grouping bug 1176010)'
) or diag($test_diff);
# #############################################################################
# Done.
# #############################################################################

View File

@@ -80,7 +80,7 @@ my $create_repl_table =
this_cnt int NOT NULL,
master_crc char(40) NULL,
master_cnt int NULL,
ts timestamp NOT NULL,
ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (db, tbl, chunk)
) ENGINE=InnoDB;";

View File

@@ -12,6 +12,6 @@ CREATE TABLE truncated_checksums (
this_cnt int NOT NULL,
master_crc char(40) NULL,
master_cnt int NULL,
ts timestamp NOT NULL,
ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (db, tbl, chunk)
) ENGINE=InnoDB;

View File

@@ -0,0 +1 @@
explicit_defaults_for_timestamp=ON

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-table-checksum";
if ( $sandbox_version lt '5.6' ) {
plan skip_all => 'Tests for MySQL 5.6';
}
diag(`$trunk/sandbox/stop-sandbox 12348 >/dev/null`);
diag(`EXTRA_DEFAULTS_FILE="$trunk/t/pt-table-checksum/samples/explicit_defaults_for_timestamp.cnf" $trunk/sandbox/start-sandbox master 12348 >/dev/null`);
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master1');
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master 12348';
}
my $master_dsn = 'h=127.1,P=12348,u=msandbox,p=msandbox';
my @args = ($master_dsn, '--max-load', '');
my $output;
my $retval;
$output = output(
sub { $retval = pt_table_checksum::main(@args, qw(-t mysql.user)) },
stderr => 1,
);
unlike(
$output,
qr/error 1364/i,
"explicit_defaults_for_timestamp (bug 1163735): no error"
);
# Exit will be non-zero because of "Diffs cannot be detected because
# no slaves were found."
# #############################################################################
# Done.
# #############################################################################
diag(`$trunk/sandbox/stop-sandbox 12348 >/dev/null`);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -111,6 +111,20 @@ test_diff (
],
);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1168434
# pt-upgrade reports differences on NULL
# #############################################################################
$sb->load_file('master', "t/pt-upgrade/samples/007/tables.sql");
test_diff(
name => 'Bug 1168434: no diff with NULL',
query1 => 'select * from test.t order by id',
query2 => 'select * from test.t order by id',
expect => [],
);
# #############################################################################
# Done.
# #############################################################################

View File

@@ -0,0 +1,4 @@
# User@Host: root[root] @ localhost []
# Query_time: 1 Lock_time: 0 Rows_sent: 7 Rows_examined: 7
use test;
select * from test.t order by id;

View File

@@ -0,0 +1,35 @@
#-----------------------------------------------------------------------
# Logs
#-----------------------------------------------------------------------
File: ...
Size: 145
#-----------------------------------------------------------------------
# Hosts
#-----------------------------------------------------------------------
host1:
DSN: h=127.1,P=12345
hostname: ...
MySQL: ...
host2:
DSN: h=127.1,P=12348
hostname: ...
MySQL: ...
#-----------------------------------------------------------------------
# Stats
#-----------------------------------------------------------------------
failed_queries 0
not_select 0
queries_filtered 0
queries_no_diffs 1
queries_read 1
queries_with_diffs 0
queries_with_errors 0

View File

@@ -0,0 +1,32 @@
#-----------------------------------------------------------------------
# Logs
#-----------------------------------------------------------------------
Results directory: ...
#-----------------------------------------------------------------------
# Hosts
#-----------------------------------------------------------------------
host1:
Reading results from ...
host2:
DSN: h=127.1,P=12348
hostname: ...
MySQL: ...
#-----------------------------------------------------------------------
# Stats
#-----------------------------------------------------------------------
failed_queries 0
not_select 0
queries_filtered 0
queries_no_diffs 1
queries_read 1
queries_with_diffs 0
queries_with_errors 0

View File

@@ -0,0 +1,3 @@
use `test`;
select * from test.t order by id
##

View File

@@ -0,0 +1,6 @@
$results = {
query_time => '0',
warnings => {}
};
##

View File

@@ -0,0 +1,12 @@
$rows = [
[
'1',
'a'
],
[
'2',
undef
]
];
##

View File

@@ -0,0 +1,11 @@
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
USE test;
CREATE TABLE t (
id int(10) NOT NULL AUTO_INCREMENT,
username varchar(8) default NULL,
PRIMARY KEY (`id`)
);
INSERT INTO t VALUES
(null, 'a'),
(null, null);

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-variable-advisor";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $dbh = $sb->get_dbh_for('master');
my $dsn = $sb->dsn_for('master');
if ( !$dbh ) {
plan skip_all => "Cannot connect to sandbox master";
}
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1168106
# pt-variable-advisor has the wrong default value for
# innodb_max_dirty_pages_pct in 5.6.10
# #############################################################################
my @args = "$dsn";
my $output = "";
$output = output(
sub { pt_variable_advisor::main(@args) },
);
unlike(
$output,
qr/innodb_max_dirty_pages_pct/,
"No innodb_max_dirty_pages_pct warning (bug 1168106)"
);
# #############################################################################
# Done.
# #############################################################################
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;