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

utiliser pyodbc sous linux pour insérer des caractères unicode ou utf-8 dans un champ nvarchar mssql

Je me souviens d'avoir eu ce genre de problèmes stupides en utilisant des pilotes odbc, même si cette fois c'était une combinaison java + oracle.

L'essentiel est que le pilote odbc encode apparemment la chaîne de requête lors de son envoi à la base de données. Même si le champ est Unicode, et si vous fournissez Unicode, dans certains cas, cela ne semble pas avoir d'importance.

Vous devez vous assurer que ce qui est envoyé par le pilote a le même encodage que votre base de données (pas seulement le serveur, mais aussi la base de données). Sinon, bien sûr, vous obtenez des caractères géniaux parce que le client ou le serveur mélange les choses lors de l'encodage/ou du décodage. Avez-vous une idée du jeu de caractères (codepoint comme MS aime à le dire) que votre serveur utilise par défaut pour décoder les données ?

Le classement n'a rien à voir avec ce problème :)

Voir cette page MS par exemple. Pour les champs Unicode, le classement est utilisé uniquement pour définir l'ordre de tri dans la colonne, pas pour spécifier comment les données sont stockées.

Si vous stockez vos données en Unicode, il existe une façon Unique de les représenter, c'est le but d'Unicode :pas besoin de définir un jeu de caractères compatible avec toutes les langues que vous allez utiliser :)

La question ici est "que se passe-t-il lorsque je donne des données au serveur qui ne sont pas Unicode ?". Par exemple :

  • Lorsque j'envoie une chaîne UTF-8 au serveur, comment la comprend-il ?
  • Lorsque j'envoie une chaîne UTF-16 au serveur, comment la comprend-il ?
  • Lorsque j'envoie une chaîne Latin1 au serveur, comment la comprend-il ?

Du point de vue du serveur, toutes ces 3 chaînes ne sont qu'un flux d'octets. Le serveur ne peut pas deviner l'encodage dans lequel vous les avez encodés. Ce qui signifie que vous allez avoir des problèmes si votre client odbc finit par envoyer des bytestrings (une chaîne encodée) au serveur au lieu d'envoyer unicode data :si vous le faites, le serveur utilisera un encodage prédéfini (c'était ma question :quel encodage le serveur utilisera-t-il ? Comme il ne s'agit pas de deviner, il doit s'agir d'une valeur de paramètre), et si la chaîne avait été encodée à l'aide d'un encodage différent, dzing , les données seront corrompues.

C'est exactement la même chose qu'en Python :

uni = u'Hey my name is André'
in_utf8 = uni.encode('utf-8')
# send the utf-8 data to server
# send(in_utf8)

# on server side
# server receives it. But server is Japanese.
# So the server treats the data with the National charset, shift-jis:
some_string = in_utf8 # some_string = receive()    
decoded = some_string.decode('sjis')

Essayez-le. C'est marrant. La chaîne décodée est censée être "Hey, je m'appelle André", mais c'est "Hey, je m'appelle Andrテゥ". é est remplacé par le japonais テゥ

D'où ma suggestion :vous devez vous assurer que pyodbc est capable d'envoyer directement les données au format Unicode. Si pyodbc ne parvient pas à le faire, vous obtiendrez des résultats inattendus.

Et j'ai décrit le problème de la manière client vers serveur. Mais le même genre de problèmes peut survenir lors de la communication entre le serveur et le client. Si le client ne peut pas comprendre les données Unicode, vous aurez probablement des problèmes.

FreeTDS gère Unicode pour vous.

En fait, FreeTDS s'occupe des choses pour vous et traduit toutes les données en unicode UCS2. (Source ).

  • Serveur <--> FreeTDS :données UCS2
  • FreeTDS <--> pyodbc :chaînes encodées, encodées en UTF-8 (depuis /etc/freetds/freetds.conf )

Je m'attendrais donc à ce que votre application fonctionne correctement si vous transmettez des données UTF-8 à pyodbc. En fait, comme ce ticket django-pyodbc états, django-pyodbc communique en UTF-8 avec pyodbc, donc ça devrait aller.

FreeTDS 0.82

Cependant, cramm0 indique que FreeTDS 0.82 n'est pas complètement exempt de bogues, et qu'il existe des différences significatives entre la version 0.82 et la version officielle corrigée 0.82 qui peuvent être trouvées ici . Vous devriez probablement essayer d'utiliser le patch FreeTDS

Modifié :suppression des anciennes données, qui n'avaient rien à voir avec FreeTDS mais ne concernaient que le pilote odbc commercial d'Easysoft. Désolé.