From ad7207139c8d643e8277cb361f88bf46e5e72373 Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Fri, 1 Mar 2013 18:57:20 -0700 Subject: [PATCH] Update OptionParser and DSNParser in all tools. --- bin/pt-archiver | 100 +++++++++++++++++++++++++++--- bin/pt-config-diff | 100 +++++++++++++++++++++++++++--- bin/pt-deadlock-logger | 100 +++++++++++++++++++++++++++--- bin/pt-duplicate-key-checker | 100 +++++++++++++++++++++++++++--- bin/pt-find | 100 +++++++++++++++++++++++++++--- bin/pt-fk-error-logger | 100 +++++++++++++++++++++++++++--- bin/pt-heartbeat | 100 +++++++++++++++++++++++++++--- bin/pt-index-usage | 100 +++++++++++++++++++++++++++--- bin/pt-kill | 100 +++++++++++++++++++++++++++--- bin/pt-query-advisor | 100 +++++++++++++++++++++++++++--- bin/pt-query-digest | 100 +++++++++++++++++++++++++++--- bin/pt-show-grants | 100 +++++++++++++++++++++++++++--- bin/pt-slave-delay | 100 +++++++++++++++++++++++++++--- bin/pt-slave-find | 100 +++++++++++++++++++++++++++--- bin/pt-slave-restart | 100 +++++++++++++++++++++++++++--- bin/pt-table-checksum | 100 +++++++++++++++++++++++++++--- bin/pt-table-sync | 100 +++++++++++++++++++++++++++--- bin/pt-table-usage | 115 +++++++++++++++++++++++++++++------ bin/pt-upgrade | 100 +++++++++++++++++++++++++++--- bin/pt-variable-advisor | 100 +++++++++++++++++++++++++++--- bin/pt-visual-explain | 115 +++++++++++++++++++++++++++++------ 21 files changed, 1944 insertions(+), 186 deletions(-) diff --git a/bin/pt-archiver b/bin/pt-archiver index 564e7c63..41350936 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -712,6 +712,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1695,6 +1696,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -2397,7 +2437,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2412,13 +2452,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2493,6 +2528,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-config-diff b/bin/pt-config-diff index acfaf017..93e7447a 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -712,6 +712,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1695,6 +1696,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1986,7 +2026,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2001,13 +2041,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2082,6 +2117,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index 171af30a..59853370 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -67,6 +67,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1050,6 +1051,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -2330,7 +2370,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2345,13 +2385,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2426,6 +2461,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-duplicate-key-checker b/bin/pt-duplicate-key-checker index edc7375b..c1d85d4e 100755 --- a/bin/pt-duplicate-key-checker +++ b/bin/pt-duplicate-key-checker @@ -875,7 +875,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -890,13 +890,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -971,6 +966,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1003,6 +1047,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1986,6 +2031,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-find b/bin/pt-find index 82240361..034da7b9 100755 --- a/bin/pt-find +++ b/bin/pt-find @@ -309,7 +309,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -324,13 +324,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -405,6 +400,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -437,6 +481,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1420,6 +1465,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index d618b03d..4aebfced 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -62,6 +62,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1045,6 +1046,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1487,7 +1527,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -1502,13 +1542,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1583,6 +1618,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 378511d2..fa36120b 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -797,6 +797,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1780,6 +1781,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -2071,7 +2111,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2086,13 +2126,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2167,6 +2202,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 37f41a4f..815c1425 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -319,7 +319,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -334,13 +334,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -415,6 +410,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -598,6 +642,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1581,6 +1626,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-kill b/bin/pt-kill index fe814a19..a97fa820 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -72,6 +72,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1055,6 +1056,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1990,7 +2030,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2005,13 +2045,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2086,6 +2121,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-query-advisor b/bin/pt-query-advisor index 91d19a15..1b91fdf4 100755 --- a/bin/pt-query-advisor +++ b/bin/pt-query-advisor @@ -969,7 +969,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -984,13 +984,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1065,6 +1060,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1097,6 +1141,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -2080,6 +2125,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-query-digest b/bin/pt-query-digest index 94c40e8d..6b837969 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -981,7 +981,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -996,13 +996,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1077,6 +1072,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1260,6 +1304,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -2243,6 +2288,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-show-grants b/bin/pt-show-grants index deb08a79..094fe641 100755 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -37,6 +37,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1020,6 +1021,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1311,7 +1351,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -1326,13 +1366,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1407,6 +1442,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-slave-delay b/bin/pt-slave-delay index 448dbfd6..49369e0e 100755 --- a/bin/pt-slave-delay +++ b/bin/pt-slave-delay @@ -65,6 +65,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1048,6 +1049,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1983,7 +2023,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -1998,13 +2038,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2079,6 +2114,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-slave-find b/bin/pt-slave-find index 48e281e6..dbe92565 100755 --- a/bin/pt-slave-find +++ b/bin/pt-slave-find @@ -45,6 +45,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1028,6 +1029,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1963,7 +2003,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -1978,13 +2018,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2059,6 +2094,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index 31b2a26a..4de3baba 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -217,6 +217,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1200,6 +1201,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -2329,7 +2369,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2344,13 +2384,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2425,6 +2460,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index b82f1264..fd85cb80 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -1555,7 +1555,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -1570,13 +1570,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1651,6 +1646,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1683,6 +1727,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -2666,6 +2711,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-table-sync b/bin/pt-table-sync index ed2caedf..7afc35ce 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -80,6 +80,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1063,6 +1064,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -2149,7 +2189,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2164,13 +2204,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2245,6 +2280,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-table-usage b/bin/pt-table-usage index 1d5365ce..2f01838d 100755 --- a/bin/pt-table-usage +++ b/bin/pt-table-usage @@ -300,7 +300,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -315,13 +315,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -396,6 +391,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -428,6 +472,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -449,7 +494,6 @@ sub new { 'default' => 1, 'cumulative' => 1, 'negatable' => 1, - 'value_is_optional' => 1, ); my $self = { @@ -691,10 +735,9 @@ sub _parse_specs { $opt->{short} = undef; } - $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; - $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; - $opt->{optional_value} = $opt->{spec} =~ m/:/ ? 1 : 0; - $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; + $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; + $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; + $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; $opt->{group} ||= 'default'; $self->{groups}->{ $opt->{group} }->{$long} = 1; @@ -830,7 +873,7 @@ sub _set_option { if ( $opt->{is_cumulative} ) { $opt->{value}++; } - elsif ( !($opt->{optional_value} && !$val) ) { + else { $opt->{value} = $val; } $opt->{got} = 1; @@ -1210,7 +1253,7 @@ sub print_usage { $desc .= ". Optional suffix s=seconds, m=minutes, h=hours, " . "d=days; if no suffix, $s is used."; } - $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol})(?:\s+|$)/g); + $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol}(?!\W))(?:\s+|(?<=\W)|$)/g); $desc =~ s/ +$//mg; if ( $short ) { $usage .= sprintf(" --%-${maxs}s -%s %s\n", $long, $short, $desc); @@ -1371,12 +1414,11 @@ sub _parse_size { sub _parse_attribs { my ( $self, $option, $attribs ) = @_; my $types = $self->{types}; - my $eq = $attribs->{'value_is_optional'} ? ':' : '='; return $option . ($attribs->{'short form'} ? '|' . $attribs->{'short form'} : '' ) . ($attribs->{'negatable'} ? '!' : '' ) . ($attribs->{'cumulative'} ? '+' : '' ) - . ($attribs->{'type'} ? $eq . $types->{$attribs->{type}} : '' ); + . ($attribs->{'type'} ? '=' . $types->{$attribs->{type}} : '' ); } sub _parse_synopsis { @@ -1414,6 +1456,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-upgrade b/bin/pt-upgrade index b3f0008a..ac08c06c 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -981,7 +981,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -996,13 +996,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -1077,6 +1072,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1671,6 +1715,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -2654,6 +2699,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-variable-advisor b/bin/pt-variable-advisor index 995cc207..e9ec7743 100755 --- a/bin/pt-variable-advisor +++ b/bin/pt-variable-advisor @@ -69,6 +69,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -1052,6 +1053,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1987,7 +2027,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2002,13 +2042,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2083,6 +2118,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/bin/pt-visual-explain b/bin/pt-visual-explain index 7979782a..8f365cf9 100755 --- a/bin/pt-visual-explain +++ b/bin/pt-visual-explain @@ -711,6 +711,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; +use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; @@ -732,7 +733,6 @@ sub new { 'default' => 1, 'cumulative' => 1, 'negatable' => 1, - 'value_is_optional' => 1, ); my $self = { @@ -974,10 +974,9 @@ sub _parse_specs { $opt->{short} = undef; } - $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; - $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; - $opt->{optional_value} = $opt->{spec} =~ m/:/ ? 1 : 0; - $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; + $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; + $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; + $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; $opt->{group} ||= 'default'; $self->{groups}->{ $opt->{group} }->{$long} = 1; @@ -1113,7 +1112,7 @@ sub _set_option { if ( $opt->{is_cumulative} ) { $opt->{value}++; } - elsif ( !($opt->{optional_value} && !$val) ) { + else { $opt->{value} = $val; } $opt->{got} = 1; @@ -1493,7 +1492,7 @@ sub print_usage { $desc .= ". Optional suffix s=seconds, m=minutes, h=hours, " . "d=days; if no suffix, $s is used."; } - $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol})(?:\s+|$)/g); + $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol}(?!\W))(?:\s+|(?<=\W)|$)/g); $desc =~ s/ +$//mg; if ( $short ) { $usage .= sprintf(" --%-${maxs}s -%s %s\n", $long, $short, $desc); @@ -1654,12 +1653,11 @@ sub _parse_size { sub _parse_attribs { my ( $self, $option, $attribs ) = @_; my $types = $self->{types}; - my $eq = $attribs->{'value_is_optional'} ? ':' : '='; return $option . ($attribs->{'short form'} ? '|' . $attribs->{'short form'} : '' ) . ($attribs->{'negatable'} ? '!' : '' ) . ($attribs->{'cumulative'} ? '+' : '' ) - . ($attribs->{'type'} ? $eq . $types->{$attribs->{type}} : '' ); + . ($attribs->{'type'} ? '=' . $types->{$attribs->{type}} : '' ); } sub _parse_synopsis { @@ -1697,6 +1695,45 @@ sub _parse_synopsis { ); }; +sub set_vars { + my ($self, $file) = @_; + $file ||= $self->{file} || __FILE__; + + my %user_vars; + my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; + 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; + $user_vars{$var} = { + val => $val, + default => 0, + }; + } + } + + my %default_vars; + my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); + if ( $default_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; + $var => { + val => $val, + default => 1, + }; + } split("\n", $default_vars); + } + + my %vars = ( + %default_vars, # first the tool's defaults + %user_vars, # then the user's which overwrite the defaults + ); + PTDEBUG && _d('--set-vars:', Dumper(\%vars)); + return \%vars; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } @@ -1988,7 +2025,7 @@ sub get_dbh { if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; - PTDEBUG && _d($dbh, ':', $sql); + PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; @@ -2003,13 +2040,8 @@ sub get_dbh { } } - if ( my $var = $self->prop('set-vars') ) { - $sql = "SET $var"; - PTDEBUG && _d($dbh, ':', $sql); - eval { $dbh->do($sql) }; - if ( $EVAL_ERROR ) { - die "Error setting $var: $EVAL_ERROR"; - } + if ( my $vars = $self->prop('set-vars') ) { + $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' @@ -2084,6 +2116,55 @@ sub copy { return \%new_dsn; } +sub set_vars { + my ($self, $dbh, $vars) = @_; + + foreach my $var ( sort keys %$vars ) { + my $val = $vars->{$var}->{val}; + + (my $quoted_var = $var) =~ s/_/\\_/; + my ($var_exists, $current_val); + eval { + ($var_exists, $current_val) = $dbh->selectrow_array( + "SHOW VARIABLES LIKE '$quoted_var'"); + }; + my $e = $EVAL_ERROR; + if ( $e ) { + PTDEBUG && _d($e); + } + + if ( $vars->{$var}->{default} && !$var_exists ) { + PTDEBUG && _d('Not setting default var', $var, + 'because it does not exist'); + next; + } + + if ( $current_val && $current_val eq $val ) { + PTDEBUG && _d('Not setting var', $var, 'because its value', + 'is already', $val); + next; + } + + my $sql = "SET SESSION $var=$val"; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( my $set_error = $EVAL_ERROR ) { + chomp($set_error); + $set_error =~ s/ at \S+ line \d+//; + my $msg = "Error setting $var: $set_error"; + if ( $current_val ) { + $msg .= " The current value for $var is $current_val. " + . "If the variable is read only (not dynamic), specify " + . "--set-vars $var=$current_val to avoid this warning, " + . "else manually set the variable and restart MySQL."; + } + warn $msg . "\n\n"; + } + } + + return; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }