sql >> Databáze >  >> RDS >> Mysql

Je BLOB převeden pomocí aktuální/výchozí znakové sady v MySQL?

Krátká odpověď:

Jednoduše smažte nebo okomentujte řádek níže a bude to vždy fungovat, bez ohledu na to, které kódování databáze se skutečně používá (utf8 , latin1 atd.):

$pdo->exec('SET CHARACTER SET utf8');

Dlouhá odpověď:

Toto není chyba PDO, to je chyba MySQL.

Když je skutečné kódování databáze latin1 , ale používáte:

SET CHARACTER SET utf8

(nebo naopak:aktuální je utf8 , ale používáte latin1 - důležité je, že je jiný ), pak, pokud mohu říci, MySQL se pokusí provést konverzi znakové sady pro veškerý provoz mezi klientem a serverem (dokonce i pro BLOB !).

Pokud NEPOUŽÍVÁTE SET CHARACTER SET Z toho, co vidím u skriptů (PHP/PDO nebo Perl/DBI), je znaková sada připojení standardně nastavena jako znaková sada databáze a v takovém případě neprobíhá žádná implicitní konverze.

Je zřejmé, že tato automatická konverze je to, co zabíjí objekty BLOB, které nechtějí, aby došlo k žádné konverzi.

Testoval jsem to na PHP/PDO i Perl/DBI a problém je snadno reprodukovatelný:oba selžou při použití databáze s latin1 kódování a použití SET CHARACTER SET utf8 (nebo naopak).

Pokud chcete být plně UTF8 kompatibilní, měli byste změnit kódování vaší databáze pomocí:

ALTER DATABASE mydb CHARSET utf8;

S tímto bude vše používat UTF8 , a objekty BLOB budou také fungovat dobře.

Minimální soubor, který způsobuje tento problém s poškozením, je blob.bin s jedním bajtem 0xFF . V Linuxu můžete tento testovací soubor vytvořit pomocí printf příkaz:

printf "0xFF" > blob.bin

Nyní otestujte skripty, které reprodukují problém:

Testovací kód PHP:

<?php
$dbh = new PDO("mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->exec("SET CHARACTER SET utf8");

$blob1 = file_get_contents("blob.bin");
$sth = $dbh->prepare(
    "INSERT INTO pdo_blob (the_blob) VALUES(:the_blob)"
);
$sth->bindParam(":the_blob", $blob1, PDO::PARAM_LOB);
$sth->execute();

$sth = $dbh->prepare(
    "SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
$sth->execute();

$blob2 = null;
$sth->bindColumn(1, $blob2, PDO::PARAM_LOB);
$sth->fetch();

if ($blob1 == $blob2) {
    echo "Equal\n";
} else {
    echo "Not equal\n";
    $arr1 = str_split($blob1);
    $arr2 = str_split($blob2);
    $i=0;
    for ($i=0; $i<count($arr1); $i++) {
        if ($arr1[$i] != $arr2[$i]) {
            echo "First diff: " . dechex(ord($arr1[$i])) . " != "
                                . dechex(ord($arr2[$i])) . "\n";
            break;
        }
    }
}
?>

Testovací kód Perlu:

#!/usr/bin/perl -w

use strict;
use DBI qw(:sql_types);

my $dbh = DBI->connect("dbi:mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->do("SET CHARACTER SET utf8");
open FILE, "blob.bin";
binmode FILE;
read(FILE, my $blob1, 100000000);
close FILE;
my $sth = $dbh->prepare(
    "INSERT INTO pdo_blob (the_blob) VALUES(?)"
);
$sth->bind_param(1, $blob1, SQL_BLOB);
$sth->execute();
my ($blob2) = $dbh->selectrow_array(
    "SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
print ($blob1 eq $blob2 ? "Equal" : "Not equal") , "\n";


  1. MySql – Je primární klíč ve výchozím nastavení jedinečný?

  2. WEEKDAY() vs DAYOFWEEK() v MariaDB:Jaký je rozdíl?

  3. Přirozené připojení na SQL Server

  4. Příklad hromadného shromažďování Oracle pomocí objektu typu typ řádku kurzoru