Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

usando pyodbc no linux para inserir caracteres unicode ou utf-8 em um campo nvarchar mssql


Lembro-me de ter esse tipo de problema estúpido usando drivers odbc, mesmo que naquela época fosse uma combinação java + oracle.

O principal é que o driver odbc aparentemente codifica a string de consulta ao enviá-la para o banco de dados. Mesmo que o campo seja Unicode, e se você fornecer Unicode, em alguns casos isso não parece importar.

Você precisa garantir que o que é enviado pelo driver tenha a mesma codificação do seu Banco de Dados (não apenas servidor, mas também banco de dados). Caso contrário, é claro que você obtém caracteres estranhos porque o cliente ou o servidor estão misturando as coisas ao codificar/ou decodificar. Você tem alguma idéia do charset (codepoint como MS gosta de dizer) que seu servidor está usando como padrão para decodificar dados?

O agrupamento não tem nada a ver com este problema :)


Consulte essa página MS por exemplo. Para campos Unicode, o agrupamento é usado apenas para definir a ordem de classificação na coluna, não para especificar como os dados são armazenados.

Se você armazena seus dados como Unicode, existe uma maneira única de representá-los, esse é o propósito do Unicode:não há necessidade de definir um charset compatível com todos os idiomas que você usará :)

A questão aqui é "o que acontece quando eu dou dados para o servidor que não Unicode?". Por exemplo:
  • Quando eu envio uma string UTF-8 para o servidor, como ele a entende?
  • Quando envio uma string UTF-16 para o servidor, como ele a entende?
  • Quando envio uma string Latin1 para o servidor, como ele a entende?

Do ponto de vista do servidor, todas essas 3 strings são apenas um fluxo de bytes. O servidor não pode adivinhar a codificação na qual você os codificou. O que significa que você vai ter problemas se o seu cliente odbc acabar enviando bytestrings (uma string codificada) para o servidor em vez de enviar unicode data:se você fizer isso, o servidor usará uma codificação predefinida (essa foi a minha pergunta:qual codificação o servidor usará? Como não é adivinhação, deve ser um valor de parâmetro), e se a string foi codificada usando um codificação diferente, dzing , os dados serão corrompidos.

É exatamente semelhante a fazer em 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')

Apenas tente. É divertido. A string decodificada deveria ser "Ei, meu nome é André", mas é "Ei, meu nome é Andrテゥ". é é substituído pelo japonês テゥ

Daí minha sugestão:você precisa garantir que o pyodbc seja capaz de enviar os dados diretamente como Unicode. Se o pyodbc não fizer isso, você obterá resultados inesperados.

E eu descrevi o problema da maneira Cliente para Servidor. Mas o mesmo tipo de problema pode surgir ao se comunicar de volta do Servidor para o Cliente. Se o cliente não puder entender os dados Unicode, você provavelmente terá problemas.

O FreeTDS lida com Unicode para você.


Na verdade, o FreeTDS cuida das coisas para você e traduz todos os dados para unicode UCS2. (Fonte ).
  • Servidor <--> FreeTDS:dados UCS2
  • FreeTDS <--> pyodbc :strings codificadas, codificadas em UTF-8 (de /etc/freetds/freetds.conf )

Portanto, espero que seu aplicativo funcione corretamente se você passar dados UTF-8 para pyodbc. Na verdade, como este tíquete django-pyodbc estados, django-pyodbc se comunica em UTF-8 com pyodbc, então você deve estar bem.

FreeTDS 0.82


No entanto, cramm0 diz que o FreeTDS 0.82 não é completamente livre de bugs e que existem diferenças significativas entre 0.82 e a versão oficial 0.82 corrigida que pode ser encontrada aqui . Você provavelmente deve tentar usar o FreeTDS corrigido

Editado :removidos os dados antigos, que não tinham nada a ver com o FreeTDS, mas eram relevantes apenas para o driver odbc comercial da Easysoft. Desculpe.