本文說明一下mysql中不支援歐元字元的原因及解決方法。
1、
問題描述
在mysql中插入的字串中若包含歐元字元(€)
,會發現該字元及以後的字串都變得「不可見」。實際上這裡並非不可見,而是根本沒有進入資料庫中。簡單描述步驟如下:
root@test 05:15:41>create table t(c char(32)) engine=innodb charset=gbk;
query ok, 0 rows affected (0.01 sec)
root@test 05:16:29>insert into t values(concat('a', char(128), 'b'));
query ok, 1 row affected, 1 warning (0.00 sec)
root@test 05:17:04>select * from t;
+------+
| c |
+------+
| a |
+------+
可以看到,我們試圖插入三個字元(a, €, b)
,但在查詢中發現只有乙個字元a.
insert的乙個warning內容為incorrect string value: '\x80b' for column 'c' at row 1
說明在插入0x80(即€) 時出錯,導致後面的字元也一起被丟棄.
2、
原因分析
我們知道,在mysql
將語句中設定的值傳給引擎時,需要先拷貝到乙個臨時結構中。但拷貝字串只會以\0
結束,0x80
對於字串拷貝過程應該是乙個正常的字元。
拷貝函式
於是我們找到做值拷貝的過程,
在sql/sql_string.cc
的well_formed_copy_nchars
中,對應的兩行**如下
res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
nchars, &well_formed_error);
memmove(to, from, res);
可以看到,拷貝內容時,先計算了可拷貝的長度,然後在用memmove. 除錯
發現,在我們上面的試驗中,返回的res=1
,因此memmove
就只拷貝了乙個字元(a).
計算長度
於是問題出在這個to_cs->cset->well_formed_len
中。由於mysql
要支援多種字元編碼,因此定義了my_charset_handler (
在include/m_ctype.h)
中,這個結構體定義了各種編碼下的特定函式介面。對應的實現實體在strings/ctyp-*.c
中。我們的例子中用到的是gbk
,因此看strings/ctype-gbk.c
。上述計算長度的函式,實際上呼叫的是本檔案中的my_well_formed_len_gbk
。
static
size_t my_well_formed_len_gbk(charset_info *cs __attribute__((unused)),
const char *b, const char *e,
size_t pos, int *error)
else if ((b < emb) && isgbkcode((uchar)*b, (uchar)b[1]))
else
} return (size_t) (b - b0);
}
第12行是對於英文本元的處理,第17行是對於中文字元的處理,其他的直接到第22行後判為error
。我們看到,0x80
就到了*error=1,
然後break
。3、
修改和小結
實際上歐元字元也可以作為單位元組處理, 將上面**的第12行改為if ((uchar) b[0] <= 128)
,重新編譯後執行結果如下
mysql> insert into t values(concat('a', char(128), 'b'));
query ok, 1 row affected (0.00 sec)
insert select hex(c) from t;
+--------+
| hex(c) |
+--------+
| 618062 |
+--------+
歐元字元在筆者客戶端內顯示不正常,但從hex(c)
中看到三個字元已經正常儲存在mysql
中。其他字元編碼也有此問題,都修改相應的string/ctype-*.c
中的my_well_formed_len*
即可。
mysql 元字元 菜鳥教程元字元總結
字元描述 將下乙個字元標記為乙個特殊字元 或乙個原義字元 或乙個 向後引用 或乙個八進位制轉義符。例如,n 匹配字元 n n 匹配乙個換行符。序列 匹配 而 則匹配 匹配輸入字串的開始位置。如果設定了 regexp 物件的 multiline 屬性,也匹配 n 或 r 之後的位置。匹配輸入字串的結束...
讓mysql支援中文
我用spring ibatis mysql搭了乙個框架,但是中文顯示亂碼。解決問題的路徑 1 在資料庫連線的url 後加上 useunicode true characterencoding utf8 2 修改mysql的配置檔案my.ini 在 client 後加上default characte...
mysql 元字元 正規表示式 元字元的使用
一 基本簡介 1.定義 即文字的高階匹配模式,提供搜尋,替換等功能。其本質是由一系列字元和特殊符號構成的字串,這個字串即正規表示式。2.原理 通過普通字元和有特定含義的字元,來組成字串,用以描述一定的字串規則,比如 重複,位置等,來表達某類特定的字串,進而匹配。3.目標 熟練掌握正規表示式元字元 能...