Showing posts with label Mysql UTF-8. Show all posts
Showing posts with label Mysql UTF-8. Show all posts

Wednesday, 14 November 2018

Fixing double-encoded UTF-8 data in MySQL

Double-encoded UTF-8 texts (not to mention triple-, quadruple- and so on) are a fairly common problem when dealing with MySQL. This may be due to the fact that the default character set of the connection to the server is Latin-1, but that is not relevant once the data is already corrupt.
Here is how to fix it, in two simple steps, using the mysqldump and mysql commands:
mysqldump -h DB_HOST -u DB_USER -p DB_PASSWORD --opt --quote-names \
    --skip-set-charset --default-character-set=latin1 DB_NAME > DB_NAME-dump.sql

mysql -h DB_HOST -u DB_USER -p DB_PASSWORD \
    --default-character-set=utf8 DB_NAME < DB_NAME-dump.sql
Of course, you should first replace DB_HOSTDB_USERDB_PASSWORD and DB_NAME with values, corresponding to your database setup.

Tuesday, 6 November 2018

Mysql: UTF-8: General? Bin? Unicode?

I'm trying to figure out what collation I should be using for various types of data. 100% of the content I will be storing is user-submitted.
My understanding is that I should be using UTF-8 General CI (Case-Insensitive) instead of UTF-8 Binary. However, I can't find a clear a distinction between UTF-8 General CI and UTF-8 Unicode CI.
  1. Should I be storing user-submitted content in UTF-8 General or UTF-8 Unicode CI columns?
  2. What type of data would UTF-8 Binary be applicable to?

 Answers


In general, utf8_general_ci is faster than utf8_unicode_ci, but less correct.
Here is the difference:
For any Unicode character set, operations performed using the _general_ci collation are faster than those for the _unicode_ci collation. For example, comparisons for the utf8_general_ci collation are faster, but slightly less correct, than comparisons for utf8_unicode_ci. The reason for this is that utf8_unicode_ci supports mappings such as expansions; that is, when one character compares as equal to combinations of other characters. For example, in German and some other languages “ß” is equal to “ss”. utf8_unicode_ci also supports contractions and ignorable characters. utf8_general_ci is a legacy collation that does not support expansions, contractions, or ignorable characters. It can make only one-to-one comparisons between characters.
For more detailed explanation, please read the following post from MySQL forums: http://forums.mysql.com/read.php?103,187048,188748
As for utf8_bin: Both utf8_general_ci and utf8_unicode_ci perform case-insensitive comparison. In constrast, utf8_bin is case-sensitive (among other differences), because it compares the binary values of the characters.



  • utf8_bin compares the bits blindly. No case folding, no accent stripping.
  • utf8_general_ci compares one byte with one byte. It does case folding and accent stripping, but no 2-character comparisions: ij is not equal ij in this collation.
  • utf8_*_ci is a set of language-specific rules, but otherwise like unicode_ci. Some special cases: ÇČchll
  • utf8_unicode_ci follows an old Unicode standard for comparisons. ij=ij, but ae != æ
  • utf8_unicode_520_ci follows an newer Unicode standard. ae = æ
See collation chart for details on what is equal to what in various utf8 collations.
utf8as defined by MySQL is limited to the 1- to 3-byte utf8 codes. This leaves out Emoji and some of Chinese. So you should really switch to utf8mb4 if you want to go much beyond Europe.
The above points apply to utf8mb4, after suitable spelling change. Going forward, utf8mb4 and utf8mb4_unicode_520_ci are preferred.
  • utf16 and utf32 are variants on utf8; there is virtually no use for them.
  • ucs2 is closer to "Unicode" than "utf8"; there is virtually no use for it.

Friday, 2 November 2018

Change MySQL default character set to UTF-8 in my.cnf?

Currently we are using the following commands in PHP to set the character set to UTF-8 in our application.
Since this is a bit of overhead, we'd like to set this as the default setting in MySQL. Can we do this in /etc/my.cnf or in another location?
SET NAMES 'utf8'
SET CHARACTER SET utf8
I've looked for a default charset in /etc/my.cnf, but there's nothing there about charsets.
At this point, I did the following to set the MySQL charset and collation variables to UTF-8:
skip-character-set-client-handshake
character_set_client=utf8
character_set_server=utf8
Is that a correct way to handle this?

 Answers


To set the default to UTF-8, you want to add the following to my.cnf
[client]
default-character-set=utf8

[mysql]
default-character-set=utf8


[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
If you want to change the character set for an existing DB, let me know... your question didn't specify it directly so I am not sure if that's what you want to do.



On MySQL 5.5 I have in my.cnf
[mysqld] 
init_connect='SET collation_connection = utf8_unicode_ci' 
init_connect='SET NAMES utf8' 
character-set-server=utf8 
collation-server=utf8_unicode_ci 
skip-character-set-client-handshake
Result is
mysql> show variables like "%character%";show variables like "%collation%";

+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_unicode_ci |
| collation_database   | utf8_unicode_ci |
| collation_server     | utf8_unicode_ci |
+----------------------+-----------------+
3 rows in set (0.00 sec)



I also have found out that after setting default-character-set = utf8 under [mysqld] title, MySQL 5.5.x would not start under Ubuntu 12.04 (Precise Pangolin).



MySQL v5.5.3 and greater:
Just add three lines only in the [mysqld] section:
[mysqld]
character-set-server = utf8
collation-server = utf8_unicode_ci
skip-character-set-client-handshake
Note: Including skip-character-set-client-handshake here obviates the need to include both init-connect in [mysqld] and default-character-set in the [client] and [mysql] sections.



Under Xubuntu 12.04 I simply added
[mysqld]
character_set_server = utf8
to /etc/mysql/my.cnf
And the result is
mysql> show variables like "%character%";show variables like "%collation%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database   | utf8_general_ci |
| collation_server     | utf8_general_ci |
+----------------------+-----------------+
3 rows in set (0.00 sec)






On Fedora 21
$ vi /etc/my.cnf
Add follow:
[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci 
skip-character-set-client-handshake
Save and exit.
Final remember restart service mysqld with service mysqld restart.



If you're having trouble confirming the client's character-set support using MySQL Workbench, then keep the following note in mind:
Important All connections opened by MySQL Workbench automatically set the client character set to utf8. Manually changing the client character set, such as using SET NAMES ..., may cause MySQL Workbench to not correctly display the characters. For additional information about client character sets, see Connection Character Sets and Collations.
Thus I was unable to override MySQL Workbench's character sets with my.cnf changes. e.g. 'set names utf8mb4'



You can do it the way it does, and if it doesn't work, you need to restart mysql.