diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 3bcd562d2..ed296d4c1 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -3029,6 +3029,10 @@ sub parse_event { } PTDEBUG && _d('Properties of event:', Dumper(\@properties)); + if ( @properties % 2 ) { + PTDEBUG && _d('Skipping malformed event (odd properties):', Dumper(\@properties)); + next EVENT; + } my $event = { @properties }; if ( !$event->{arg} ) { PTDEBUG && _d('Partial event, no arg'); diff --git a/bin/pt-query-digest b/bin/pt-query-digest index abeb8c94b..d0a20a467 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -5234,6 +5234,10 @@ sub parse_event { } PTDEBUG && _d('Properties of event:', Dumper(\@properties)); + if ( @properties % 2 ) { + PTDEBUG && _d('Skipping malformed event (odd properties):', Dumper(\@properties)); + next EVENT; + } my $event = { @properties }; if ( !$event->{arg} ) { PTDEBUG && _d('Partial event, no arg'); @@ -5625,6 +5629,10 @@ sub make_handler { ); } + if ( $type =~ m/^(?:num|bool)$/ ) { + push @lines, q{$val = 0 if defined $val && $val eq '';}; + } + if ( $type eq 'num' && $self->{attrib_limit} ) { push @lines, ( "if ( \$val > $self->{attrib_limit} ) {", @@ -5654,7 +5662,7 @@ sub make_handler { . $gt . ' PLACE->{max};', ); if ( $track{sum} ) { - push @tmp, 'PLACE->{sum} += $val;'; + push @tmp, 'PLACE->{sum} += (defined $val && $val ne q{} ? $val : 0);'; } if ( $track{all} ) { diff --git a/bin/pt-table-usage b/bin/pt-table-usage index a3882f876..86d7fcc9d 100755 --- a/bin/pt-table-usage +++ b/bin/pt-table-usage @@ -2451,6 +2451,10 @@ sub parse_event { } PTDEBUG && _d('Properties of event:', Dumper(\@properties)); + if ( @properties % 2 ) { + PTDEBUG && _d('Skipping malformed event (odd properties):', Dumper(\@properties)); + next EVENT; + } my $event = { @properties }; if ( !$event->{arg} ) { PTDEBUG && _d('Partial event, no arg'); diff --git a/bin/pt-upgrade b/bin/pt-upgrade index dc69194a7..825d189ff 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -6995,6 +6995,10 @@ sub parse_event { } PTDEBUG && _d('Properties of event:', Dumper(\@properties)); + if ( @properties % 2 ) { + PTDEBUG && _d('Skipping malformed event (odd properties):', Dumper(\@properties)); + next EVENT; + } my $event = { @properties }; if ( !$event->{arg} ) { PTDEBUG && _d('Partial event, no arg'); diff --git a/lib/EventAggregator.pm b/lib/EventAggregator.pm index 05624304e..728069ef9 100644 --- a/lib/EventAggregator.pm +++ b/lib/EventAggregator.pm @@ -380,6 +380,12 @@ sub make_handler { ); } + # Slow log and similar sources can leave numeric attributes as ''; treat as 0 + # so type detection and later arithmetic stay consistent. + if ( $type =~ m/^(?:num|bool)$/ ) { + push @lines, q{$val = 0 if defined $val && $val eq '';}; + } + # Make sure the value is constrained to legal limits. If it's out of # bounds, just use the last-seen value for it. if ( $type eq 'num' && $self->{attrib_limit} ) { @@ -422,8 +428,9 @@ sub make_handler { 'PLACE->{max} = $val if !defined PLACE->{max} || $val ' . $gt . ' PLACE->{max};', ); + # Num/bool sums must not use += on undef or '' (would warn or incorrectly sum). if ( $track{sum} ) { - push @tmp, 'PLACE->{sum} += $val;'; + push @tmp, 'PLACE->{sum} += (defined $val && $val ne q{} ? $val : 0);'; } # Save all values in a bucketed list. See bucket_idx() below. diff --git a/lib/SlowLogParser.pm b/lib/SlowLogParser.pm index fa35f587f..6c81ac196 100644 --- a/lib/SlowLogParser.pm +++ b/lib/SlowLogParser.pm @@ -309,6 +309,12 @@ sub parse_event { # Don't dump $event; want to see full dump of all properties, and after # it's been cast into a hash, duplicated keys will be gone. PTDEBUG && _d('Properties of event:', Dumper(\@properties)); + # An odd-length @properties list would pair keys/values wrong in the + # hash below; skip the event rather than corrupt aggregation. + if ( @properties % 2 ) { + PTDEBUG && _d('Skipping malformed event (odd properties):', Dumper(\@properties)); + next EVENT; + } my $event = { @properties }; if ( !$event->{arg} ) { PTDEBUG && _d('Partial event, no arg');