2017-10-13 69 views
0

私はDebian 8マシンでPerl 5.20.2とMySQL 5.5.57を使用しています。私は最近、MySQLのutf8テーブルが3バイトのcharacetersに限定されていることを発見しました。結果として、私は絵文字を保存できません。 それで、私は問題を解決するはずのutfmb4テーブルを試しました。私はmysqlクライアント内からutf8mb4するUTF8からテーブルを変更:mytableは中のデータを保存するPerl MySQL utf8mb4の問題/可能なバグ

ALTER DATABASE `mydb` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; 
ALTER TABLE `mydb`.`mytable` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 
ALTER TABLE `mydb`.`mytable` CHANGE `object` `object` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 

は、少なくとも私はphpMyAdminの中に予想される絵文字を見ることができ、動作しているようです。しかし、テーブルから読むと、私は3つの印字不可能な文字を持つ4文字の結果を受け取ります。次のプログラムは、二度同じ絵文字を印刷するようになっている:期待

#!/usr/bin/perl 

use 5.10.1; 
use warnings; 
use strict; 
use DBI; 

binmode(STDOUT, ':utf8'); 

my $object = "\x{1F600}"; 
my $hd_db = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password'); 
$hd_db->do('SET NAMES utf8mb4'); 

# cleanup 
my $delete = $hd_db->prepare("DELETE FROM mytable"); 
$delete->execute; 

my $insert = $hd_db->prepare("INSERT INTO mytable (object) VALUES ('" . $object . "')"); 
$insert->execute; 
my $select = $hd_db->prepare("SELECT * FROM mytable"); 
$select->execute; 
my $row = $select->fetchrow_hashref; 

say $object; 
say $row->{'object'}; 

出力:



実際の出力:


� 

は私にはバグのように思えます。どのようにそれを回避するための任意の提案?

EDITは:mysqlクライアント内からデータを選択することも予想される絵文字に

mysql> SET SESSION CHARACTER_SET_CLIENT = utf8mb4; 
mysql> SET SESSION CHARACTER_SET_RESULTS = utf8mb4; 
mysql> SELECT * FROM mytable; 
+--------+ 
| object | 
+--------+ 
|  | 
+--------+ 
+1

実際にはプレースホルダを使用する必要があります。 – simbabque

+0

あなたはprepare文を参照していますか?私は通常そうしていますが、それはここではあまり意味がないと思われます – Marcus

+0

私はそれを指摘する時間がかかりました;-) – simbabque

答えて

2

あなたは通信のためのUTF-8を使用するようにMySQLを告げていますが、データをデコード(またはそれを自分で行う)ためにDBD :: mysqlのを指示する必要があります。

あなたは "ユニコード" ではなく、 "UTF8" である

my $dbh = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password') 
    or die($DBI::errstr); 

$dbh->do('SET NAMES utf8mb4') 
    or die($dbh->errstr); 

$dbh->{mysql_enable_utf8mb4} = 1; 
+1

私はこの答えを 'DBI'バージョン> = 4.041_01に行く方法として受け入れました。 Debian 8は3.0.17で出荷されます。このバージョンのデコードは、mysql_enable_utf8 => 1を選択すると動作します。[this post](http://blogs.perl.org/users/mike_b/2016/12/dbdmysql-all-your-utf-8-bugs)を参照してください。 -are-belong-to-us.html) – Marcus

0

を示してこの問題を回避するには、MySQLはバイトとしてすべてを扱うようにすると、アプリケーションでエンコードを行うことです。

use Encode qw(encode decode); 

my $object = "\x{1F600}"; 
my $hd_db = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password'); 
$hd_db->do('SET NAMES latin1'); 

... 

my $insert = $hd_db->prepare("INSERT INTO mytable (object) VALUES ('" . 
    encode("UTF-8",$object) . "')"); # or equiv statement with placeholders 
$insert->execute; 

... 

my $select = $hd_db->prepare("SELECT * FROM mytable"); 
$select->execute; 
my $row = $select->fetchrow_hashref; 
say $object; 
say decode("UTF-8",$row->{'object'}); 
+0

提案していただきありがとうございますが、残念ながらアプリケーションで1k db以上のクエリを再訪する必要があります。そして悪いことに、彼らはテストする必要があります.. – Marcus

0

"\x{1F600}";と同等です

my $dbh = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password', { 
    mysql_enable_utf8mb4 => 1, 
}) 
    or die($DBI::errstr); 

たい。それらは関連していますが、ではなく、と同じエンコードです。

あなたはUTF-8(mysql以外の世界がそれを呼び出すため)とutf8mb4(MySQLが呼び出すので)が必要です。

は、F09F9880(utf8mb4で)です。 CHARACTER SET latin1( "Mojobake")に変換する場合は😀

SELECT HEX(object) ...を実行して、それらの4桁の16進数を取得するかどうかを確認してください。次に、INSERTまたはSELECTに注目するかどうかがわかります。

あなたは「実際の出力」と言いますが、これはどこですか?ウェブページ? UTF-8のために設定されていますか?または、他の何か?コマンドラインウィンドウの場合は、UTF-8に設定されていることを確認してください。ウィンドウでは、それはchcp 65001によって行われます。

あなただけの2に設定する必要が3のだ

mysql> SET SESSION CHARACTER_SET_CLIENT = utf8mb4; 
mysql> SET SESSION CHARACTER_SET_RESULTS = utf8mb4; 

を述べました。

SET NAMES utf8mb4; 
+0

これはコンソール出力で、UbuntuとW10/Putty 0.7の両方ですぐに使用できました。私は 'chcp'ingを試していませんが、Win7/Putty 0.7は動作しません。 – Marcus

+0

' my.cnf'を比較してください。異なるデフォルトを見つけることができます。どのバージョンのMySQL? –

関連する問題