Fixes for DSN parser to use UTF8

This commit is contained in:
Carlos Salguero
2018-01-28 14:46:51 -03:00
parent f3132d3cee
commit d38a584271
7 changed files with 4132 additions and 23 deletions

View File

@@ -379,6 +379,28 @@ sub get_dbh {
. ": $EVAL_ERROR"; . ": $EVAL_ERROR";
} }
} }
my ($mysql_version) = eval { $dbh->selectrow_array('SELECT VERSION()') };
if ($EVAL_ERROR) {
die "Cannot get MySQL version: $EVAL_ERROR";
}
my (undef, $character_set_server) = eval { $dbh->selectrow_array("SHOW VARIABLES LIKE 'character_set_server'") };
if ($EVAL_ERROR) {
die "Cannot get MySQL var character_set_server: $EVAL_ERROR";
}
if ($mysql_version =~ m/^(\d+)\.(\d)\.(\d+).*/) {
if ($1 >= 8 && $character_set_server =~ m/^utf8/) {
$dbh->{mysql_enable_utf8} = 1;
my $msg = "MySQL version $mysql_version >= 8 and character_set_server = $character_set_server\n".
"Setting: SET NAMES $character_set_server";
PTDEBUG && _d($msg);
eval { $dbh->do("SET NAMES 'utf8mb4'") };
if ($EVAL_ERROR) {
die "Cannot SET NAMES $character_set_server: $EVAL_ERROR";
}
}
}
PTDEBUG && _d('DBH info: ', PTDEBUG && _d('DBH info: ',
$dbh, $dbh,

View File

@@ -133,7 +133,7 @@ sub create_dbs {
sub get_dbh_for { sub get_dbh_for {
my ( $self, $server, $cxn_ops, $user ) = @_; my ( $self, $server, $cxn_ops, $user ) = @_;
_check_server($server); _check_server($server);
$cxn_ops ||= { AutoCommit => 1 }; $cxn_ops ||= { AutoCommit => 1, mysql_enable_utf8 => 1 };
$user ||= 'msandbox'; $user ||= 'msandbox';
PTDEBUG && _d('dbh for', $server, 'on port', $port_for{$server}); PTDEBUG && _d('dbh for', $server, 'on port', $port_for{$server});
my $dp = $self->{DSNParser}; my $dp = $self->{DSNParser};

View File

@@ -44,6 +44,7 @@
package TableChunker; package TableChunker;
use strict; use strict;
use utf8;
use warnings FATAL => 'all'; use warnings FATAL => 'all';
use English qw(-no_match_vars); use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0; use constant PTDEBUG => $ENV{PTDEBUG} || 0;
@@ -591,7 +592,7 @@ sub _chunk_char {
$dbh->do($sql); $dbh->do($sql);
my $col_def = $args{tbl_struct}->{defs}->{$chunk_col}; my $col_def = $args{tbl_struct}->{defs}->{$chunk_col};
$sql = "CREATE TEMPORARY TABLE $tmp_db_tbl ($col_def) " $sql = "CREATE TEMPORARY TABLE $tmp_db_tbl ($col_def) "
. "ENGINE=MEMORY"; . "ENGINE=MEMORY DEFAULT CHARSET = utf8";
PTDEBUG && _d($dbh, $sql); PTDEBUG && _d($dbh, $sql);
$dbh->do($sql); $dbh->do($sql);
@@ -601,7 +602,8 @@ sub _chunk_char {
PTDEBUG && _d($dbh, $sql); PTDEBUG && _d($dbh, $sql);
my $ins_char_sth = $dbh->prepare($sql); # avoid quoting issues my $ins_char_sth = $dbh->prepare($sql); # avoid quoting issues
for my $char_code ( $min_col_ord..$max_col_ord ) { for my $char_code ( $min_col_ord..$max_col_ord ) {
$ins_char_sth->execute($char_code); # Ignore errors on invalid chars for UTF8
eval { $ins_char_sth->execute($char_code) };
} }
# Select from the char-to-number map all characters between the # Select from the char-to-number map all characters between the

View File

@@ -29,7 +29,7 @@ report-host = 127.0.0.1
report-port = PORT report-port = PORT
server-id = PORT server-id = PORT
#local_infile = ON #local_infile = ON
#default_authentication_plugin=mysql_native_password default_authentication_plugin=mysql_native_password
# fkc test # fkc test
binlog_format = STATEMENT binlog_format = STATEMENT

File diff suppressed because one or more lines are too long

View File

@@ -315,6 +315,7 @@ sub test_alter_table {
# still functiona: i.e. that they'll prevent us from delete # still functiona: i.e. that they'll prevent us from delete
# a parent row that's being referenced by a child. # a parent row that's being referenced by a child.
my $sql = "DELETE FROM $table WHERE $pk_col=1 LIMIT 1"; my $sql = "DELETE FROM $table WHERE $pk_col=1 LIMIT 1";
warn ">> SQL: $sql";
eval { eval {
$master_dbh->do($sql); $master_dbh->do($sql);
}; };
@@ -471,6 +472,7 @@ test_alter_table(
], ],
); );
diag(">>>>>>>");
test_alter_table( test_alter_table(
name => "Basic FK drop_swap --execute", name => "Basic FK drop_swap --execute",
table => "pt_osc.country", table => "pt_osc.country",
@@ -487,6 +489,7 @@ test_alter_table(
], ],
); );
diag("2 >>>>>>>");
# Let the tool auto-determine the fk update method. This should choose # Let the tool auto-determine the fk update method. This should choose
# the rebuild_constraints method because the tables are quite small. # the rebuild_constraints method because the tables are quite small.
# This is tested by indicating the rebuild_constraints method, which # This is tested by indicating the rebuild_constraints method, which
@@ -510,6 +513,7 @@ test_alter_table(
], ],
); );
diag("3 >>>>>>>");
# Specify --alter-foreign-keys-method for a table with no child tables. # Specify --alter-foreign-keys-method for a table with no child tables.
test_alter_table( test_alter_table(
name => "Child table", name => "Child table",
@@ -527,6 +531,7 @@ test_alter_table(
], ],
); );
diag("4 >>>>>>>");
# Use drop_swap to alter address, which no other table references, # Use drop_swap to alter address, which no other table references,
# so the tool should re-enable --swap-tables and --drop-old-table. # so the tool should re-enable --swap-tables and --drop-old-table.
test_alter_table( test_alter_table(
@@ -545,6 +550,7 @@ test_alter_table(
], ],
); );
diag("5 >>>>>>>");
# Alter city and verify that its fk to country still exists. # Alter city and verify that its fk to country still exists.
# (https://bugs.launchpad.net/percona-toolkit/+bug/969726) # (https://bugs.launchpad.net/percona-toolkit/+bug/969726)
test_alter_table( test_alter_table(

View File

@@ -32,25 +32,25 @@ CREATE TABLE `address` (
CONSTRAINT `fk_address_city` FOREIGN KEY (`city_id`) REFERENCES `city` (`city_id`) ON UPDATE CASCADE CONSTRAINT `fk_address_city` FOREIGN KEY (`city_id`) REFERENCES `city` (`city_id`) ON UPDATE CASCADE
) ENGINE=InnoDB; ) ENGINE=InnoDB;
INSERT INTO pt_osc.country VALUES INSERT INTO pt_osc.country (`country_id`, `country`) VALUES
(1, 'Canada', null), (1, 'Canada'),
(2, 'USA', null), (2, 'USA'),
(3, 'Mexico', null), (3, 'Mexico'),
(4, 'France', null), (4, 'France'),
(5, 'Spain', null); (5, 'Spain');
INSERT INTO pt_osc.city VALUES INSERT INTO pt_osc.city (`city_id`, `city`, `country_id`) VALUES
(1, 'Montréal', 1, null), (1, 'Montréal', 1),
(2, 'New York', 2, null), (2, 'New York', 2),
(3, 'Durango', 3, null), (3, 'Durango', 3),
(4, 'Paris', 4, null), (4, 'Paris', 4),
(5, 'Madrid', 5, null); (5, 'Madrid', 5);
INSERT INTO pt_osc.address VALUES INSERT INTO pt_osc.address (`address_id`, `address`, `city_id`, `postal_code`) VALUES
(1, 'addy 1', 1, '10000', null), (1, 'addy 1', 1, '10000'),
(2, 'addy 2', 2, '20000', null), (2, 'addy 2', 2, '20000'),
(3, 'addy 3', 3, '30000', null), (3, 'addy 3', 3, '30000'),
(4, 'addy 4', 4, '40000', null), (4, 'addy 4', 4, '40000'),
(5, 'addy 5', 5, '50000', null); (5, 'addy 5', 5, '50000');
SET foreign_key_checks=1; SET foreign_key_checks=1;