Trabalhar com banco de dados, às vezes, não é uma tarefa muito fácil. Eu sou do tipo de DBA que prefere manter as coisas o mais simples possível, porém, tem vezes em que não é possível. Alguns dias atrás, me deparei com um problema o qual nenhuma das collations presentes no MySQL resolveria. Para evitar uma grande re-escrita do código, descobri uma opção até então desconhecida, adicionar minha própria collation no MySQL.
Esta opção está descrita na documentação. Neste artigo, vou mostrar como fazer o MySQL identificar vogais com acento agudo como uma letra diferente.
Primeiro, precisamos descobrir onde está o nosso diretório com os charset’s:
mysql [localhost] {msandbox} ((none)) > SHOW VARIABLES LIKE 'character_sets_dir'; +--------------------+---------------------------------------+ | Variable_name | Value | +--------------------+---------------------------------------+ | character_sets_dir | /mysql/sources/5.6.26/share/charsets/ | +--------------------+---------------------------------------+ 1 row in set (0.00 sec)
Neste caso, trabalharei com a pasta /mysql/sources/5.6.26/share/charsets/. Ela provavelmente será diferente no seu ambiente. Nós vamos achar um arquivo chamado Index.xml dentro desta pasta, e vamos trabalhar nele.
Neste arquivo, vamos estar utilizando a sintaxe chamada de locate data markup language (LDML), mais especificamente os elementos reset / p / t. Você pode achar mais informação sobre a implementação de LDML no MySQL neste link.
Vamos editar o arquivo e adicionar nossa collation:
<charset name="utf8"> <family>Unicode</family> <description>UTF-8 Unicode</description> <alias>utf-8</alias> . . . <collation name="utf8_test_ci" id="1122" version="5.2.0"> <rules> <reset>A</reset> <p>\u00c1</p> <t>\u00e1</t> <reset>E</reset> <p>\u00c9</p> <t>\u00e9</t> <reset>I</reset> <p>\u00cd</p> <t>\u00ed</t> <reset>O</reset> <p>\u00d3</p> <t>\u00f3</t> <reset>U</reset> <p>\u00da</p> <t>\u00fa</t> </rules> </collation> </charset>
Explicando um pouco o que cada linha representa:
<reset>A</reset> <p>\u00c1</p> <t>\u00e1</t>
- reset – está resetando a ordem e regras da letra A (e também da letra a)
- p – está dizendo que \u00c1 (Á) será tratada como uma letra diferente
- t – está dizendo que \u00e1 (á) será tratada como a versão minuscula de \u00c1 (Á)
A mesma lista de regras se aplica às demais letras que temos no arquivo (E / I / O / U). Agora, tudo o que precisamos é re-iniciar o serviço do MySQL.
Vamos agora testar e verificar como isto funciona na prática. Vou criar duas tabelas, uma com a collation padrão do utf8 e outra tabela com a nossa nova collation:
mysql [localhost] {msandbox} (test) > CREATE TABLE `utf8` ( `name` varchar(50), PRIMARY KEY (`name`) ) ENGINE=InnoDB DEFAULT CHARSET utf8; Query OK, 0 rows affected (0.04 sec) mysql [localhost] {msandbox} (test) > INSERT INTO utf8 VALUES ('A'); Query OK, 1 row affected (0.01 sec) mysql [localhost] {msandbox} (test) > INSERT INTO utf8 VALUES ('Á'); ERROR 1062 (23000): Duplicate entry 'Á' for key 'PRIMARY' mysql [localhost] {msandbox} (test) > INSERT INTO utf8 VALUES ('a'); ERROR 1062 (23000): Duplicate entry 'a' for key 'PRIMARY' mysql [localhost] {msandbox} (test) > INSERT INTO utf8 VALUES ('á'); ERROR 1062 (23000): Duplicate entry 'á' for key 'PRIMARY' mysql [localhost] {msandbox} (test) > SELECT * FROM utf8; +------+ | name | +------+ | A | +------+ 1 row in set (0.00 sec)
O MySQL só aceitou uma variação da letra A, todas as próximas falharam por serem consideradas iguais. Vamos ver como funciona na nossa collation:
mysql [localhost] {msandbox} (test) > CREATE TABLE `utf8_test` ( `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_test_ci , PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET utf8; Query OK, 0 rows affected (0.03 sec) mysql [localhost] {msandbox} (test) > INSERT INTO utf8_test VALUES ('A'); Query OK, 1 row affected (0.01 sec) mysql [localhost] {msandbox} (test) > INSERT INTO utf8_test VALUES ('Á'); Query OK, 1 row affected (0.01 sec) mysql [localhost] {msandbox} (test) > INSERT INTO utf8_test VALUES ('a'); ERROR 1062 (23000): Duplicate entry 'a' for key 'PRIMARY' mysql [localhost] {msandbox} (test) > INSERT INTO utf8_test VALUES ('á'); ERROR 1062 (23000): Duplicate entry 'á' for key 'PRIMARY' mysql [localhost] {msandbox} (test) > SELECT * FROM utf8_test; +------+ | name | +------+ | A | | Á | +------+ 2 rows in set (0.00 sec)
Neste caso, o MySQL aceitou 2 variações, A / Á. “a” foi bloqueada pois é idêntica a letra “A” e “á” foi bloqueada pois é idêntica a letra “Á”.
Por hoje é isso.
Espero que tenham gostado!