Data

1 set, 2015

Adicionando nova collation no MySQL

Publicidade

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!