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) कनेक्शन वर्णसेट के लिए जो मैं देखता हूं उससे कथन डिफ़ॉल्ट रूप से डेटाबेस वर्णसेट के रूप में सेट होता है, और उस स्थिति में कोई अंतर्निहित रूपांतरण नहीं होता है।

जाहिर है, यह स्वचालित रूपांतरण बीएलओबी को मारता है, जो नहीं चाहते कि कोई रूपांतरण हो।

मैंने PHP/PDO और Perl/DBI दोनों पर इसका परीक्षण किया है, और समस्या आसानी से प्रतिलिपि प्रस्तुत करने योग्य है:latin1 के साथ डेटाबेस का उपयोग करने पर दोनों विफल हो जाएंगे एन्कोडिंग और SET CHARACTER SET utf8 . का उपयोग करना (या इसके विपरीत)।

अगर आप पूरी तरह से UTF8 बनना चाहते हैं संगत, आपको निम्न का उपयोग करके अपने डेटाबेस के एन्कोडिंग को बदलना चाहिए:

ALTER DATABASE mydb CHARSET utf8;

इसके साथ, सब कुछ UTF8 का उपयोग कर रहा होगा , और बीएलओबी भी ठीक काम करेंगे।

इस भ्रष्टाचार समस्या का कारण बनने वाली न्यूनतम फ़ाइल है 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;
        }
    }
}
?>

पर्ल टेस्ट कोड:

#!/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. SQL क्वेरी कम से कम कुछ में से एक

  2. mysqldump:लिखने पर 32 त्रुटि मिली

  3. MYSQL लेफ्ट जॉइन ग्रुप बाय के साथ

  4. MYSQLi त्रुटि:उपयोगकर्ता के पास पहले से ही 'max_user_connections' से अधिक सक्रिय कनेक्शन हैं

  5. MySQL - संग्रहित प्रक्रिया में अपवाद कैसे फेंकें?