Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Czy BLOB jest konwertowany przy użyciu bieżącego/domyślnego zestawu znaków w MySQL?

Krótka odpowiedź:

Po prostu usuń lub skomentuj poniższy wiersz, a zawsze będzie działać, bez względu na to, które kodowanie bazy danych jest naprawdę używane (utf8 , latin1 itd.):

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

Długa odpowiedź:

To nie jest błąd PDO, to błąd MySQL.

Kiedy rzeczywiste kodowanie bazy danych to latin1 , ale używasz:

SET CHARACTER SET utf8

(lub odwrotnie:rzeczywisty to utf8 , ale używasz latin1 - ważne jest to, że jest inne ), wtedy, o ile wiem, MySQL spróbuje wykonać konwersję zestawu znaków dla całego ruchu między klientem a serwerem (nawet dla BLOB !).

Jeśli NIE używasz SET CHARACTER SET oświadczenie, z tego, co widzę dla skryptów (PHP/PDO lub Perl/DBI), domyślnie zestaw znaków połączenia jest ustawiony jako zestaw znaków bazy danych iw takim przypadku nie zachodzi niejawna konwersja.

Oczywiście ta automatyczna konwersja zabija obiekty BLOB, które nie chcą, aby doszło do jakiejkolwiek konwersji.

Przetestowałem to zarówno na PHP/PDO, jak i Perl/DBI, a problem można łatwo odtworzyć:oba nie powiedzie się, jeśli użyjesz bazy danych z latin1 kodowanie i używanie SET CHARACTER SET utf8 (lub odwrotnie).

Jeśli chcesz być w pełni UTF8 kompatybilny, powinieneś zmienić kodowanie bazy danych za pomocą:

ALTER DATABASE mydb CHARSET utf8;

Dzięki temu wszystko będzie używać UTF8 , a obiekty BLOB również będą działać dobrze.

Minimalny plik, który powoduje ten problem z uszkodzeniem, to blob.bin z jednobajtowym 0xFF . W systemie Linux możesz utworzyć ten plik testowy za pomocą printf polecenie:

printf "0xFF" > blob.bin

Teraz przetestuj skrypty, które odtwarzają problem:

Kod testu 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;
        }
    }
}
?>

Kod testu Perla:

#!/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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SELECT INTO OUTFILE nie można zapisać do pliku

  2. Kod błędu:2013. Utracono połączenie z serwerem MySQL podczas zapytania

  3. Jak zresetować hasło roota mysql?

  4. Jak zainstalować moduł Python MySQLdb za pomocą pip?

  5. Wstawianie NOW() do bazy danych z aktywnym rekordem CodeIgniter