sql >> Base de Datos >  >> RDS >> PostgreSQL

No se puede almacenar el signo Euro en la propiedad LOB String con Hibernate/PostgreSQL

Después de investigar mucho en el código fuente de Hibernate y el controlador JDBC de PostgreSQL, logré encontrar la raíz del problema. Al final, se invoca el método write() de BlobOutputStream (proporcionado por el controlador JDBC) para escribir el contenido de Clob en la base de datos. Este método se ve así:

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 toma un 'int' (32 bits/4 bytes) como argumento y lo convierte en un 'byte' (8 bits/1 byte) perdiendo efectivamente 3 bytes de información. Las representaciones de cadenas dentro de Java están codificadas en UTF-16, lo que significa que cada carácter está representado por 16 bits/2 bytes. El símbolo del euro tiene el valor int 8364. Después de la conversión a byte, el valor 172 permanece (en representación de octeto 254).

No estoy seguro de cuál es ahora la mejor resolución para este problema. En mi humilde opinión, el controlador JDBC debería ser responsable de codificar/decodificar los caracteres Java UTF-16 para cualquier codificación que necesite la base de datos. Sin embargo, no veo ninguna posibilidad de ajuste en el código del controlador JDBC para alterar su comportamiento (y no quiero escribir ni mantener mi propio código del controlador JDBC).

Por lo tanto, amplié Hibernate con un ClobType personalizado y logré convertir los caracteres UTF-16 a UTF-8 antes de escribir en la base de datos y viceversa al recuperar el Clob.

Las soluciones son demasiado grandes para simplemente pegarlas en esta respuesta. Si estás interesado, escríbeme y te lo envío.

Saludos, Franck