From 8ad0bc0827faeae5d2ef6eeffa6695a20b9de184 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Mon, 18 Sep 2023 15:16:56 +0200 Subject: [PATCH 1/9] I had to correct few things in the script to have it working correctly: 1) OR instead and in the if line 2042 2) evaluate array create_user if it has some value 3) filter out the user creation in Mariadb inside the Grants --- bin/pt-show-grants | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) mode change 100755 => 100644 bin/pt-show-grants diff --git a/bin/pt-show-grants b/bin/pt-show-grants old mode 100755 new mode 100644 index 4a0655cef..8564e3b10 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2039,7 +2039,7 @@ sub main { # If MySQL 5.7.6+ then we need to use SHOW CREATE USER my @create_user; - if (( VersionCompare::cmp($version, '5.7.6') >= 0 ) && + if (( VersionCompare::cmp($version, '5.7.6') >= 0 ) || ( VersionCompare::cmp($version, '10.0.0') <= 0 )) { eval { @create_user = @{ $dbh->selectcol_arrayref("SHOW CREATE USER $user_host") }; @@ -2048,16 +2048,18 @@ sub main { PTDEBUG && _d($EVAL_ERROR); $exit_status = 1; } - PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); - # make this replication safe converting the CREATE USER into - # CREATE USER IF NOT EXISTS and then doing an ALTER USER - my $create = $create_user[0]; - my $alter = $create; - $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; - $create =~ s{ IDENTIFIED .*}{}; - $alter =~ s{CREATE USER}{ALTER USER}; - @create_user = ( $create, $alter ); - PTDEBUG && _d('AdjustedCreateUser:', Dumper(\@create_user)); + if ($#create_user > 0){ + PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); + # make this replication safe converting the CREATE USER into + # CREATE USER IF NOT EXISTS and then doing an ALTER USER + my $create = $create_user[0]; + my $alter = $create; + $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; + $create =~ s{ IDENTIFIED .*}{}; + $alter =~ s{CREATE USER}{ALTER USER}; + @create_user = ( $create, $alter ); + PTDEBUG && _d('AdjustedCreateUser:', Dumper(\@create_user)); + } } my @grants; eval { @@ -2067,6 +2069,13 @@ sub main { PTDEBUG && _d($EVAL_ERROR); $exit_status = 1; } + #IF is MariaDB we need to remove the password from the user + if ( VersionCompare::cmp($version, 'MariaDB') >= 0 ){ + for my $i (0 .. $#grants){ + $grants[$i] =~ s{IDENTIFIED.*}{}; + } + PTDEBUG && _d('Grants:', Dumper(\@grants)); + } PTDEBUG && _d('Grants:', Dumper(\@grants)); next unless @grants; From 275ceb0051f022bfbeec7a9e55b70ae333e71916 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Thu, 21 Sep 2023 16:35:57 +0200 Subject: [PATCH 2/9] Fixing other small things and MariaDB specific, - Use of VIA - Use of USING - Incompatible syntax with MySQL - ADD IF NOT EXISTS - convert the script to us AS to maintain the hash as they are Add a parameter --convert-MariaDB as parameter (default false) --- bin/pt-show-grants | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 8564e3b10..70dea38c9 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2048,16 +2048,25 @@ sub main { PTDEBUG && _d($EVAL_ERROR); $exit_status = 1; } - if ($#create_user > 0){ + if ($#create_user >= 0){ PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); # make this replication safe converting the CREATE USER into # CREATE USER IF NOT EXISTS and then doing an ALTER USER my $create = $create_user[0]; - my $alter = $create; + my $alter = $create_user[0]; $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; - $create =~ s{ IDENTIFIED .*}{}; + $create =~ s{ IDENTIFIED VIA }{ IDENTIFIED AS }; + $create =~ s{ BY }{ AS }; + $create =~ s{ AS.*PASSWORD }{ AS }; $alter =~ s{CREATE USER}{ALTER USER}; - @create_user = ( $create, $alter ); + # Alter user should not be pass in the latest MySQL version + #we need to cleanup other MariaDB diversions + if ( VersionCompare::cmp($version, 'MariaDB') >= 0 && + $o->get('convert-MariaDB')){ + $create =~ s/IDENTIFIED.*USING.*unix_socket.*/IDENTIFIED WITH auth_socket/; + $create =~ s/IDENTIFIED AS/IDENTIFIED WITH mysql_native_password AS/; + } + @create_user = ( $create); PTDEBUG && _d('AdjustedCreateUser:', Dumper(\@create_user)); } } @@ -2442,6 +2451,10 @@ type: array Only show grants for this comma-separated list of users. +=item --convert-MariaDB + +When set it convert some of the proprietary MariaDB syntax into valid MySQL form + =item --password short form: -p; type: string From 3be972e51802031fcc19baf94dca6a55629b06ec Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Thu, 21 Sep 2023 17:03:49 +0200 Subject: [PATCH 3/9] Fixed one issue (I introduced filtering the PASSWORD keyword) correct an IF condition removed a delete action on mysql.user. Always use DROP not delete --- bin/pt-show-grants | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 70dea38c9..5a2e798f8 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2057,12 +2057,11 @@ sub main { $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; $create =~ s{ IDENTIFIED VIA }{ IDENTIFIED AS }; $create =~ s{ BY }{ AS }; - $create =~ s{ AS.*PASSWORD }{ AS }; $alter =~ s{CREATE USER}{ALTER USER}; # Alter user should not be pass in the latest MySQL version #we need to cleanup other MariaDB diversions - if ( VersionCompare::cmp($version, 'MariaDB') >= 0 && - $o->get('convert-MariaDB')){ + if ( ($version =~ m/MariaDB/) && $o->get('convert-MariaDB')){ + $create =~ s{ AS.*PASSWORD }{ AS }; $create =~ s/IDENTIFIED.*USING.*unix_socket.*/IDENTIFIED WITH auth_socket/; $create =~ s/IDENTIFIED AS/IDENTIFIED WITH mysql_native_password AS/; } @@ -2079,7 +2078,7 @@ sub main { $exit_status = 1; } #IF is MariaDB we need to remove the password from the user - if ( VersionCompare::cmp($version, 'MariaDB') >= 0 ){ + if (($version =~ m/MariaDB/)){ for my $i (0 .. $#grants){ $grants[$i] =~ s{IDENTIFIED.*}{}; } @@ -2165,7 +2164,7 @@ sub main { if ( $o->get('drop') && !defined($u->{IsRole}) ) { print join("\n", "DROP USER $user_host;", - "DELETE FROM `mysql`.`user` WHERE `User`='$u->{User}' AND `Host`='$u->{Host}';", + #"DELETE FROM `mysql`.`user` WHERE `User`='$u->{User}' AND `Host`='$u->{Host}';", ), "\n"; } From b9be38d3a09ef76c8058f12dff9a79bfb0539f29 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Fri, 22 Sep 2023 17:18:23 +0200 Subject: [PATCH 4/9] Significant refactor of the create in case of MySQL 8 and caching_sha2_password plugin. The problem is that when caching_sha2_password is used the character utilised in the string may be invalid for MySQL itself to process during creation time. Given that the password must be converted to HEX and then pushed as binary using the AS format --- bin/pt-show-grants | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 5a2e798f8..96574ce74 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2050,6 +2050,14 @@ sub main { } if ($#create_user >= 0){ PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); + #given caching_sha2_password issue we need to select the password in binary format and replace the one coming from the create + my $query = "SELECT authentication_string sha2 from mysql.user where user='$u->{User}' and host='$u->{Host}'"; + PTDEBUG && _d('get password:', Dumper($query)); + my ( $pw_sha2) = $dbh->selectrow_array($query); + my $pw_bin = $pw_sha2; + $pw_bin =~ s/(.)/sprintf '%02X', ord $1/seg; + $pw_bin = "0x".$pw_bin; + # make this replication safe converting the CREATE USER into # CREATE USER IF NOT EXISTS and then doing an ALTER USER my $create = $create_user[0]; @@ -2057,6 +2065,10 @@ sub main { $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; $create =~ s{ IDENTIFIED VIA }{ IDENTIFIED AS }; $create =~ s{ BY }{ AS }; + if ( $create =~ m/caching_sha2_password/ ) { + print "-- Converting $user_host caching_sha2_password to binary for correct export/import\n"; + $create =~ s/\sAS\s.*'\s|$/ AS $pw_bin /g; + } $alter =~ s{CREATE USER}{ALTER USER}; # Alter user should not be pass in the latest MySQL version #we need to cleanup other MariaDB diversions From b9675c56b6606eba5e0c7c28fb9acd6e461cf3d7 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Fri, 22 Sep 2023 17:32:27 +0200 Subject: [PATCH 5/9] small bug in regex --- bin/pt-show-grants | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 96574ce74..8ffd2b13e 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2067,7 +2067,7 @@ sub main { $create =~ s{ BY }{ AS }; if ( $create =~ m/caching_sha2_password/ ) { print "-- Converting $user_host caching_sha2_password to binary for correct export/import\n"; - $create =~ s/\sAS\s.*'\s|$/ AS $pw_bin /g; + $create =~ s/\sAS\s.*'\s/ AS $pw_bin /g; } $alter =~ s{CREATE USER}{ALTER USER}; # Alter user should not be pass in the latest MySQL version From 6f767a9d1d0aad9198df38fc3858670d6b3b1354 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Fri, 22 Sep 2023 17:40:00 +0200 Subject: [PATCH 6/9] Adding replication safe condition for drop --- bin/pt-show-grants | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 8ffd2b13e..d7207ba6b 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2175,7 +2175,7 @@ sub main { if ( $o->get('drop') && !defined($u->{IsRole}) ) { print join("\n", - "DROP USER $user_host;", + "DROP USER IF EXISTS $user_host;", #"DELETE FROM `mysql`.`user` WHERE `User`='$u->{User}' AND `Host`='$u->{Host}';", ), "\n"; } From e3a3d973e214a7dc990c85f9a56fa12a714c9aa7 Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Mon, 25 Sep 2023 15:13:56 +0200 Subject: [PATCH 7/9] Adding the option to use in session print_identified_with_as_hex as an alternative to the conversion Param --print_identified_with_as_hex --- bin/pt-show-grants | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index d7207ba6b..2ca2307fd 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2042,6 +2042,9 @@ sub main { if (( VersionCompare::cmp($version, '5.7.6') >= 0 ) || ( VersionCompare::cmp($version, '10.0.0') <= 0 )) { eval { + if (( VersionCompare::cmp($version, '8.0.17') >= 0 ) && ($o->get('print_identified_with_as_hex'))){ + $dbh->do("SET print_identified_with_as_hex=1") or die(); + } @create_user = @{ $dbh->selectcol_arrayref("SHOW CREATE USER $user_host") }; }; if ( $EVAL_ERROR ) { @@ -2051,6 +2054,7 @@ sub main { if ($#create_user >= 0){ PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); #given caching_sha2_password issue we need to select the password in binary format and replace the one coming from the create + #my $query = "SELECT authentication_string as sha2, convert(authentication_string using Binary) as bin from mysql.user where user='$u->{User}' and host='$u->{Host}'"; my $query = "SELECT authentication_string sha2 from mysql.user where user='$u->{User}' and host='$u->{Host}'"; PTDEBUG && _d('get password:', Dumper($query)); my ( $pw_sha2) = $dbh->selectrow_array($query); @@ -2065,7 +2069,7 @@ sub main { $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; $create =~ s{ IDENTIFIED VIA }{ IDENTIFIED AS }; $create =~ s{ BY }{ AS }; - if ( $create =~ m/caching_sha2_password/ ) { + if (( $create =~ m/caching_sha2_password/ ) && !($o->get('print_identified_with_as_hex'))) { print "-- Converting $user_host caching_sha2_password to binary for correct export/import\n"; $create =~ s/\sAS\s.*'\s/ AS $pw_bin /g; } @@ -2466,6 +2470,12 @@ Only show grants for this comma-separated list of users. When set it convert some of the proprietary MariaDB syntax into valid MySQL form +=item --print_identified_with_as_hex + +Enabling print_identified_with_as_hex causes SHOW CREATE USER to display such hash values as hexadecimal strings rather than as regular string literals. +Hash values that do not contain unprintable characters still display as regular string literals, even with this variable enabled. + + =item --password short form: -p; type: string From 1dc1c999f1cd302d086e7b4f0c799b65e40027cc Mon Sep 17 00:00:00 2001 From: Marco Tusa Date: Mon, 25 Sep 2023 15:44:43 +0200 Subject: [PATCH 8/9] Adding a small check if we have MariaDB in order to prevent usage of print_identified_with_as_hex --- bin/pt-show-grants | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 2ca2307fd..4e4d64509 100644 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2042,8 +2042,9 @@ sub main { if (( VersionCompare::cmp($version, '5.7.6') >= 0 ) || ( VersionCompare::cmp($version, '10.0.0') <= 0 )) { eval { - if (( VersionCompare::cmp($version, '8.0.17') >= 0 ) && ($o->get('print_identified_with_as_hex'))){ + if (!($version =~ m/MariaDB/) && ( VersionCompare::cmp($version, '8.0.17') >= 0 ) && ($o->get('print_identified_with_as_hex'))){ $dbh->do("SET print_identified_with_as_hex=1") or die(); + print "-- Setting print_identified_with_as_hex as ACTIVE at session level for correct export/import\n"; } @create_user = @{ $dbh->selectcol_arrayref("SHOW CREATE USER $user_host") }; }; From f3f4943d520d4cf89a19d7afe5eedc376913df20 Mon Sep 17 00:00:00 2001 From: Sveta Smirnova Date: Thu, 16 May 2024 23:21:59 +0300 Subject: [PATCH 9/9] PT-2247 - pt-show-grants does not CREATE USER - Removed option print_identified_with_as_hex, because it was already implemented in the PT-2190 fix - Simplified patch - Kept CREATE USER/ALTER USER sequence and extra DELETE from mysql.user table - Added test case --- bin/pt-show-grants | 79 ++++++++++++++------------------------ t/pt-show-grants/pt-2247.t | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 50 deletions(-) mode change 100644 => 100755 bin/pt-show-grants create mode 100644 t/pt-show-grants/pt-2247.t diff --git a/bin/pt-show-grants b/bin/pt-show-grants old mode 100644 new mode 100755 index ab9414773..b5b76752c --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2062,51 +2062,34 @@ sub main { # If MySQL 5.7.6+ then we need to use SHOW CREATE USER my @create_user; - if (( VersionCompare::cmp($version, '5.7.6') >= 0 ) || - ( VersionCompare::cmp($version, '10.0.0') <= 0 )) { + if ( ( VersionCompare::cmp($version, '5.7.6') >= 0 ) ) { eval { - if (!($version =~ m/MariaDB/) && ( VersionCompare::cmp($version, '8.0.17') >= 0 ) && ($o->get('print_identified_with_as_hex'))){ - $dbh->do("SET print_identified_with_as_hex=1") or die(); - print "-- Setting print_identified_with_as_hex as ACTIVE at session level for correct export/import\n"; - } @create_user = @{ $dbh->selectcol_arrayref("SHOW CREATE USER $user_host") }; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); $exit_status = 1; } - if ($#create_user >= 0){ - PTDEBUG && _d('CreateUser:', Dumper(\@create_user)); - #given caching_sha2_password issue we need to select the password in binary format and replace the one coming from the create - #my $query = "SELECT authentication_string as sha2, convert(authentication_string using Binary) as bin from mysql.user where user='$u->{User}' and host='$u->{Host}'"; - my $query = "SELECT authentication_string sha2 from mysql.user where user='$u->{User}' and host='$u->{Host}'"; - PTDEBUG && _d('get password:', Dumper($query)); - my ( $pw_sha2) = $dbh->selectrow_array($query); - my $pw_bin = $pw_sha2; - $pw_bin =~ s/(.)/sprintf '%02X', ord $1/seg; - $pw_bin = "0x".$pw_bin; - - # make this replication safe converting the CREATE USER into + if ( $#create_user >= 0 ) { + PTDEBUG && _d('CREATE USER:', Dumper(\@create_user)); + + # Make this replication safe converting the CREATE USER into # CREATE USER IF NOT EXISTS and then doing an ALTER USER - my $create = $create_user[0]; - my $alter = $create_user[0]; - $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; - $create =~ s{ IDENTIFIED VIA }{ IDENTIFIED AS }; - $create =~ s{ BY }{ AS }; - if (( $create =~ m/caching_sha2_password/ ) && !($o->get('print_identified_with_as_hex'))) { - print "-- Converting $user_host caching_sha2_password to binary for correct export/import\n"; - $create =~ s/\sAS\s.*'\s/ AS $pw_bin /g; - } - $alter =~ s{CREATE USER}{ALTER USER}; - # Alter user should not be pass in the latest MySQL version - #we need to cleanup other MariaDB diversions - if ( ($version =~ m/MariaDB/) && $o->get('convert-MariaDB')){ - $create =~ s{ AS.*PASSWORD }{ AS }; - $create =~ s/IDENTIFIED.*USING.*unix_socket.*/IDENTIFIED WITH auth_socket/; - $create =~ s/IDENTIFIED AS/IDENTIFIED WITH mysql_native_password AS/; - } - @create_user = ( $create); - PTDEBUG && _d('AdjustedCreateUser:', Dumper(\@create_user)); + my $create = $create_user[0]; + my $alter = $create; + $create =~ s{CREATE USER}{CREATE USER IF NOT EXISTS}; + $create =~ s{ IDENTIFIED .*}{}; + $alter =~ s{CREATE USER}{ALTER USER}; + + # We need to cleanup MariaDB diversions + if ( ($version =~ m/MariaDB/) && $o->get('convert-MariaDB')){ + $create =~ s{ AS.*PASSWORD }{ AS }; + $create =~ s/IDENTIFIED.*USING.*unix_socket.*/IDENTIFIED WITH auth_socket/; + $create =~ s/IDENTIFIED AS/IDENTIFIED WITH mysql_native_password AS/; + } + + @create_user = ( $create, $alter ); + PTDEBUG && _d('Adjusted CREATE USER:', Dumper(\@create_user)); } } my @grants; @@ -2117,13 +2100,15 @@ sub main { PTDEBUG && _d($EVAL_ERROR); $exit_status = 1; } - #IF is MariaDB we need to remove the password from the user - if (($version =~ m/MariaDB/)){ - for my $i (0 .. $#grants){ + + # We need to remove password form the user grants when dump MariaDB + if ( $version =~ m/MariaDB/ ){ + PTDEBUG && _d('Original Grants - MariaDB:', Dumper(\@grants)); + for my $i (0 .. $#grants){ $grants[$i] =~ s{IDENTIFIED.*}{}; - } - PTDEBUG && _d('Grants:', Dumper(\@grants)); + } } + PTDEBUG && _d('Grants:', Dumper(\@grants)); next unless @grants; @@ -2204,7 +2189,7 @@ sub main { if ( $o->get('drop') && !defined($u->{IsRole}) ) { print join("\n", "DROP USER IF EXISTS $user_host;", - #"DELETE FROM `mysql`.`user` WHERE `User`='$u->{User}' AND `Host`='$u->{Host}';", + "DELETE FROM `mysql`.`user` WHERE `User`='$u->{User}' AND `Host`='$u->{Host}';", ), "\n"; } @@ -2492,13 +2477,7 @@ Only show grants for this comma-separated list of users. =item --convert-MariaDB -When set it convert some of the proprietary MariaDB syntax into valid MySQL form - -=item --print_identified_with_as_hex - -Enabling print_identified_with_as_hex causes SHOW CREATE USER to display such hash values as hexadecimal strings rather than as regular string literals. -Hash values that do not contain unprintable characters still display as regular string literals, even with this variable enabled. - +Convert proprietary MariaDB syntax into valid MySQL form =item --password diff --git a/t/pt-show-grants/pt-2247.t b/t/pt-show-grants/pt-2247.t new file mode 100644 index 000000000..7c93a0390 --- /dev/null +++ b/t/pt-show-grants/pt-2247.t @@ -0,0 +1,77 @@ +#!/usr/bin/env perl + +BEGIN { + die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" + unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; + unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; +}; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Test::More; + +use PerconaTest; +use Sandbox; +use SqlModes; +use VersionParser; +require "$trunk/bin/pt-show-grants"; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $dbh = $sb->get_dbh_for('master'); + +if ( !$dbh ) { + plan skip_all => 'Cannot connect to sandbox master'; +} + +if ( VersionParser->new($dbh)->flavor !~ m/maria/i ) { + plan skip_all => "This test requires MariaDB"; +} + +$sb->wipe_clean($dbh); + +my $output; +my $cnf = '/tmp/12345/my.sandbox.cnf'; + +diag(`/tmp/12345/use -u root -e "CREATE USER 'sally'\@'%' IDENTIFIED BY 'A005?>6LZe1'"`); + +ok( + `/tmp/12345/use -s -u sally -p'A005?>6LZe1' -e "SELECT 1" 2>/dev/null`, + 'User sally can log in before tests' +); + +$output = output( + sub { pt_show_grants::main('-F', $cnf, qw(--only sally)); } +); + +like( + $output, + qr/CREATE USER IF NOT EXISTS `sally`@`%`;/, + 'CREATE USER printed' +) or diag($output); + +like( + $output, + qr/ALTER USER `sally`@`%` IDENTIFIED BY PASSWORD '\*A5C09B5E9542E3C716E3E0A711336D9ABB48D89F';/, + 'ALTER USER printed' +) or diag($output); + +diag(`/tmp/12345/use -u root -e "DROP USER 'sally'\@'%'"`); +open(my $pipe, '|-', '/tmp/12345/use -u root'); +print $pipe $output; +close($pipe); + +ok( + `/tmp/12345/use -s -u sally -p'A005?>6LZe1' -e "SELECT 1" 2>/dev/null`, + 'User sally can log in' +) or diag($output); + +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"); +done_testing;