Mysql
 sql >> база данни >  >> RDS >> Mysql

Преобразува ли се BLOB с помощта на текущия/подразбиращ се набор от знаци в MySQL?

Кратък отговор:

Просто изтрийте или коментирайте реда по-долу и той винаги ще работи, без значение кое кодиране на базата данни наистина се използва (utf8 , latin1 и т.н.):

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

Дълъг отговор:

Това не е грешка в PDO, това е грешка в MySQL.

Когато действителното кодиране на базата данни е latin1 , но използвате:

SET CHARACTER SET utf8

(или обратно:действителното е utf8 , но използвате latin1 - важна част е, че еразлично ), тогава, доколкото мога да преценя, MySQL ще се опита да извърши преобразуване на набор от знаци за целия трафик между клиент и сървър (дори за BLOB !).

Ако НЕ използвате SET CHARACTER SET декларация, от това, което виждам за скриптове (PHP/PDO или Perl/DBI), наборът от знаци за връзка по подразбиране е зададен да бъде наборът от знаци на базата данни и в този случай не се извършва неявно преобразуване.

Очевидно това автоматично преобразуване е това, което убива BLOB-овете, които не искат да се случи преобразуване.

Тествах това както на PHP/PDO, така и на Perl/DBI и проблемът е лесно възпроизводим:и двата ще се провалят, ако използвате база данни с latin1 кодиране и използване на SET CHARACTER SET utf8 (или обратно).

Ако искате да сте напълно UTF8 съвместим, трябва да промените кодирането на вашата база данни, като използвате:

ALTER DATABASE mydb CHARSET utf8;

С това всичко ще използва UTF8 и BLOB също ще работят добре.

Минималният файл, който причинява този проблем с повреда, е blob.bin с един байт 0xFF . В Linux можете да създадете този тестов файл с помощта на printf команда:

printf "0xFF" > blob.bin

Сега тествайте скриптове, които възпроизвеждат проблема:

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

Тестов код на Perl:

#!/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. Производителност на MySQL:Преобразуване на MySQL в MariaDB

  2. Задайте максимално време за изпълнение в MYSQL / PHP

  3. Как да нулирате/промените MySql root парола на командния ред в ubuntu linux

  4. CONVERT_TZ – Как да промените часовата зона на MySQL в заявка

  5. вмъкване в съхранена процедура с параметри MYSQL не работи