The last couple of days I’ve been developing a little app that imports Twitter feeds and saves tweets to a MySQL database; however, I quickly hit an issue where certain tweets would not save. MySQL was returning the error message ‘SQLSTATE[HY000]: General error: 1366 Incorrect string value’. Looking at the specific tweets causing the database to throw the error I noticed that they contained emoticons.
I was using
utf8 encoding in MySQL which I thought (wrongly) could represent all unicode characters.
The unicodes for emoticons are fully supported by the UTF-8 encoding; however, MySQL’s
utf8 does not! To save emoticons to a MySQL database we need to use
The difference between MySQL’s
utf8mb4 is that the former can only store 3 byte characters whereas the latter can store 4 byte ones. Therefore with
utf8 we can only store unicode characters from the Basic Multilingual Plane. Put more simply,
utf8 is suitable for characters from the majority of modern languages and some symbols. Emoticon characters exist in the Supplementary Multilingual Plane for which we need to use
In order to save emoticons and other unicode not supported by MySQL’s
utf8 we need to change the character set and collation properties of our database, tables and columns. As long as our database is currently using
utf8 there should be no risk of data loss as
utf8mb4 is fully backwards compatible with it. However, it is still a good idea to make a backup of the database before running the following commands.
Let’s first set the connection encoding to
utf8mb4 and then change the database’s character set and collation to it:-
SET NAMES utf8mb4; ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
database_name with the name of the database.)
Next we need to convert the relevant tables to utf8mb4/utf8mb4_unicode_ci (you will need to run this for each table):-
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
table_name with the name of the database table.)
Finally we need to update the character set and collation for the column(s):-
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(140) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;
Read that last command carefully as it will need modifying to your specific needs. The important bit to note is the
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. (As with the other commands you need to replace
Bear in mind that changing from
utfmb4 affects the maximum lengths of columns and index keys. The maximum lengths of columns will be unchanged when modifying the tables with the commands discussed here; but in terms of actual characters the amount that can be stored is reduced. This is a consequence of changing from being able to store only 3 bytes up to 4! You may need to update these lengths if this is relevant to you.
It may be a good idea to make sure every table that has been converted is repaired and optimised after making the above changes. You can run the following for each modified table:-
REPAIR TABLE table_name; OPTIMIZE TABLE table_name;
mysqlcheck to repair and optimises everything in one go:-
mysqlcheck -u root -p --auto-repair --optimize --all-databases
Everything should be ready now, but don’t forget to update how your app connects to the database so that it uses the new encoding. For example, in CakePHP 3 the datasource’s encoding needs updating to
'Datasources' => [ 'default' => [ ... 'database' => 'database_name', 'encoding' => 'utf8mb4', ... ] ]
We should now be good to go and start saving tweets containing emoticons (or anything else using them).
I hope that this has been informative and useful to you.