Merge pt-show-grant-col-privs-bug-866075

This commit is contained in:
Daniel Nichter
2012-11-01 13:58:20 -06:00
7 changed files with 139 additions and 11 deletions

View File

@@ -1636,10 +1636,16 @@ sub _d {
# ###########################################################################
package pt_show_grants;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
use Data::Dumper;
$Data::Dumper::Quotekeys = 0;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
sub main {
@ARGV = @_; # set global ARGV for this package
@@ -1757,13 +1763,17 @@ sub main {
PTDEBUG && _d($EVAL_ERROR);
$exit_status = 1;
}
PTDEBUG && _d('Grants:', Dumper(\@grants));
next unless @grants;
if ( $o->get('separate') ) { # List each grant separately.
if ( $o->get('separate') ) {
# List each grant separately.
@grants = map {
my ( $grants, $on_what ) = $_ =~ m/GRANT (.*?) ON (.*)$/;
map { "GRANT $_ ON $on_what" } split(', ', $grants);
map { "GRANT $_ ON $on_what" } split_grants($grants);
} @grants;
PTDEBUG && _d('Grants separated:', Dumper(\@grants));
my $count;
# If the row with IDENTIFIED BY has multiple grants, this will
# create many such rows; strip it from all but the first.
@@ -1775,12 +1785,15 @@ sub main {
}
$_;
} @grants;
PTDEBUG && _d('Grants separated:', Dumper(\@grants));
}
else { # Sort the actual grants lexically within each row for consistency.
else {
# Sort the actual grants lexically within each row for consistency.
@grants = map {
$_ =~ s/GRANT (.*?) ON (`|\*)/"GRANT " . join(', ', sort(split(', ', $1))) . " ON $2"/e;
$_ =~ s/GRANT (.*?) ON (`|\*)/"GRANT " . join(', ', sort(split_grants($1))) . " ON $2"/e;
$_;
} @grants;
PTDEBUG && _d('Grants grouped:', Dumper(\@grants));
}
# Sort the grant rows for consistency too, but the one with the password
@@ -1788,6 +1801,7 @@ sub main {
@grants = sort {
$b =~ m/IDENTIFIED BY/ <=> $a =~ m/IDENTIFIED BY/ || $a cmp $b
} @grants;
PTDEBUG && _d('Grants sorted:', Dumper(\@grants));
# Print REVOKE statements.
if ( $o->get('revoke') ) {
@@ -1802,7 +1816,7 @@ sub main {
my @result;
if ( $o->get('separate') ) {
@result = map { "REVOKE $_ ON $on_what FROM $user" }
split(', ', $grants);
split_grants($grants);
}
else {
@result = "REVOKE $grants ON $on_what FROM $user";
@@ -1867,6 +1881,31 @@ sub parse_user {
return ( $user, $host );
}
sub split_grants {
my ($grants) = @_;
return unless $grants;
my @grants;
if ( $grants =~ m/(?:INSERT|SELECT|UPDATE) \(/ ) {
PTDEBUG && _d('Splitting grants on keywords:', $grants);
# TODO: the following .+? might break (e.g. on `annoying)column`).
# Remember to update this whenever we switch to using
# a common SQL regex module
@grants = $grants =~ m/
(
(?:INSERT|SELECT|UPDATE)\s\(.+?\) # a column grants
| [A-Z\s]+
)
(?:,\s)? # Separted from the next grant, if any, by a comma
/xg;
}
else {
PTDEBUG && _d('Splitting grants on comma:', $grants);
@grants = split(', ', $grants);
}
PTDEBUG && _d('Grants split:', Dumper(\@grants));
return @grants;
}
sub _d {
my ($package, undef, $line) = caller 0;
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
@@ -1894,7 +1933,7 @@ pt-show-grants - Canonicalize and print MySQL grants so you can effectively repl
=head1 SYNOPSIS
Usage: pt-show-grants [OPTION...] [DSN]
Usage: pt-show-grants [OPTIONS] [DSN]
pt-show-grants shows grants (user privileges) from a MySQL server.

View File

@@ -22,9 +22,6 @@ my $dbh = $sb->get_dbh_for('master');
if ( !$dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
else {
plan tests => 11;
}
$sb->wipe_clean($dbh);
@@ -94,8 +91,59 @@ like(
'No output when all users skipped'
);
# #############################################################################
# pt-show-grant doesn't support column-level grants
# https://bugs.launchpad.net/percona-toolkit/+bug/866075
# #############################################################################
$sb->load_file('master', 't/pt-show-grants/samples/column-grants.sql');
diag(`/tmp/12345/use -u root -e "GRANT SELECT(DateCreated, PckPrice, PaymentStat, SANumber) ON test.t TO 'sally'\@'%'"`);
diag(`/tmp/12345/use -u root -e "GRANT SELECT(city_id), INSERT(city) ON sakila.city TO 'sally'\@'%'"`);
ok(
no_diff(
sub { pt_show_grants::main('-F', $cnf, qw(--only sally --no-header)) },
"t/pt-show-grants/samples/column-grants.txt",
stderr => 1,
),
"Column-level grants (bug 866075)"
);
ok(
no_diff(
sub { pt_show_grants::main('-F', $cnf, qw(--only sally --no-header),
qw(--separate)) },
"t/pt-show-grants/samples/column-grants-separate.txt",
stderr => 1,
),
"Column-level grants --separate (bug 866075)"
);
ok(
no_diff(
sub { pt_show_grants::main('-F', $cnf, qw(--only sally --no-header),
qw(--separate --revoke)) },
"t/pt-show-grants/samples/column-grants-separate-revoke.txt",
stderr => 1,
),
"Column-level grants --separate --revoke (bug 866075)"
);
diag(`/tmp/12345/use -u root -e "GRANT SELECT ON sakila.city TO 'sally'\@'%'"`);
ok(
no_diff(
sub { pt_show_grants::main('-F', $cnf, qw(--only sally --no-header)) },
"t/pt-show-grants/samples/column-grants-combined.txt",
stderr => 1,
),
"Column-level grants combined with table-level grants on the same table (bug 866075)"
);
diag(`/tmp/12345/use -u root -e "DROP USER 'sally'\@'%'"`);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;
done_testing;

View File

@@ -0,0 +1,4 @@
-- Grants for 'sally'@'%'
GRANT INSERT (city), SELECT, SELECT (city_id) ON `sakila`.`city` TO 'sally'@'%';
GRANT SELECT (SANumber, DateCreated, PaymentStat, PckPrice) ON `test`.`t` TO 'sally'@'%';
GRANT USAGE ON *.* TO 'sally'@'%';

View File

@@ -0,0 +1,10 @@
-- Revoke statements for 'sally'@'%'
REVOKE INSERT (city) ON `sakila`.`city` FROM 'sally'@'%';
REVOKE SELECT (SANumber, DateCreated, PaymentStat, PckPrice) ON `test`.`t` FROM 'sally'@'%';
REVOKE SELECT (city_id) ON `sakila`.`city` FROM 'sally'@'%';
REVOKE USAGE ON *.* FROM 'sally'@'%';
-- Grants for 'sally'@'%'
GRANT INSERT (city) ON `sakila`.`city` TO 'sally'@'%';
GRANT SELECT (SANumber, DateCreated, PaymentStat, PckPrice) ON `test`.`t` TO 'sally'@'%';
GRANT SELECT (city_id) ON `sakila`.`city` TO 'sally'@'%';
GRANT USAGE ON *.* TO 'sally'@'%';

View File

@@ -0,0 +1,5 @@
-- Grants for 'sally'@'%'
GRANT INSERT (city) ON `sakila`.`city` TO 'sally'@'%';
GRANT SELECT (SANumber, DateCreated, PaymentStat, PckPrice) ON `test`.`t` TO 'sally'@'%';
GRANT SELECT (city_id) ON `sakila`.`city` TO 'sally'@'%';
GRANT USAGE ON *.* TO 'sally'@'%';

View File

@@ -0,0 +1,18 @@
drop database if exists test;
create database test;
use test;
CREATE TABLE t (
`SOrNum` mediumint(9) unsigned NOT NULL auto_increment,
`SPNum` mediumint(9) unsigned NOT NULL,
`DateCreated` timestamp NOT NULL default CURRENT_TIMESTAMP,
`DateRelease` timestamp NOT NULL default '0000-00-00 00:00:00',
`ActualReleasedDate` timestamp NULL default NULL,
`PckPrice` decimal(10,2) NOT NULL default '0.00',
`Status` varchar(20) NOT NULL,
`PaymentStat` varchar(20) NOT NULL default 'Unpaid',
`CusCode` int(9) unsigned NOT NULL,
`SANumber` mediumint(9) unsigned NOT NULL default '0',
`SpecialInstruction` varchar(500) default NULL,
PRIMARY KEY (`SOrNum`)
) ENGINE=InnoDB;

View File

@@ -0,0 +1,4 @@
-- Grants for 'sally'@'%'
GRANT INSERT (city), SELECT (city_id) ON `sakila`.`city` TO 'sally'@'%';
GRANT SELECT (SANumber, DateCreated, PaymentStat, PckPrice) ON `test`.`t` TO 'sally'@'%';
GRANT USAGE ON *.* TO 'sally'@'%';