Skip to content

Instantly share code, notes, and snippets.

@jazzl0ver
Last active December 15, 2017 10:53
Show Gist options
  • Save jazzl0ver/cb66fe520d62782c3d19688da52c335f to your computer and use it in GitHub Desktop.
Save jazzl0ver/cb66fe520d62782c3d19688da52c335f to your computer and use it in GitHub Desktop.
https://lists.mysql.com/commits/80079: mysqlhotcopy did not handle the encoding of schema names in the filesystem, so schemas with most non-alphanumeric characters in their name could not be backed up (http://bugs.mysql.com/44278)
--- mysqlhotcopy.org 2016-05-11 09:31:09.000000000 +0300
+++ mysqlhotcopy 2017-12-13 13:57:51.972468660 +0300
@@ -239,7 +239,7 @@
$to_other_database=0;
if (defined($tgt_name) && $tgt_name =~ m:^\w+$: && @db_desc <= 1)
{
- $tgt_dirname = "$datadir/$tgt_name";
+ $tgt_dirname = "$datadir/" . encode_identifier_as_filename($tgt_name);
$to_other_database=1;
}
elsif (defined($tgt_name) && ($tgt_name =~ m:/: || $tgt_name eq '.')) {
@@ -310,7 +310,7 @@
}
## get list of files to copy
- my $db_dir = "$datadir/$db";
+ my $db_dir = "$datadir/" . encode_identifier_as_filename($db);
opendir(DBDIR, $db_dir )
or die "Cannot open dir '$db_dir': $!";
@@ -372,13 +372,13 @@
if ($to_other_database)
{
foreach my $rdb ( @db_desc ) {
- $rdb->{target} = "$tgt_dirname";
+ $rdb->{target} = "$tgt_dirname/" . encode_identifier_as_filename($rdb->{src});
}
}
elsif ($opt{method} =~ /^scp\b/)
{ # we have to trust scp to hit the target
foreach my $rdb ( @db_desc ) {
- $rdb->{target} = "$tgt_dirname/$rdb->{src}";
+ $rdb->{target} = "$tgt_dirname/" . encode_identifier_as_filename($rdb->{src});
}
}
else
@@ -386,7 +386,7 @@
die "Last argument ($tgt_dirname) is not a directory\n"
if (!(-e $tgt_dirname && -d $tgt_dirname ) );
foreach my $rdb ( @db_desc ) {
- $rdb->{target} = "$tgt_dirname/$rdb->{src}";
+ $rdb->{target} = "$tgt_dirname/" . encode_identifier_as_filename($rdb->{src});
}
}
}
@@ -394,7 +394,7 @@
die "Error: expected \$opt{suffix} to exist" unless ( exists $opt{suffix} );
foreach my $rdb ( @db_desc ) {
- $rdb->{target} = "$datadir/$rdb->{src}$opt{suffix}";
+ $rdb->{target} = "$datadir/" . encode_identifier_as_filename("$rdb->{src}$opt{suffix}");
}
}
@@ -439,7 +439,7 @@
unless -d $tgt_dirpath;
if ($^O !~ m/^(NetWare)$/)
{
- my @f_info= stat "$datadir/$rdb->{src}";
+ my @f_info= stat "$datadir/" . encode_identifier_as_filename($rdb->{src});
chown $f_info[4], $f_info[5], $tgt_dirpath;
}
}
@@ -496,7 +496,7 @@
foreach my $rdb ( @db_desc )
{
- my @files = map { "$datadir/$rdb->{src}/$_" } @{$rdb->{files}};
+ my @files = map { "$datadir/" .encode_identifier_as_filename($rdb->{src}) ."/$_" } @{$rdb->{files}};
next unless @files;
eval { copy_files($opt{method}, \@files, $rdb->{target}); };
@@ -507,7 +507,7 @@
if ($rdb->{index})
{
copy_index($opt{method}, \@files,
- "$datadir/$rdb->{src}", $rdb->{target} );
+ "$datadir/" . encode_identifier_as_filename($rdb->{src}), $rdb->{target} );
}
if ( $opt{checkpoint} ) {
@@ -819,6 +819,20 @@
return "`$db`.`$table`";
}
+#
+# In MySQL 5.1 and later, directory and table names are encoded on disk.
+# We use the server to figure out the encoded names, and just fall back
+# to the unencoded identifier if that fails.
+#
+sub encode_identifier_as_filename {
+ my ($ident)= @_;
+ my ($filename)= $dbh->selectrow_array(
+ "SELECT BINARY(CAST(? AS CHAR CHARACTER SET FILENAME))",
+ { RaiseError => 0 },
+ $ident);
+ return $filename ? $filename : $ident;
+}
+
__END__
=head1 DESCRIPTION
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment