aws aurora rds (mysql) in a cluster cannot insert emoji - mysql

I am using an aurora rds (mysql) in a cluster and cannot insert emoji's. The column which I am trying to insert into has the collation:
utf8mb4 - utf8mb4_unicode_ci
I have tried inserting using client and also from mysql workbench writing the query but in both cases I just see ???? in the field.
I have updated the table default character set:
utf8mb4
and default collation:
utf8mb4_unicode_ci
But still getting ??? instead of emoji
Edit 1:
I've tried to edit the parameter group of the cluster and set all character set values to utf8mb4 and all collation values to utf8mb4_unicode_ci but still not working.

Your cluster parameter group should have the following options set:
character_set_client: utf8mb4
character_set_connection: utf8mb4
character_set_database: utf8mb4
character_set_server: utf8mb4
collation_connection: utf8mb4_unicode_ci
collation_server: utf8mb4_unicode_ci
Rebooting your instances after updating this might be required. When you connect to the cluster you want to set the correct collation for your connection, like this:
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
If you run SHOW VARIABLES LIKE "%collation%" after this you should see three variables that all have the correct collation (utf8mb4_unicode_ci).
You also need to convert your tables and columns to the correct charset and collation, this has been answered before on the DBA Stack Exchange: How to easily convert utf8 tables to utf8mb4 in MySQL 5.5

Changing the default character set of a table doesn't alter any of the existing columns. You can run SHOW CREATE TABLE MyTable and see the difference.
For example, we can create a table with an old-fashioned charset:
mysql> create table MyTable (string1 varchar(100) ) default character set = latin1;
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Next, we change the table's default, but we see that does not change the column. The existing column automatically gets an option showing us what it actually uses for a charset, since it's now different from the table default:
mysql> alter table MyTable default charset = utf8mb4;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
The default is used for columns added to the table subsequently:
mysql> alter table MyTable add column string2 varchar(100);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) CHARACTER SET latin1 DEFAULT NULL,
`string2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
To convert the existing column, use CONVERT TO CHARACTER SET. This rewrites the table, converting the existing data of each column if needed:
mysql> alter table MyTable convert to character set utf8mb4;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) DEFAULT NULL,
`string2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Now both columns say nothing about their respective charsets, because they match the table's default.

I wrote a detailed blog post (a few years back) explaining how to support emoji and Aurora MySQL in Ruby on Rails here:
https://josephecombs.com/2018/05/06/how-to-support-emojis-with-rails-elasticbeanstalk-and-amazon-aurora
I know external links are frowned upon here, but this could help others in a similar situation. The guide is too long to paste as an answer.

Related

MYSQL won't drop the default value for a timestamp

I am trying to drop the default value of a timestamp column.
My DDL looks something like this:
CREATE TABLE bills
(
...
created_at TIMESTAMP DEFAULT '1971-01-06 00:00:00',
updated_at TIMESTAMP DEFAULT '1970-01-01 00:00:01',
);
When I try any of the following:
ALTER TABLE bills ALTER COLUMN created_at DROP DEFAULT;
ALTER TABLE bills ALTER COLUMN created_at SET DEFAULT NULL;
ALTER TABLE bills MODIFY COLUMN created_at TIMESTAMP NULL;
ALTER TABLE bills MODIFY COLUMN created_at TIMESTAMP NULL DEFAULT NULL;
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL;
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL DEFAULT NULL;
The MYSQL shell says it has executed correctly.
However, when I check the DDL again, it is clear nothing has changed.
On the other hand, I can alter the default value to a specified value like so:
ALTER TABLE bills ALTER COLUMN created_at SET DEFAULT '1972-02-02 00:00:00';
And it updates correctly.
Note that the columns are nullable (as you can see by the DDL) and I have put null data values in the "create_at" column.
The MYSQL version I am using is as v5.7.12
Here is more details about the version I am using:
$ mysql --version
mysql Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using EditLine wrapper
Use the CHANGE COLUMN or MODIFY COLUMN versions of the ALTER TABLE syntax. These require you to specify all the attributes of the column that you want to carry over from the old to the new definition (CHANGE also requires the name so that you can rename at the same time).
e.g.
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL;
ALTER TABLE bills MODIFY COLUMN updated_at TIMESTAMP NULL;
Here's a sqlfiddle so you can see it working http://sqlfiddle.com/#!9/303110/3
Update
Have you checked the value of the EXPLICIT_DEFAULTS_FOR_TIMESTAMP variable?
Following on from my comments below, I've now succeeded in getting both of your statements to work in mysql 5.7 by setting the variable EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 1;
I'm afraid I can't properly explain the purpose of this variable except to say that it appears to be intended to disable some 'nonstandard' behaviours in TIMESTAMP fields. It's documented here.
I'll quote one bit of this
By default, explicit_defaults_for_timestamp is disabled, which enables
the nonstandard behaviors.
Personally, I think this is the wrong way round, you ought to set the variable to allow the use of 'nonstandard' behaviours if you wish to go down that path. I'd call that a bug.
In your case, and assuming this actually works on your system, disabling the 'nonstandard' behaviour would allow the 'standard' syntax for changing a column default to work.
This is the output on my system
paul#zoltan:~$ mysql --version
mysql Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using EditLine wrapper
mysql> SET ##SESSION.EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> drop table bills;
Query OK, 0 rows affected (0.17 sec)
mysql> create table bills (
-> id INT AUTO_INCREMENT PRIMARY KEY,
-> created_at TIMESTAMP DEFAULT '1971-01-06 00:00:00',
-> updated_at TIMESTAMP DEFAULT '1970-01-01 01:00:01'
-> );
Query OK, 0 rows affected (0.42 sec)
mysql> alter table bills alter column created_at drop default;
Query OK, 0 rows affected (0.10 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column created_at set default null;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column updated_at drop default;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column updated_at set default null;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table bills\G
*************************** 1. row ***************************
Table: bills
Create Table: CREATE TABLE `bills` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

DROP TRIGGER statement after RENAME TABLE statement in MySQL results in "Error Code: 1146. Table 'testschema.TestRenamed' doesn't exist"

I am using MySQL 5.7.10 and noticed that if a table that has an existing trigger is renamed via a RENAME TABLE statement, attempting to drop the existing trigger will result in a "Table doesn't exist" error. See the sample script below to demonstrate the error.
CREATE SCHEMA testschema DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE testschema;
CREATE TABLE Test(
id int not null primary key auto_increment,
name varchar(255)
);
delimiter //
CREATE TRIGGER TEST_TRIGGER
BEFORE INSERT ON Test
FOR EACH ROW
BEGIN
SET NEW.name = CONCAT(NEW.name, '_X');
END//
delimiter ;
RENAME TABLE Test TO TestRenamed;
DROP TRIGGER TEST_TRIGGER;
Executing the script above will give the following response:
"Error Code: 1146. Table 'testschema.TestRenamed' doesn't exist"
However executing the following query returns a row showing the table was successfully renamed.
SELECT * from information_schema.TABLES WHERE TABLE_SCHEMA = 'testschema' AND TABLE_NAME = 'TestRenamed';
What are the options, for dropping a trigger after renaming a table?
EDIT: I have filed a bug report with MySQL but would also like to hear if there is a potential workaround for dropping these triggers in the meantime.
EDIT 2: Just for more information about the environment, this is on OSX El Capitan 10.11.2 and the disk is case insensitive OSX Extended File System.
EDIT 3: This appears to be an OSX specific issue. I have verified the script works as desired on MySQL in Linux Mint.
I can't reproduce the problem.
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.10 |
+-----------+
1 row in set (0,00 sec)
mysql> CREATE SCHEMA `testschema`
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0,00 sec)
mysql> USE `testschema`;
Database changed
mysql> CREATE TABLE `Test` (
-> `id` int not null primary key auto_increment,
-> `name` varchar(255)
-> );
Query OK, 0 rows affected (0,01 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `TEST_TRIGGER` BEFORE INSERT ON `Test`
-> FOR EACH ROW
-> BEGIN
-> SET NEW.`name` = CONCAT(NEW.`name`, '_X');
-> END//
Query OK, 0 rows affected (0,00 sec)
mysql> DELIMITER ;
mysql> RENAME TABLE `Test` TO `TestRenamed`;
Query OK, 0 rows affected (0,00 sec)
mysql> SHOW TRIGGERS\G
*************************** 1. row ***************************
Trigger: TEST_TRIGGER
Event: INSERT
Table: TestRenamed
Statement: BEGIN
SET NEW.`name` = CONCAT(NEW.`name`, '_X');
END
Timing: BEFORE
Created: **********
sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
Definer: **********
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0,00 sec)
mysql> DROP TRIGGER `TEST_TRIGGER`;
Query OK, 0 rows affected (0,00 sec)
Please, show the result of executing the statement: SHOW TRIGGERS\G, before executing DROP TRIGGER;.

change character encoding of mysql table

When I change the character set of a table from utf8 to latin1, the columns still keep the old setting.
For e.g. in the example below, name column is still utf8 even if the table is converted to latin1
mysql> create table mytest (id int, name varchar(255)) engine=myisam default charset=utf8;
Query OK, 0 rows affected (0.02 sec)
mysql> alter table mytest charset=latin1;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table mytest\G
*************************** 1. row ***************************
Table: mytest
Create Table: CREATE TABLE `mytest` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
This must be to preseve the data integrity. But is there any way to change everything to latin1. I am not much worried about data. I am ok if there are a few junk characters due to conversion.

Issue with Collation in Mysql

I have a table as
mysql> show create table tbl_name\G
************* 1. row *************
Table: tbl_name
Create Table: CREATE TABLE `tbl_name` (
`name` char(15) CHARACTER SET latin1 DEFAULT NULL,
`id` int(5) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin7 COLLATE=latin7_estonian_cs
1 row in set (0.00 sec)
The DATA In Table is as
mysql> select * from tbl_name;
name id
manaf 1
manaf 2
MANAF 3
MAnaf 4
4 rows in set (0.00 sec)
Now i want the Case Sensitivity in all the records
mysql> select distinct(name) from tbl_name;
It should return the 3 rows in result but it is returing just 1.why..??
As I have set the table collation as latin7_estonian_cs
try this
SELECT DISTINCT BINARY value FROM tableName
Reference

Importance of Default charset

I have a 4 GB table and the default charset was set to utf8 though I am saving only latin1 characters.
I changed it to latin1 using alter table statement on a test machine.
The index file log_details.MYI was reduced by 5% while there was no difference noted in the data file, log_details.MYD
I have a few questions:
1) Should I alter the table on production? is it worth it?
2) Will it improve the select speed?
3) I guess I can have longer indexes once I change the default charset to latin1. Any
other advantage?
I have also noted that after changing the default charset using alter table statement, the varchar columns types were changed automatically.
Item_ID varchar(32) character set utf8 How do I avoid this?
mysql> create table char_test( id int, Item_ID varchar(32) ) default charset = utf8;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into char_test values (1, 'abc');
Query OK, 1 row affected (0.00 sec)
mysql> show create table char_test\G
*************************** 1. row ***************************
Table: char_test
Create Table: CREATE TABLE `char_test` (
`id` int(11) default NULL,
`Item_ID` varchar(32) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> alter table char_test default charset = latin1;
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> show create table char_test\G
*************************** 1. row ***************************
Table: char_test
Create Table: CREATE TABLE `char_test` (
`id` int(11) default NULL,
`Item_ID` varchar(32) character set utf8 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Performance is probably the last thing you should care about. What character set is you client-side app using? What natural language is the info written on? Those are the questions you must make.
If you stick to Latin1 you won't be able to store Japanese characters but also some common chars like the € symbol. On the other side, using UTF-8 in the database may be useless (or plain wrong) if your application cannot handle multi-byte input.