mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-10 13:11:32 +00:00
Merge pt-show-grant-col-privs-bug-866075
This commit is contained in:
@@ -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.
|
||||
|
||||
|
@@ -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;
|
||||
|
4
t/pt-show-grants/samples/column-grants-combined.txt
Normal file
4
t/pt-show-grants/samples/column-grants-combined.txt
Normal 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'@'%';
|
10
t/pt-show-grants/samples/column-grants-separate-revoke.txt
Normal file
10
t/pt-show-grants/samples/column-grants-separate-revoke.txt
Normal 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'@'%';
|
5
t/pt-show-grants/samples/column-grants-separate.txt
Normal file
5
t/pt-show-grants/samples/column-grants-separate.txt
Normal 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'@'%';
|
18
t/pt-show-grants/samples/column-grants.sql
Normal file
18
t/pt-show-grants/samples/column-grants.sql
Normal 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;
|
4
t/pt-show-grants/samples/column-grants.txt
Normal file
4
t/pt-show-grants/samples/column-grants.txt
Normal 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'@'%';
|
Reference in New Issue
Block a user