Bài tập lớn thứ nhất: Việt hóa phương pháp so sánh xâu trong MySQL 5.x ở mức collate
Quy trình thay đổi mã nguồn của một phiên bản MySQL (tính từ lúc download về đến lúc biên dịch xong) để có được một DBMS hỗ trợ Tiếng Việt đơn âm tiết theo chuẩn TCVN 6909:2001
1. Giới thiệu
MySql là một hệ quản trị cơ sở dữ liệu mã nguồn mở được sử dụng nhiều nhất. Nó có nhiều tính năng mà các DBMS khác không có (chẳng hạn như multiple, native, custom storage engines) [1].
Phiên bản release hiện tại (cho đến ngày 16 tháng 1 năm 2008) là 5.0. MySql 5.x là một cách tân [2] nhảy vọt so với các phiên bản trước vì nó đã có gần như đầy đủ các tính năng chuẩn của một RDBMS ( như Stored procedures, Trigger, Cursors, XA distributed transaction processing…). Tuy nhiên nó vẫn còn thiếu nhiều tính năng hữu dụng, trong đó có việc MySql chưa hỗ trợ i18n đầy đủ. Như trong reference manual của phiên bản 5.1
[3] có viết:
Currently, the utf8_unicode_ci collation has only partial support for the Unicode Collation Algorithm. Some characters are not supported yet. Also, combining marks are not fully supported. This affects primarily Vietnamese, Yoruba, and some smaller languages such as Navajo.
Trong bài tập này, mục tiêu của tôi là tùy biến một phiên bản MySql 5.x để nó hỗ trợ Tiếng Việt đơn âm tiết theo chuẩn TCVN 6909:2001 ở mức collate với bốn collate mới như sau (sau đây tôi sẽ gọi tắt những mục tiêu này là “bài toán Vietnamese collation”):
- utf8_vnpred_ci (mã dựng sẵn k0 phân biệt hoa thường)
- utf8_vnpred_cs (mã dựng sẵn phân biệt hoa thường)
- utf8_vncomp_ci (mã tổ hợp k0 phân biệt hoa thường)
- utf8_vncomp_cs (mã tổ hợp phân biệt hoa thường)
Một character set là một tập các ký hiệu (symbol) và các mã (encoding). Một Collation là một tập các quy tắc để so sánh các ký tự trong một character set. Trong một phát biểu SQL, khi cần nói rõ việc so sánh là theo collation nào thì từ COLLATE sẽ được sử dụng, chẳng hạn với các mệnh đề ORDER BY, AS, GROUP BY, WHERE, DISTINCT…
MySql 5.1 hỗ trợ hơn 30 character set và hơn 70 collation, trong đó có 2 unicode character set là ucs2 và utf8. MySql 5.0 và 5.1 cài đặt collation theo thuật toán Unicode Collation Algorithm (UCA)[4]. Về lý thuyết, ta có thể giải “bài toán Vietnamese collation” bằng 3 cách:
Cách 1: Cài đặt lại collation trong MySql cũng theo UCA (tất nhiên là vì UCA đã là chuẩn, nên ta không nên cài đặt theo cách khác), nhưng là cài đặt theo một implementation khác của UCA, chẳng hạn theo ICU Collation Service API [5]. Phương pháp này thực ra cũng khả thi, tuy nhiên khối lượng công việc khá nhiều, và nhất là ta không nên làm khác với MySQL Community mà chỉ nên phát triển những gì đã được MySQL Community lựa chọn.
Cách 2 và 3: Theo Alexander Barkov và Peter Gulutzan [6], có 2 cách để thêm một collation là sửa mã nguồn hoặc sửa file LDML (Locale Data Markup Language – ngôn ngữ đánh dấu dữ liệu địa phương [7]). Tuy nhiên. thực ra thì về bản chất, cả 2 cách ấy chỉ là một: Chúng chỉ thay đổi thứ tự của các ký tự tiếng Việt theo phương pháp tailoring [8]. 2 cách này thực ra là một, nhưng lại mới chỉ là một cách chưa trọn vẹn, lý do tôi xin trình bày trong phần tiếp theo.
Bản chất của vấn đề Vietnamese collation trong MySql là do MySql chưa cài đặt đầy đủ UCA [13]. Cụ thể hơn là bản cài đặt hiện tại của MySql mới chỉ hỗ trợ phép so sánh bằng (quan hệ tương đương) và so sánh nhỏ hơn (quan hệ thứ tự) theo primary level [9]. Vì vậy nếu làm theo cách 2 và 3 ở trên, kết quả nhận được là chưa chính xác (điều này tôi cũng đã thử nghiệm). Vậy giải pháp trọn vẹn sẽ là cài đặt thêm cho MySql để hỗ trợ đầy đủ UCA. Nhưng việc cài đặt này sẽ liên quan đến rất nhiều file mã nguồn ở tầng sâu của MySql (chứ không đơn giản như phương pháp sửa mã nguồn đưa ra bởi Alexander Barkov và Peter Gulutzan trong [6] – chỉ là sửa ở tầng trên, tức là chỉ sửa một vài dòng define và thêm một xâu ký tự định nghĩa tailoring cho collation mới). Vì thế, trong khuôn khổ của bài tập này, tôi sẽ không tìm hiểu và làm được đến mức như vậy. Vậy giải pháp tôi đưa ra là gì? Tôi sẽ định nghĩa nhiều collation trong file LDML, ở đó khi cần phân biệt thứ tự giữa 2 character, tôi sẽ định nghĩa chúng khác nhau theo primary level (mặc dù nếu theo UCA thì chúng chỉ khác nhau ở các level sau) (thực ra ý tưởng của giải pháp này được đưa ra bởi Quan Nguyen trong [10], nhưng cách cụ thể mà Quan Nguyen đưa ra lại chưa đúng).
Tôi đã thử nghiệm và thấy nếu ta tùy biến được MySql 5.1 để hỗ trợ Vietnamese collation cho utf8 thì ta cũng có thể làm được cho ucs2 bằng cách hoàn toàn tương tự (ta chỉ việc copy đoạn mã LDML định nghĩa cho utf8 collation sang phần định nghĩa cho ucs2 collation).
Trong bài toán Vietnamese collation đặt ra ở trên, có 2 mục tiêu hỗ trợ collation cho mã utf8 tổ hợp và 2 mục tiêu cho utf8 dựng sẵn. Nhưng sau khi tìm hiểu về UCA, tôi nhận thấy thực ra ta không cần phân biệt việc các xâu ký tự là ở dạng mã unicode tổ hợp hay dựng sẵn, nghĩa là bài toán chỉ còn 2 mục tiêu. Lý do tôi xin trình bày sau đây.
Trước hết cần phân biệt tổ hợp và dựng sẵn khác nhau như thế nào? Để thể hiện một ký tự, chẳng hạn Ầ (ký tự A, có dấu mũ và dấu huyền) có thể sử dụng một mã (1EA6)trong unicode character code table (khi đó ta nói nó ở dạng mã dựng sẵn, hoặc sử dụng một dãy mã: mã chữ A (0041), mã dấu huyền (0300) và mã dấu mũ (0302), hoặc dãy mã: A, mũ, huyền. Khi sử dụng dãy mã như vậy để thể hiện một ký tự thì ta nói nó ở dạng mã tổ hợp.
Hai là, theo UCA/ Main_Algorithm [11], UCA gồm 4 bước, trong đó ở bước thứ nhất, các ký tự được chuyển về dạng chuẩn D [12]. Ở dạng chuẩn này, các xâu ký tự (có thể chứa cả các ký tự dựng sẵn, hoặc tổ hợp ở các cách khác nhau – như ‘A, mũ, huyền’ hoặc ‘A, huyền, mũ’ ) đều được phân tích thành một dạng duy nhất. Sau đó mỗi xâu cần so sánh được sử dụng làm đầu vào để sinh ra một mảng các collation elements. Mảng ấy lại được dùng để tính ra một soft key, và việc so sánh các xâu là dựa vào các soft key này. Như vậy, rõ ràng một ký tự ở dạng dựng sẵn hay tổ hợp thì cũng tương đương nhau về mặt collate sau bước thứ nhất của UCA. Đây là lý do tôi nói bài toán Vietnamese collation chỉ còn 2 mục tiêu.
Sau đây tôi xin trình bày về quá trình thực hiện tùy biến MySql để giải quyết bài toán Vietnamese collation:
2.Giải quyết bài toán
2.1.Cho Windows:
*Download file mysql-5.0.51.tar.gz
*Trên Windowns XP, cài , VS2005, bison, (có chọn install package perl để test).
*Giải nén mysql-5.0.51.tar.gz vào C:\workdir
*Sửa bug31217
*Sửa các file config/ac-macros/character_sets.m4, mysys/charset-def.c, strings/ctype-uca.c như trong các file đính kèm. Tôi định nghĩa thêm 4 collation là ucs2_vietnamese_ci, ucs2_vietnamese_cs, utf8_vietnamese_ci, utf8_vietnamese_cs.
*Sinh mã nguồn cho VS2005:

*Mở mysql.sln bằng VS2005, build solution với configuration là release.
*Test (optional): vào cygwin để chạy test suite:

*Build MySQL distribution: vào cygwin:

*Giải nén file kết quả mysql.zip vào C:\
2.2.Cho Linux
*Trong CentOS5.1, arch i386, cài make, autoconf , automake, libtool, m4, gcc-c++ phiên bản mới nhất. Giải nén mysql-5.0.51.tar.gz vào /usr/local/
*Sửa các file config/ac-macros/character_sets.m4, mysys/charset-def.c, strings/ctype-uca.c như trong phần 2.b (cho Windows).
*Chạy các lệnh sau (dưới user root của linux) để lấy mã nguồn và build, initialize:
*Sửa file /etc/my.cnf, thay đoạn “basedir=/var/lib/mysql” thành “basedỉ=usr/local/mysql”
3.Kết luận
Hiện tại, unicode collation của MySql vẫn chưa hỗ trợ được cho tiếng Việt. Nguyên nhân là vì chưa có collation nào của MySql cài đặt đầy đủ UCA. Bài viết này có sử dụng một phương pháp tuy chưa phải là hoàn chỉnh nhưng tạm thời vẫn có thể áp dụng cho các ứng dụng cơ sở dữ liệu thực tế ở Việt Nam (có dùng MySql)
Để test, tôi có dùng 1 script sql như trong file collation.sql đính kèm.
Tài liệu tham khảo:
[1] http://en.wikipedia.org/wiki/Mysql#Distinguishing_features
[2] http://dev.mysql.com/doc/refman/5.0/en/mysql-nutshell.html
[3] http://dev.mysql.com/doc/refman/5.1/en/charset-charsets.html
[4] http://www.unicode.org/reports/tr10/
[5] http://www.icu-project.org/userguide/Collate_API.html
[6] http://bugs.mysql.com/file.php?id=6814
[8] http://www.unicode.org/reports/tr10/#Tailoring
[9] http://www.unicode.org/reports/tr10/#Data_Table_Format
[10] http://bugs.mysql.com/bug.php?id=4745
[11] http://www.unicode.org/reports/tr10/#Main_Algorithm
[12] http://www.unicode.org/reports/tr15/
[13] http://forge.mysql.com/worklog/task.php?id=896
[bug31217] http://bugs.mysql.com/bug.php?id=31217
http://thanhbv.googlepages.com/vietnam-colate-mysql-5.0.51.rar