Per scrivere codice per eseguire il controllo di coerenza dei dati archiviati in SQL Server e PostgreSQL, ho intenzione di calcolare l'MD5 sui dati della tabella per entrambi i database e verificare se sono pari. Questo funziona bene fino a quando i dati è il testo normale (ANSI), come di seguito:Errore di corrispondenza MD5 tra server SQL e PostgreSQL
sql-server> SELECT master.dbo.fn_varbintohexstr(HashBytes('MD5', 'a'));
0x0cc175b9c0f1b6a831c399e269772661
postgres=# select MD5('a');
0cc175b9c0f1b6a831c399e269772661
Ora, se provo ad usare alcuni caratteri Hangul (coreano), MD5 match fallisce:
sql-server> SELECT master.dbo.fn_varbintohexstr(HashBytes('MD5', '무'));
0x7827b52f65d9f7777d37071cbbbf7f2d
postgres=# select MD5('무');
cb3e9be1a3a28b355eabae1fa1e291b3
Come Per mia comprensione, il motivo della mancata corrispondenza è che i caratteri unicode sono memorizzati come codifica UCS-2 (codifica a 16 bit fissi) nella codifica SQL server e UTF-8 in PostgreSQL. E poiché MD5 lavora sui bit dei caratteri, la sequenza dei bit dei caratteri sarebbe diversa sia in SQL server che in PostgreSQL.
come ho avuto a che fare per lo più con Hangul carattere-set, la soluzione che ho usato in PostgreSQL è quello di convertire la codifica da UTF-8 a UHC (Universal Hangul Character-set) prima di calcolare hash, come di seguito:
postgres=# select MD5(CONVERT('무'::bytea,'UTF8','UHC'));
7827b52f65d9f7777d37071cbbbf7f2d
Come si può vedere, il valore di hash sopra riportato è uguale a quello per il server SQL.
Tutto va bene finché ho a che fare con i caratteri di Hangul. Ma alcune tabelle contengono mix di Hangul e caratteri cinesi, e la conversione non riesce in quel caso:
postgres=# select MD5(CONVERT('무么'::bytea,'UTF8','UHC'));
ERROR: character 0xe4b988 of encoding "UTF8" has no equivalent in "UHC"
postgres=#
L'errore ha un senso in quanto non esistono equivalenti di caratteri cinesi in UHC carattere-set.
Come posso farlo funzionare? Fondamentalmente, ho bisogno di trovare il modo di convertire UCS-2 in UTF-8 in SQL server, o di convertire UTF-8 in UCS-2 in PostgreSQL prima di calcolare MD5. Voglio eseguire tutte queste operazioni all'interno del motore di database e non caricare i dati in un'applicazione esterna per calcolare MD5, poiché alcune tabelle hanno un enorme set di dati.
versione del server SQL 2005 PostgreSQL versione 9.1
Non sono sicuro, che effettivamente utilizzate UCS-2 (o UTF-16) nel lato server SQL. '무' in utf-8 (hex) è 'EB AC B4', in utf-16be (e ucs-2be) è' BB 34' e in UHC è 'B9 AB'. Solo l'ultimo ti dà l'hash, hai menzionato (e ti aspetti) nei tuoi esempi. – pozs
@pozs, questa è un'osservazione interessante. Mi sembra in sql-server: N '무' assicurerà –
@pozs, Questa è un'osservazione interessante. Sembra che in sql-server 'select N '무'' garantirà la codifica ucs-2 usando il tipo nvarchar. 'selezionare '무'' il valore predefinito è varchar e la sequenza di bit del carattere è determinata dalle regole di confronto del database. Nel mio caso, le regole di confronto del database sql-server sono _Korean_Wansung_CI_AS_. Sembra che la sequenza dei bit dei caratteri per questo confronto sia simile a UHC. Ma poi, nel caso in cui i caratteri cinesi siano gestiti correttamente da questo confronto, perché non è gestito dalla codifica UHC in PostgreSQL? O quale codifica dovrei usare in Postgres per gestire anche i caratteri cinesi? –