python - Verwenden von pyodbc unter Linux zum Einfügen von Unicode- oder UTF-8-Zeichen in ein Nvarchar-Mssql-Feld




sql-server (3)

Ich benutze Ubuntu 9.04

Ich habe folgende Paketversionen installiert:

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

Ich habe /etc/unixodbc.ini wie /etc/unixodbc.ini konfiguriert:

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

Ich habe /etc/freetds/freetds.conf so konfiguriert:

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

Ich habe pjodbc revision 31e2fae4adbf1b2af1726e5668a3414cf46b454f von http://github.com/mkleehammer/pyodbc gepackt und installiert es mit " python setup.py install "

Ich habe einen Windows-Rechner mit Microsoft SQL Server 2000 in meinem lokalen Netzwerk installiert und höre auf der lokalen IP-Adresse 10.32.42.69. Ich habe eine leere Datenbank mit dem Namen "Common" erstellt. Ich habe den Benutzer "sa" mit Passwort "geheim" mit vollen Rechten.

Ich verwende den folgenden Python-Code, um die Verbindung einzurichten:

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

Alles funktioniert bis zu diesem Punkt. Ich habe SQL Server Enterprise Manager auf dem Server verwendet und die neue Tabelle ist da. Jetzt möchte ich einige Daten in die Tabelle einfügen.

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

Das scheitert !! Hier ist der Fehler, den ich bekomme:

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

Da mein Client für die Verwendung von UTF-8 konfiguriert ist, dachte ich, ich könnte das lösen, indem ich Daten in UTF-8 kodiere. Das funktioniert, aber dann bekomme ich komische Daten zurück:

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]

Das gibt keinen Fehler, aber die zurückgegebenen Daten sind nicht die gleichen Daten gesendet! Ich bekomme:

<type 'unicode'> somé string

Das heißt, Pyodbc akzeptiert kein Unicode-Objekt direkt, aber es gibt Unicode-Objekte an mich zurück! Und die Codierung wird durcheinandergebracht!

Jetzt für die Frage:

Ich möchte, dass Code Unicode-Daten in ein NVARCHAR- und / oder NTEXT-Feld einfügt. Wenn ich zurück ansuche, möchte ich die gleichen Daten, die ich zurück eingefügt habe.

Dies kann durch eine andere Konfiguration des Systems oder durch Verwendung einer Wrapper-Funktion geschehen, die die Daten beim Einfügen oder Abrufen korrekt in / aus Unicode konvertieren kann

Das verlangt nicht viel, oder?


Ich benutze UCS-2 zur Interaktion mit SQL Server, nicht UTF-8.

Korrektur: Ich habe den Eintrag .freetds.conf geändert, so dass der Client UTF-8 verwendet

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

Bind-Werte funktionieren jetzt gut für UTF-8-codierte Strings. Der Treiber konvertiert transparent zwischen dem UCS-2, das für die Speicherung auf der Datenserver-Seite verwendet wird, und den UTF-8-codierten Zeichenfolgen, die dem Client gegeben / entnommen werden.

Dies ist mit pyodbc 2.0 auf Solaris 10 mit Python 2.5 und FreeTDS freetds-0.82.1.dev.20081111 und 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    


Hier ist die Ausgabe aus der Testtabelle (ich hatte manuell einige Testdaten über Management Studio eingegeben)

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 ?', )

Ich konnte einige Unicode-Codepunkte direkt aus Management Studio in den Dialog "Edit Top 200 rows" eingeben und die Hexadezimalziffern für den Unicode-Codepunkt eingeben und dann Alt-X drücken


Ich hatte das gleiche Problem beim Versuch, Unicode-Parameter zu binden: '[HY004] [FreeTDS] [SQL Server] Ungültiger Datentyp (0) (SQLBindParameter)'

Ich habe es gelöst, indem ich freetds auf Version 0.91 aktualisiert habe.

Ich benutze pyodbc 2.1.11. Ich musste this Patch anwenden, damit er mit Unicode funktioniert, sonst bekam ich gelegentlich Speicherfehler.






pyodbc