From e92fdfc2f6b4d52a55f093f4c34debfe9909b461 Mon Sep 17 00:00:00 2001 From: Kedar Date: Mon, 23 Mar 2026 20:34:19 +0530 Subject: [PATCH 1/2] PT-2519 - harden slow log parse and event aggregation --- bin/pt-index-usage | 4 ++++ bin/pt-query-digest | 10 +++++++++- bin/pt-table-usage | 4 ++++ bin/pt-upgrade | 4 ++++ lib/EventAggregator.pm | 9 ++++++++- lib/SlowLogParser.pm | 6 ++++++ 6 files changed, 35 insertions(+), 2 deletions(-) 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..c4c25825f 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 mis-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'); From 9f83cf0545368577c16d1152eace983ae5dfc419 Mon Sep 17 00:00:00 2001 From: Kedar Date: Tue, 24 Mar 2026 09:43:11 +0530 Subject: [PATCH 2/2] Update EventAggregator.pm fixed typo "mis" --- lib/EventAggregator.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/EventAggregator.pm b/lib/EventAggregator.pm index c4c25825f..728069ef9 100644 --- a/lib/EventAggregator.pm +++ b/lib/EventAggregator.pm @@ -428,7 +428,7 @@ 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 mis-sum). + # Num/bool sums must not use += on undef or '' (would warn or incorrectly sum). if ( $track{sum} ) { push @tmp, 'PLACE->{sum} += (defined $val && $val ne q{} ? $val : 0);'; }