Domanda

Sto usando Ubuntu 9.04

Ho installato le versioni dei pacchetti seguenti:

unixodbc and unixodbc-dev: 2.2.11-16build3
tdsodbc: 0.82-4
libsybdb5: 0.82-4
freetds-common and freetds-dev: 0.82-4

Ho configurato /etc/unixodbc.ini in questo modo:

[FreeTDS]
Description             = TDS driver (Sybase/MS SQL)
Driver          = /usr/lib/odbc/libtdsodbc.so
Setup           = /usr/lib/odbc/libtdsS.so
CPTimeout               = 
CPReuse         = 
UsageCount              = 2

Ho configurato /etc/freetds/freetds.conf in questo modo:

[global]
    tds version = 8.0
    client charset = UTF-8

Ho afferrato pyodbc 31e2fae4adbf1b2af1726e5668a3414cf46b454f revisione da http://github.com/mkleehammer/pyodbc e installato tramite "python setup.py install"

Ho una macchina Windows con di Microsoft SQL Server 2000 installata sulla mia rete locale, e in ascolto sul 10.32.42.69 indirizzo IP locale. Ho un database vuoto creato con il nome "Comune". Ho l'utente "sa" con password "segreta" con privilegi completi.

Sto usando il seguente codice Python per impostare la connessione:

import pyodbc
odbcstring = "SERVER=10.32.42.69;UID=sa;PWD=secret;DATABASE=Common;DRIVER=FreeTDS"
con = pyodbc.connect(s)
cur = con.cursor()
cur.execute('''
CREATE TABLE testing (
    id INTEGER NOT NULL IDENTITY(1,1), 
    name NVARCHAR(200) NULL, 
    PRIMARY KEY (id)
)
    ''')
con.commit()

Tutto LAVORI fino a questo punto. Ho usato di SQLServer Enterprise Manager sul server e la nuova tabella è lì. Ora voglio inserire alcuni dati sul tavolo.

cur = con.cursor()
cur.execute('INSERT INTO testing (name) VALUES (?)', (u'something',))

che non riesce !! Ecco l'errore che ottengo:

pyodbc.Error: ('HY004', '[HY004] [FreeTDS][SQL Server]Invalid data type 
(0) (SQLBindParameter)'

Dal momento che il mio cliente è configurato per utilizzare UTF-8 ho pensato che avrei potuto risolvere con codifica dei dati in UTF-8. Che funziona, ma poi torno strana dati:

cur = con.cursor()
cur.execute('DELETE FROM testing')
cur.execute('INSERT INTO testing (name) VALUES (?)', (u'somé string'.encode('utf-8'),))
con.commit()
# fetching data back
cur = con.cursor()
cur.execute('SELECT name FROM testing')
data = cur.fetchone()
print type(data[0]), data[0]

Che dà nessun errore, ma i dati restituiti non è la stessa di dati inviati! Ottengo:

<type 'unicode'> somé string

Cioè, pyodbc non accetterà direttamente un oggetto unicode, ma restituisce oggetti unicode torna da me! E la codifica viene mescolata!

Ora per la domanda:

Voglio il codice per inserire i dati Unicode in un NVARCHAR e / o il campo NTEXT. Quando mi interrogo indietro, voglio gli stessi dati ho inserito di nuovo.

Questo può essere configurando il sistema in modo diverso, oppure utilizzando una funzione involucro in grado di convertire i dati correttamente da / unicode durante l'inserimento o il recupero

Non è chiedere molto, vero?

È stato utile?

Soluzione

posso ricordare avere questo tipo di problemi stupidi utilizzando driver ODBC, anche se allora si trattava di una combinazione di Java + oracolo.

La cosa principale è che a quanto pare driver ODBC codifica la stringa di query quando si invia al DB. Anche se il campo è Unicode, e se si fornisce Unicode, in alcuni casi, non sembra avere importanza.

È necessario assicurarsi che ciò che viene inviato dal conducente ha la stessa codifica come database (non solo server, ma anche database). In caso contrario, ovviamente si ottiene caratteri funky perché il client o il server è mescolare le cose quando la codifica / decodifica o. Avete qualche idea del charset (codepoint come MS amano dire) che il server utilizza come default per la decodifica dei dati?

regole di confronto non ha nulla a che fare con questo problema:)

la pagina MS per esempio. Per i campi Unicode, la fascicolazione viene utilizzato solo per definire l'ordinamento nella colonna, non per specificare come i dati sono memorizzati.

Se si memorizzano i dati come Unicode, c'è un modo unico per rappresentarlo, che è lo scopo di Unicode: non c'è bisogno di definire un set di caratteri che è compatibile con tutte le lingue che si intende utilizzare :)

La domanda qui è "cosa succede quando do i dati al server che è non Unicode?". Ad esempio:

  • Quando invio una stringa UTF-8 al server, come si capisce?
  • Quando invio una stringa UTF-16 al server, come si capisce?
  • Quando mando una stringa Latin1 al server, come si capisce?

Dal punto di vista del server, tutti questi 3 stringhe sono solo un flusso di byte. Il server non può indovinare la codifica in cui sono stati codificati. Il che significa che si avere problemi se il client ODBC finisce per l'invio di stringhe di byte (una stringa codificata) al server invece di inviare unicode Dati: in tal caso, il server utilizzerà una codifica predefinito (che era la mia domanda: cosa che codifica per il server utilizzerà Dal momento che non è indovinare, deve essere un valore di parametro?), e se la stringa fosse stato codificato utilizzando una codifica diversa , Dzing , i dati potranno ottenere danneggiato.

E 'esattamente simile come fare in 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')

Provare per credere. È divertente. La stringa decodificata dovrebbe essere "Hey il mio nome è André", ma è "Hey il mio nome è Andr テ ゥ". é viene sostituito da テ ゥ giapponese

Quindi il mio suggerimento: è necessario assicurarsi che pyodbc è in grado di inviare direttamente i dati come Unicode. Se pyodbc non riesce a fare questo, si ottengono risultati imprevisti.

E ho descritto il problema nel client di modo Server. Ma lo stesso tipo di problemi possono sorgere durante la comunicazione di ritorno dal server al client. Se il Cliente non riesce a capire i dati Unicode, è probabile ottenere nei guai.

FreeTDS maniglie Unicode per voi.

In realtà, FreeTDS prende cura delle cose per voi e traduce tutti i dati per UCS2 unicode. ( Source).

  • server <-> FreeTDS: dati UCS2
  • FreeTDS <-> pyodbc: stringhe codificate, codificati in UTF-8 (da /etc/freetds/freetds.conf)

Quindi mi aspetto la vostra applicazione di funzionare correttamente se si passa dati UTF-8 a pyodbc. Infatti, come afferma questo biglietto django-pyodbc , django-pyodbc comunica in UTF-8 con pyodbc, così si dovrebbe andare bene.

FreeTDS 0,82

Tuttavia, cramm0 dice che FreeTDS 0.82 non è del tutto priva di bug, e che non ci sono differenze significative tra 0,82 e il funzionario patchato 0.82 versione che possono essere trovati qui . Probabilmente si dovrebbe provare a utilizzare i FreeTDS rattoppate


A cura : rimossi i vecchi dati, che non avevano nulla a che fare con FreeTDS ma era rilevante solo per Easysoft driver ODBC commerciale. Siamo spiacenti.

Altri suggerimenti

Io uso UCS-2 per interagire con SQL Server, non UTF-8.

Correzione: ho cambiato la voce .freetds.conf in modo che il client utilizza UTF-8

    tds version = 8.0
    client charset = UTF-8
    text size = 32768

Ora, i valori legano funzionano bene per le stringhe UTF-8 codificato. Il driver converte in modo trasparente tra i UCS-2 utilizzato per la memorizzazione sul lato server dati e le stringhe UTF-8 codificati dati a / prelevate dal client.

Questo è con pyodbc 2,0 su Solaris 10 in esecuzione Python 2.5 e FreeTDS FreeTDS-0.82.1.dev.20081111 e SQL Server 2008

import pyodbc
test_string = u"""Comment ça va ? Très bien ?"""

print type(test_string),repr(test_string)
utf8 = 'utf8:' + test_string.encode('UTF-8')
print type(utf8), repr(utf8)

c = pyodbc.connect('DSN=SA_SQL_SERVER_TEST;UID=XXX;PWD=XXX')

cur = c.cursor()
# This does not work as test_string is not UTF-encoded
try: 
    cur.execute('INSERT unicode_test(t) VALUES(?)', test_string)
    c.commit()
except pyodbc.Error,e:
    print e


# This one does:
try:
    cur.execute('INSERT unicode_test(t) VALUES(?)', utf8)
    c.commit()
except pyodbc.Error,e:
    print e    


Ecco l'uscita dalla tabella di prova (avevo messo manualmente in un mucchio di dati di test tramite Management Studio)

In [41]: for i in cur.execute('SELECT t FROM unicode_test'):
   ....:     print i
   ....:
   ....:
('this is not a banana', )
('\xc3\x85kergatan 24', )
('\xc3\x85kergatan 24', )
('\xe6\xb0\xb4 this is code-point 63CF', )
('Mich\xc3\xa9l', )
('Comment a va ? Trs bien ?', )
('utf8:Comment \xc3\xa7a va ? Tr\xc3\xa8s bien ?', )

Sono stato in grado di mettere in qualche in punti di codice Unicode direttamente nella tabella da Management Studio dalla finestra di dialogo 'Modifica Top 200 righe' e inserendo le cifre esadecimali per il punto di codice Unicode e quindi premendo Alt-X

Ho avuto lo stesso problema quando si cerca di legare il parametro unicode: '[HY004] [FreeTDS] [SQL Server] tipo non valido di dati (0) (SQLBindParameter)'

ho risolto con l'aggiornamento alla versione 0.91 FreeTDS.

Io uso pyodbc 2.1.11. Ho dovuto applicare questo patch per farlo funzionare con Unicode, altrimenti mi è stato sempre gli errori di corruzione della memoria di tanto in tanto.

Sei sicuro che sia INSERT che non è causando problemi di lettura? C'è un bug aperto su pyodbc Problema di recupero NTEXT e NVARCHAR dati .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top