PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Não é possível armazenar o Euro-sign na propriedade LOB String com Hibernate/PostgreSQL


Depois de muito pesquisar no código-fonte do Hibernate e no driver PostgreSQL JDBC, consegui encontrar a causa raiz do problema. No final, o método write() do BlobOutputStream (fornecido pelo driver JDBC) é invocado para gravar o conteúdo do Clob no banco de dados. Este método se parece com isso:
public void write(int b) throws java.io.IOException
{
    checkClosed();
    try
    {
        if (bpos >= bsize)
        {
            lo.write(buf);
            bpos = 0;
        }
        buf[bpos++] = (byte)b;
    }
    catch (SQLException se)
    {
        throw new IOException(se.toString());
    }
}

Este método recebe um 'int' (32 bits/4 bytes) como argumento e o converte em um 'byte' (8 bits/1 byte) efetivamente perdendo 3 bytes de informação. As representações de string em Java são codificadas em UTF-16, o que significa que cada caractere é representado por 16 bits/2 bytes. O sinal Euro tem o valor int 8364. Após a conversão para byte, o valor 172 permanece (na representação de octeto 254).

Não tenho certeza qual é agora a melhor resolução para esse problema. IMHO o driver JDBC deve ser responsável por codificar/decodificar os caracteres Java UTF-16 para qualquer codificação que o banco de dados precise. No entanto, não vejo nenhuma possibilidade de ajuste no código do driver JDBC para alterar seu comportamento (e não quero escrever e manter meu próprio código do driver JDBC).

Portanto, estendi o Hibernate com um ClobType personalizado e consegui converter os caracteres UTF-16 para UTF-8 antes de gravar no banco de dados e vice-versa ao recuperar o Clob.

As soluções são muito grandes para simplesmente colar nesta resposta. Se tiver interesse, me mande uma mensagem que eu te envio.

Saúde, Franck