PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Impossible de stocker le signe euro dans la propriété LOB String avec Hibernate/PostgreSQL

Après de nombreuses recherches dans le code source d'Hibernate et du pilote PostgreSQL JDBC, j'ai réussi à trouver la cause première du problème. Au final, la méthode write() du BlobOutputStream (fournie par le pilote JDBC) est invoquée pour écrire le contenu du Clob dans la base de données. Cette méthode ressemble à ceci :

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());
    }
}

Cette méthode prend un 'int' (32 bits/4 octets) comme argument et le convertit en un 'octet' (8 bits/1 octet) perdant effectivement 3 octets d'informations. Les représentations de chaîne dans Java sont encodées en UTF-16, ce qui signifie que chaque caractère est représenté par 16 bits/2 octets. Le signe euro a la valeur int 8364. Après conversion en octet, la valeur 172 reste (dans la représentation de l'octet 254).

Je ne sais pas quelle est maintenant la meilleure solution à ce problème. À mon humble avis, le pilote JDBC devrait être responsable de l'encodage/décodage des caractères Java UTF-16 selon l'encodage dont la base de données a besoin. Cependant, je ne vois aucune possibilité d'ajustement dans le code du pilote JDBC pour modifier son comportement (et je ne veux pas écrire et maintenir mon propre code de pilote JDBC).

Par conséquent, j'ai étendu Hibernate avec un ClobType personnalisé et j'ai réussi à convertir les caractères UTF-16 en UTF-8 avant d'écrire dans la base de données et vice-versa lors de la récupération du Clob.

Les solutions sont trop grandes pour être simplement collées dans cette réponse. Si vous êtes intéressé, écrivez-moi et je vous l'envoie.

Bravo, Franck